Merge pull request #6021 from grpc/release-0_13

0.13 a tiny upmerge 
diff --git a/.clang_complete b/.clang_complete
new file mode 100644
index 0000000..79d0946
--- /dev/null
+++ b/.clang_complete
@@ -0,0 +1,8 @@
+-Ithird_party/googletest/include
+-Ithird_party/googletest
+-Iinclude
+-Igens
+-I.
+-Ithird_party/boringssl/include
+-Ithird_party/zlib
+-Ithird_party/protobuf/src
diff --git a/.gitmodules b/.gitmodules
index c37d0ab..c85a539 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,7 +13,7 @@
 	url = https://github.com/google/googletest.git
 [submodule "third_party/boringssl"]
 	path = third_party/boringssl
-	url = https://boringssl.googlesource.com/boringssl
+	url = https://github.com/google/boringssl.git
 [submodule "third_party/nanopb"]
 	path = third_party/nanopb
 	url = https://github.com/nanopb/nanopb.git
diff --git a/BUILD b/BUILD
index 0e9f37a..fc4dfe8 100644
--- a/BUILD
+++ b/BUILD
@@ -41,65 +41,82 @@
 
 
 
+
 cc_library(
   name = "gpr",
   srcs = [
-    "src/core/profiling/timers.h",
-    "src/core/support/block_annotate.h",
-    "src/core/support/env.h",
-    "src/core/support/load_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/time_precise.h",
-    "src/core/support/tmpfile.h",
-    "src/core/profiling/basic_timers.c",
-    "src/core/profiling/stap_timers.c",
-    "src/core/support/alloc.c",
-    "src/core/support/avl.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/histogram.c",
-    "src/core/support/host_port.c",
-    "src/core/support/load_file.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/subprocess_windows.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_precise.c",
-    "src/core/support/time_win32.c",
-    "src/core/support/tls_pthread.c",
-    "src/core/support/tmpfile_posix.c",
-    "src/core/support/tmpfile_win32.c",
-    "src/core/support/wrap_memcpy.c",
+    "src/core/lib/profiling/timers.h",
+    "src/core/lib/support/backoff.h",
+    "src/core/lib/support/block_annotate.h",
+    "src/core/lib/support/env.h",
+    "src/core/lib/support/load_file.h",
+    "src/core/lib/support/murmur_hash.h",
+    "src/core/lib/support/stack_lockfree.h",
+    "src/core/lib/support/string.h",
+    "src/core/lib/support/string_win32.h",
+    "src/core/lib/support/thd_internal.h",
+    "src/core/lib/support/time_precise.h",
+    "src/core/lib/support/tmpfile.h",
+    "src/core/lib/profiling/basic_timers.c",
+    "src/core/lib/profiling/stap_timers.c",
+    "src/core/lib/support/alloc.c",
+    "src/core/lib/support/avl.c",
+    "src/core/lib/support/backoff.c",
+    "src/core/lib/support/cmdline.c",
+    "src/core/lib/support/cpu_iphone.c",
+    "src/core/lib/support/cpu_linux.c",
+    "src/core/lib/support/cpu_posix.c",
+    "src/core/lib/support/cpu_windows.c",
+    "src/core/lib/support/env_linux.c",
+    "src/core/lib/support/env_posix.c",
+    "src/core/lib/support/env_win32.c",
+    "src/core/lib/support/histogram.c",
+    "src/core/lib/support/host_port.c",
+    "src/core/lib/support/load_file.c",
+    "src/core/lib/support/log.c",
+    "src/core/lib/support/log_android.c",
+    "src/core/lib/support/log_linux.c",
+    "src/core/lib/support/log_posix.c",
+    "src/core/lib/support/log_win32.c",
+    "src/core/lib/support/murmur_hash.c",
+    "src/core/lib/support/slice.c",
+    "src/core/lib/support/slice_buffer.c",
+    "src/core/lib/support/stack_lockfree.c",
+    "src/core/lib/support/string.c",
+    "src/core/lib/support/string_posix.c",
+    "src/core/lib/support/string_win32.c",
+    "src/core/lib/support/subprocess_posix.c",
+    "src/core/lib/support/subprocess_windows.c",
+    "src/core/lib/support/sync.c",
+    "src/core/lib/support/sync_posix.c",
+    "src/core/lib/support/sync_win32.c",
+    "src/core/lib/support/thd.c",
+    "src/core/lib/support/thd_posix.c",
+    "src/core/lib/support/thd_win32.c",
+    "src/core/lib/support/time.c",
+    "src/core/lib/support/time_posix.c",
+    "src/core/lib/support/time_precise.c",
+    "src/core/lib/support/time_win32.c",
+    "src/core/lib/support/tls_pthread.c",
+    "src/core/lib/support/tmpfile_posix.c",
+    "src/core/lib/support/tmpfile_win32.c",
+    "src/core/lib/support/wrap_memcpy.c",
   ],
   hdrs = [
+    "include/grpc/impl/codegen/alloc.h",
+    "include/grpc/impl/codegen/atm.h",
+    "include/grpc/impl/codegen/atm_gcc_atomic.h",
+    "include/grpc/impl/codegen/atm_gcc_sync.h",
+    "include/grpc/impl/codegen/atm_win32.h",
+    "include/grpc/impl/codegen/log.h",
+    "include/grpc/impl/codegen/port_platform.h",
+    "include/grpc/impl/codegen/slice.h",
+    "include/grpc/impl/codegen/slice_buffer.h",
+    "include/grpc/impl/codegen/sync.h",
+    "include/grpc/impl/codegen/sync_generic.h",
+    "include/grpc/impl/codegen/sync_posix.h",
+    "include/grpc/impl/codegen/sync_win32.h",
+    "include/grpc/impl/codegen/time.h",
     "include/grpc/support/alloc.h",
     "include/grpc/support/atm.h",
     "include/grpc/support/atm_gcc_atomic.h",
@@ -128,15 +145,371 @@
     "include/grpc/support/tls_msvc.h",
     "include/grpc/support/tls_pthread.h",
     "include/grpc/support/useful.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+  ],
+)
+
+
+
+cc_library(
+  name = "grpc",
+  srcs = [
+    "src/core/ext/transport/chttp2/transport/alpn.h",
+    "src/core/ext/transport/chttp2/transport/bin_encoder.h",
+    "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
+    "src/core/ext/transport/chttp2/transport/frame.h",
+    "src/core/ext/transport/chttp2/transport/frame_data.h",
+    "src/core/ext/transport/chttp2/transport/frame_goaway.h",
+    "src/core/ext/transport/chttp2/transport/frame_ping.h",
+    "src/core/ext/transport/chttp2/transport/frame_rst_stream.h",
+    "src/core/ext/transport/chttp2/transport/frame_settings.h",
+    "src/core/ext/transport/chttp2/transport/frame_window_update.h",
+    "src/core/ext/transport/chttp2/transport/hpack_encoder.h",
+    "src/core/ext/transport/chttp2/transport/hpack_parser.h",
+    "src/core/ext/transport/chttp2/transport/hpack_table.h",
+    "src/core/ext/transport/chttp2/transport/http2_errors.h",
+    "src/core/ext/transport/chttp2/transport/huffsyms.h",
+    "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
+    "src/core/ext/transport/chttp2/transport/internal.h",
+    "src/core/ext/transport/chttp2/transport/status_conversion.h",
+    "src/core/ext/transport/chttp2/transport/stream_map.h",
+    "src/core/ext/transport/chttp2/transport/timeout_encoding.h",
+    "src/core/ext/transport/chttp2/transport/varint.h",
+    "src/core/lib/census/aggregation.h",
+    "src/core/lib/census/grpc_filter.h",
+    "src/core/lib/census/grpc_plugin.h",
+    "src/core/lib/census/mlog.h",
+    "src/core/lib/census/rpc_metric_id.h",
+    "src/core/lib/channel/channel_args.h",
+    "src/core/lib/channel/channel_stack.h",
+    "src/core/lib/channel/channel_stack_builder.h",
+    "src/core/lib/channel/client_channel.h",
+    "src/core/lib/channel/compress_filter.h",
+    "src/core/lib/channel/connected_channel.h",
+    "src/core/lib/channel/context.h",
+    "src/core/lib/channel/http_client_filter.h",
+    "src/core/lib/channel/http_server_filter.h",
+    "src/core/lib/channel/subchannel_call_holder.h",
+    "src/core/lib/client_config/client_config.h",
+    "src/core/lib/client_config/connector.h",
+    "src/core/lib/client_config/initial_connect_string.h",
+    "src/core/lib/client_config/lb_policies/load_balancer_api.h",
+    "src/core/lib/client_config/lb_policies/pick_first.h",
+    "src/core/lib/client_config/lb_policies/round_robin.h",
+    "src/core/lib/client_config/lb_policy.h",
+    "src/core/lib/client_config/lb_policy_factory.h",
+    "src/core/lib/client_config/lb_policy_registry.h",
+    "src/core/lib/client_config/resolver.h",
+    "src/core/lib/client_config/resolver_factory.h",
+    "src/core/lib/client_config/resolver_registry.h",
+    "src/core/lib/client_config/resolvers/dns_resolver.h",
+    "src/core/lib/client_config/resolvers/sockaddr_resolver.h",
+    "src/core/lib/client_config/subchannel.h",
+    "src/core/lib/client_config/subchannel_factory.h",
+    "src/core/lib/client_config/subchannel_index.h",
+    "src/core/lib/client_config/uri_parser.h",
+    "src/core/lib/compression/algorithm_metadata.h",
+    "src/core/lib/compression/message_compress.h",
+    "src/core/lib/debug/trace.h",
+    "src/core/lib/http/format_request.h",
+    "src/core/lib/http/httpcli.h",
+    "src/core/lib/http/parser.h",
+    "src/core/lib/iomgr/closure.h",
+    "src/core/lib/iomgr/endpoint.h",
+    "src/core/lib/iomgr/endpoint_pair.h",
+    "src/core/lib/iomgr/exec_ctx.h",
+    "src/core/lib/iomgr/executor.h",
+    "src/core/lib/iomgr/fd_posix.h",
+    "src/core/lib/iomgr/iocp_windows.h",
+    "src/core/lib/iomgr/iomgr.h",
+    "src/core/lib/iomgr/iomgr_internal.h",
+    "src/core/lib/iomgr/iomgr_posix.h",
+    "src/core/lib/iomgr/pollset.h",
+    "src/core/lib/iomgr/pollset_posix.h",
+    "src/core/lib/iomgr/pollset_set.h",
+    "src/core/lib/iomgr/pollset_set_posix.h",
+    "src/core/lib/iomgr/pollset_set_windows.h",
+    "src/core/lib/iomgr/pollset_windows.h",
+    "src/core/lib/iomgr/resolve_address.h",
+    "src/core/lib/iomgr/sockaddr.h",
+    "src/core/lib/iomgr/sockaddr_posix.h",
+    "src/core/lib/iomgr/sockaddr_utils.h",
+    "src/core/lib/iomgr/sockaddr_win32.h",
+    "src/core/lib/iomgr/socket_utils_posix.h",
+    "src/core/lib/iomgr/socket_windows.h",
+    "src/core/lib/iomgr/tcp_client.h",
+    "src/core/lib/iomgr/tcp_posix.h",
+    "src/core/lib/iomgr/tcp_server.h",
+    "src/core/lib/iomgr/tcp_windows.h",
+    "src/core/lib/iomgr/time_averaged_stats.h",
+    "src/core/lib/iomgr/timer.h",
+    "src/core/lib/iomgr/timer_heap.h",
+    "src/core/lib/iomgr/udp_server.h",
+    "src/core/lib/iomgr/unix_sockets_posix.h",
+    "src/core/lib/iomgr/wakeup_fd_pipe.h",
+    "src/core/lib/iomgr/wakeup_fd_posix.h",
+    "src/core/lib/iomgr/workqueue.h",
+    "src/core/lib/iomgr/workqueue_posix.h",
+    "src/core/lib/iomgr/workqueue_windows.h",
+    "src/core/lib/json/json.h",
+    "src/core/lib/json/json_common.h",
+    "src/core/lib/json/json_reader.h",
+    "src/core/lib/json/json_writer.h",
+    "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h",
+    "src/core/lib/security/auth_filters.h",
+    "src/core/lib/security/b64.h",
+    "src/core/lib/security/credentials.h",
+    "src/core/lib/security/handshake.h",
+    "src/core/lib/security/json_token.h",
+    "src/core/lib/security/jwt_verifier.h",
+    "src/core/lib/security/secure_endpoint.h",
+    "src/core/lib/security/security_connector.h",
+    "src/core/lib/security/security_context.h",
+    "src/core/lib/statistics/census_interface.h",
+    "src/core/lib/statistics/census_rpc_stats.h",
+    "src/core/lib/surface/api_trace.h",
+    "src/core/lib/surface/call.h",
+    "src/core/lib/surface/call_test_only.h",
+    "src/core/lib/surface/channel.h",
+    "src/core/lib/surface/channel_init.h",
+    "src/core/lib/surface/channel_stack_type.h",
+    "src/core/lib/surface/completion_queue.h",
+    "src/core/lib/surface/event_string.h",
+    "src/core/lib/surface/init.h",
+    "src/core/lib/surface/lame_client.h",
+    "src/core/lib/surface/server.h",
+    "src/core/lib/surface/surface_trace.h",
+    "src/core/lib/transport/byte_stream.h",
+    "src/core/lib/transport/connectivity_state.h",
+    "src/core/lib/transport/metadata.h",
+    "src/core/lib/transport/metadata_batch.h",
+    "src/core/lib/transport/static_metadata.h",
+    "src/core/lib/transport/transport.h",
+    "src/core/lib/transport/transport_impl.h",
+    "src/core/lib/tsi/fake_transport_security.h",
+    "src/core/lib/tsi/ssl_transport_security.h",
+    "src/core/lib/tsi/ssl_types.h",
+    "src/core/lib/tsi/transport_security.h",
+    "src/core/lib/tsi/transport_security_interface.h",
+    "src/core/ext/transport/chttp2/client/insecure/channel_create.c",
+    "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c",
+    "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
+    "src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c",
+    "src/core/ext/transport/chttp2/transport/alpn.c",
+    "src/core/ext/transport/chttp2/transport/bin_encoder.c",
+    "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
+    "src/core/ext/transport/chttp2/transport/frame_data.c",
+    "src/core/ext/transport/chttp2/transport/frame_goaway.c",
+    "src/core/ext/transport/chttp2/transport/frame_ping.c",
+    "src/core/ext/transport/chttp2/transport/frame_rst_stream.c",
+    "src/core/ext/transport/chttp2/transport/frame_settings.c",
+    "src/core/ext/transport/chttp2/transport/frame_window_update.c",
+    "src/core/ext/transport/chttp2/transport/hpack_encoder.c",
+    "src/core/ext/transport/chttp2/transport/hpack_parser.c",
+    "src/core/ext/transport/chttp2/transport/hpack_table.c",
+    "src/core/ext/transport/chttp2/transport/huffsyms.c",
+    "src/core/ext/transport/chttp2/transport/incoming_metadata.c",
+    "src/core/ext/transport/chttp2/transport/parsing.c",
+    "src/core/ext/transport/chttp2/transport/status_conversion.c",
+    "src/core/ext/transport/chttp2/transport/stream_lists.c",
+    "src/core/ext/transport/chttp2/transport/stream_map.c",
+    "src/core/ext/transport/chttp2/transport/timeout_encoding.c",
+    "src/core/ext/transport/chttp2/transport/varint.c",
+    "src/core/ext/transport/chttp2/transport/writing.c",
+    "src/core/lib/census/context.c",
+    "src/core/lib/census/grpc_context.c",
+    "src/core/lib/census/grpc_filter.c",
+    "src/core/lib/census/grpc_plugin.c",
+    "src/core/lib/census/initialize.c",
+    "src/core/lib/census/mlog.c",
+    "src/core/lib/census/operation.c",
+    "src/core/lib/census/placeholders.c",
+    "src/core/lib/census/tracing.c",
+    "src/core/lib/channel/channel_args.c",
+    "src/core/lib/channel/channel_stack.c",
+    "src/core/lib/channel/channel_stack_builder.c",
+    "src/core/lib/channel/client_channel.c",
+    "src/core/lib/channel/compress_filter.c",
+    "src/core/lib/channel/connected_channel.c",
+    "src/core/lib/channel/http_client_filter.c",
+    "src/core/lib/channel/http_server_filter.c",
+    "src/core/lib/channel/subchannel_call_holder.c",
+    "src/core/lib/client_config/client_config.c",
+    "src/core/lib/client_config/connector.c",
+    "src/core/lib/client_config/default_initial_connect_string.c",
+    "src/core/lib/client_config/initial_connect_string.c",
+    "src/core/lib/client_config/lb_policies/load_balancer_api.c",
+    "src/core/lib/client_config/lb_policies/pick_first.c",
+    "src/core/lib/client_config/lb_policies/round_robin.c",
+    "src/core/lib/client_config/lb_policy.c",
+    "src/core/lib/client_config/lb_policy_factory.c",
+    "src/core/lib/client_config/lb_policy_registry.c",
+    "src/core/lib/client_config/resolver.c",
+    "src/core/lib/client_config/resolver_factory.c",
+    "src/core/lib/client_config/resolver_registry.c",
+    "src/core/lib/client_config/resolvers/dns_resolver.c",
+    "src/core/lib/client_config/resolvers/sockaddr_resolver.c",
+    "src/core/lib/client_config/subchannel.c",
+    "src/core/lib/client_config/subchannel_factory.c",
+    "src/core/lib/client_config/subchannel_index.c",
+    "src/core/lib/client_config/uri_parser.c",
+    "src/core/lib/compression/compression_algorithm.c",
+    "src/core/lib/compression/message_compress.c",
+    "src/core/lib/debug/trace.c",
+    "src/core/lib/http/format_request.c",
+    "src/core/lib/http/httpcli.c",
+    "src/core/lib/http/httpcli_security_connector.c",
+    "src/core/lib/http/parser.c",
+    "src/core/lib/iomgr/closure.c",
+    "src/core/lib/iomgr/endpoint.c",
+    "src/core/lib/iomgr/endpoint_pair_posix.c",
+    "src/core/lib/iomgr/endpoint_pair_windows.c",
+    "src/core/lib/iomgr/exec_ctx.c",
+    "src/core/lib/iomgr/executor.c",
+    "src/core/lib/iomgr/fd_posix.c",
+    "src/core/lib/iomgr/iocp_windows.c",
+    "src/core/lib/iomgr/iomgr.c",
+    "src/core/lib/iomgr/iomgr_posix.c",
+    "src/core/lib/iomgr/iomgr_windows.c",
+    "src/core/lib/iomgr/pollset_multipoller_with_epoll.c",
+    "src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c",
+    "src/core/lib/iomgr/pollset_posix.c",
+    "src/core/lib/iomgr/pollset_set_posix.c",
+    "src/core/lib/iomgr/pollset_set_windows.c",
+    "src/core/lib/iomgr/pollset_windows.c",
+    "src/core/lib/iomgr/resolve_address_posix.c",
+    "src/core/lib/iomgr/resolve_address_windows.c",
+    "src/core/lib/iomgr/sockaddr_utils.c",
+    "src/core/lib/iomgr/socket_utils_common_posix.c",
+    "src/core/lib/iomgr/socket_utils_linux.c",
+    "src/core/lib/iomgr/socket_utils_posix.c",
+    "src/core/lib/iomgr/socket_windows.c",
+    "src/core/lib/iomgr/tcp_client_posix.c",
+    "src/core/lib/iomgr/tcp_client_windows.c",
+    "src/core/lib/iomgr/tcp_posix.c",
+    "src/core/lib/iomgr/tcp_server_posix.c",
+    "src/core/lib/iomgr/tcp_server_windows.c",
+    "src/core/lib/iomgr/tcp_windows.c",
+    "src/core/lib/iomgr/time_averaged_stats.c",
+    "src/core/lib/iomgr/timer.c",
+    "src/core/lib/iomgr/timer_heap.c",
+    "src/core/lib/iomgr/udp_server.c",
+    "src/core/lib/iomgr/unix_sockets_posix.c",
+    "src/core/lib/iomgr/unix_sockets_posix_noop.c",
+    "src/core/lib/iomgr/wakeup_fd_eventfd.c",
+    "src/core/lib/iomgr/wakeup_fd_nospecial.c",
+    "src/core/lib/iomgr/wakeup_fd_pipe.c",
+    "src/core/lib/iomgr/wakeup_fd_posix.c",
+    "src/core/lib/iomgr/workqueue_posix.c",
+    "src/core/lib/iomgr/workqueue_windows.c",
+    "src/core/lib/json/json.c",
+    "src/core/lib/json/json_reader.c",
+    "src/core/lib/json/json_string.c",
+    "src/core/lib/json/json_writer.c",
+    "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c",
+    "src/core/lib/security/b64.c",
+    "src/core/lib/security/client_auth_filter.c",
+    "src/core/lib/security/credentials.c",
+    "src/core/lib/security/credentials_metadata.c",
+    "src/core/lib/security/credentials_posix.c",
+    "src/core/lib/security/credentials_win32.c",
+    "src/core/lib/security/google_default_credentials.c",
+    "src/core/lib/security/handshake.c",
+    "src/core/lib/security/json_token.c",
+    "src/core/lib/security/jwt_verifier.c",
+    "src/core/lib/security/secure_endpoint.c",
+    "src/core/lib/security/security_connector.c",
+    "src/core/lib/security/security_context.c",
+    "src/core/lib/security/server_auth_filter.c",
+    "src/core/lib/surface/alarm.c",
+    "src/core/lib/surface/api_trace.c",
+    "src/core/lib/surface/byte_buffer.c",
+    "src/core/lib/surface/byte_buffer_reader.c",
+    "src/core/lib/surface/call.c",
+    "src/core/lib/surface/call_details.c",
+    "src/core/lib/surface/call_log_batch.c",
+    "src/core/lib/surface/channel.c",
+    "src/core/lib/surface/channel_connectivity.c",
+    "src/core/lib/surface/channel_init.c",
+    "src/core/lib/surface/channel_ping.c",
+    "src/core/lib/surface/channel_stack_type.c",
+    "src/core/lib/surface/completion_queue.c",
+    "src/core/lib/surface/event_string.c",
+    "src/core/lib/surface/init.c",
+    "src/core/lib/surface/init_secure.c",
+    "src/core/lib/surface/lame_client.c",
+    "src/core/lib/surface/metadata_array.c",
+    "src/core/lib/surface/server.c",
+    "src/core/lib/surface/validate_metadata.c",
+    "src/core/lib/surface/version.c",
+    "src/core/lib/transport/byte_stream.c",
+    "src/core/lib/transport/connectivity_state.c",
+    "src/core/lib/transport/metadata.c",
+    "src/core/lib/transport/metadata_batch.c",
+    "src/core/lib/transport/static_metadata.c",
+    "src/core/lib/transport/transport.c",
+    "src/core/lib/transport/transport_op_string.c",
+    "src/core/lib/tsi/fake_transport_security.c",
+    "src/core/lib/tsi/ssl_transport_security.c",
+    "src/core/lib/tsi/transport_security.c",
+  ],
+  hdrs = [
+    "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/impl/codegen/byte_buffer.h",
+    "include/grpc/impl/codegen/compression_types.h",
+    "include/grpc/impl/codegen/connectivity_state.h",
+    "include/grpc/impl/codegen/grpc_types.h",
+    "include/grpc/impl/codegen/propagation_bits.h",
+    "include/grpc/impl/codegen/status.h",
+    "include/grpc/status.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    "//external:libssl",
+    "//external:zlib",
+    ":gpr",
+    "//external:nanopb",
+  ],
+  copts = [
+    "-std=gnu99",
+  ],
+)
+
+
+
+cc_library(
+  name = "grpc_codegen_lib",
+  srcs = [
+  ],
+  hdrs = [
     "include/grpc/impl/codegen/alloc.h",
     "include/grpc/impl/codegen/atm.h",
     "include/grpc/impl/codegen/atm_gcc_atomic.h",
     "include/grpc/impl/codegen/atm_gcc_sync.h",
     "include/grpc/impl/codegen/atm_win32.h",
+    "include/grpc/impl/codegen/byte_buffer.h",
+    "include/grpc/impl/codegen/compression_types.h",
+    "include/grpc/impl/codegen/connectivity_state.h",
+    "include/grpc/impl/codegen/grpc_types.h",
     "include/grpc/impl/codegen/log.h",
     "include/grpc/impl/codegen/port_platform.h",
+    "include/grpc/impl/codegen/propagation_bits.h",
     "include/grpc/impl/codegen/slice.h",
     "include/grpc/impl/codegen/slice_buffer.h",
+    "include/grpc/impl/codegen/status.h",
     "include/grpc/impl/codegen/sync.h",
     "include/grpc/impl/codegen/sync_generic.h",
     "include/grpc/impl/codegen/sync_posix.h",
@@ -148,619 +521,293 @@
     ".",
   ],
   deps = [
+    "//external:protobuf_compiler",
   ],
 )
 
 
-cc_library(
-  name = "grpc",
-  srcs = [
-    "src/core/census/grpc_filter.h",
-    "src/core/channel/channel_args.h",
-    "src/core/channel/channel_stack.h",
-    "src/core/channel/client_channel.h",
-    "src/core/channel/client_uchannel.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/subchannel_call_holder.h",
-    "src/core/client_config/client_config.h",
-    "src/core/client_config/connector.h",
-    "src/core/client_config/initial_connect_string.h",
-    "src/core/client_config/lb_policies/load_balancer_api.h",
-    "src/core/client_config/lb_policies/pick_first.h",
-    "src/core/client_config/lb_policies/round_robin.h",
-    "src/core/client_config/lb_policy.h",
-    "src/core/client_config/lb_policy_factory.h",
-    "src/core/client_config/lb_policy_registry.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/sockaddr_resolver.h",
-    "src/core/client_config/subchannel.h",
-    "src/core/client_config/subchannel_factory.h",
-    "src/core/client_config/subchannel_index.h",
-    "src/core/client_config/uri_parser.h",
-    "src/core/compression/algorithm_metadata.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/parser.h",
-    "src/core/iomgr/closure.h",
-    "src/core/iomgr/endpoint.h",
-    "src/core/iomgr/endpoint_pair.h",
-    "src/core/iomgr/exec_ctx.h",
-    "src/core/iomgr/executor.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_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/timer.h",
-    "src/core/iomgr/timer_heap.h",
-    "src/core/iomgr/udp_server.h",
-    "src/core/iomgr/wakeup_fd_pipe.h",
-    "src/core/iomgr/wakeup_fd_posix.h",
-    "src/core/iomgr/workqueue.h",
-    "src/core/iomgr/workqueue_posix.h",
-    "src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.h",
-    "src/core/statistics/census_interface.h",
-    "src/core/statistics/census_rpc_stats.h",
-    "src/core/surface/api_trace.h",
-    "src/core/surface/call.h",
-    "src/core/surface/call_test_only.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/byte_stream.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_encoder.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_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/metadata_batch.h",
-    "src/core/transport/static_metadata.h",
-    "src/core/transport/transport.h",
-    "src/core/transport/transport_impl.h",
-    "src/core/security/auth_filters.h",
-    "src/core/security/b64.h",
-    "src/core/security/credentials.h",
-    "src/core/security/handshake.h",
-    "src/core/security/json_token.h",
-    "src/core/security/jwt_verifier.h",
-    "src/core/security/secure_endpoint.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/ssl_types.h",
-    "src/core/tsi/transport_security.h",
-    "src/core/tsi/transport_security_interface.h",
-    "src/core/census/aggregation.h",
-    "src/core/census/mlog.h",
-    "src/core/census/rpc_metric_id.h",
-    "third_party/nanopb/pb.h",
-    "third_party/nanopb/pb_common.h",
-    "third_party/nanopb/pb_decode.h",
-    "third_party/nanopb/pb_encode.h",
-    "src/core/census/grpc_context.c",
-    "src/core/census/grpc_filter.c",
-    "src/core/channel/channel_args.c",
-    "src/core/channel/channel_stack.c",
-    "src/core/channel/client_channel.c",
-    "src/core/channel/client_uchannel.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/subchannel_call_holder.c",
-    "src/core/client_config/client_config.c",
-    "src/core/client_config/connector.c",
-    "src/core/client_config/default_initial_connect_string.c",
-    "src/core/client_config/initial_connect_string.c",
-    "src/core/client_config/lb_policies/load_balancer_api.c",
-    "src/core/client_config/lb_policies/pick_first.c",
-    "src/core/client_config/lb_policies/round_robin.c",
-    "src/core/client_config/lb_policy.c",
-    "src/core/client_config/lb_policy_factory.c",
-    "src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c",
-    "src/core/client_config/subchannel.c",
-    "src/core/client_config/subchannel_factory.c",
-    "src/core/client_config/subchannel_index.c",
-    "src/core/client_config/uri_parser.c",
-    "src/core/compression/compression_algorithm.c",
-    "src/core/compression/message_compress.c",
-    "src/core/debug/trace.c",
-    "src/core/httpcli/format_request.c",
-    "src/core/httpcli/httpcli.c",
-    "src/core/httpcli/parser.c",
-    "src/core/iomgr/closure.c",
-    "src/core/iomgr/endpoint.c",
-    "src/core/iomgr/endpoint_pair_posix.c",
-    "src/core/iomgr/endpoint_pair_windows.c",
-    "src/core/iomgr/exec_ctx.c",
-    "src/core/iomgr/executor.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_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/timer.c",
-    "src/core/iomgr/timer_heap.c",
-    "src/core/iomgr/udp_server.c",
-    "src/core/iomgr/wakeup_fd_eventfd.c",
-    "src/core/iomgr/wakeup_fd_nospecial.c",
-    "src/core/iomgr/wakeup_fd_pipe.c",
-    "src/core/iomgr/wakeup_fd_posix.c",
-    "src/core/iomgr/workqueue_posix.c",
-    "src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c",
-    "src/core/surface/alarm.c",
-    "src/core/surface/api_trace.c",
-    "src/core/surface/byte_buffer.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_connectivity.c",
-    "src/core/surface/channel_create.c",
-    "src/core/surface/channel_ping.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/validate_metadata.c",
-    "src/core/surface/version.c",
-    "src/core/transport/byte_stream.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_encoder.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_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/metadata_batch.c",
-    "src/core/transport/static_metadata.c",
-    "src/core/transport/transport.c",
-    "src/core/transport/transport_op_string.c",
-    "src/core/httpcli/httpcli_security_connector.c",
-    "src/core/security/b64.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/handshake.c",
-    "src/core/security/json_token.c",
-    "src/core/security/jwt_verifier.c",
-    "src/core/security/secure_endpoint.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/context.c",
-    "src/core/census/initialize.c",
-    "src/core/census/mlog.c",
-    "src/core/census/operation.c",
-    "src/core/census/placeholders.c",
-    "src/core/census/tracing.c",
-    "third_party/nanopb/pb_common.c",
-    "third_party/nanopb/pb_decode.c",
-    "third_party/nanopb/pb_encode.c",
-  ],
-  hdrs = [
-    "include/grpc/grpc_security.h",
-    "include/grpc/impl/codegen/byte_buffer.h",
-    "include/grpc/impl/codegen/compression_types.h",
-    "include/grpc/impl/codegen/connectivity_state.h",
-    "include/grpc/impl/codegen/grpc_types.h",
-    "include/grpc/impl/codegen/propagation_bits.h",
-    "include/grpc/impl/codegen/status.h",
-    "include/grpc/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",
-  ],
-  includes = [
-    "include",
-    ".",
-  ],
-  deps = [
-    "//external:libssl",
-    "//external:zlib",
-    ":gpr",
-  ],
-  copts = [
-    "-std=gnu99",
-  ],
-)
-
 
 cc_library(
   name = "grpc_unsecure",
   srcs = [
-    "src/core/census/grpc_filter.h",
-    "src/core/channel/channel_args.h",
-    "src/core/channel/channel_stack.h",
-    "src/core/channel/client_channel.h",
-    "src/core/channel/client_uchannel.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/subchannel_call_holder.h",
-    "src/core/client_config/client_config.h",
-    "src/core/client_config/connector.h",
-    "src/core/client_config/initial_connect_string.h",
-    "src/core/client_config/lb_policies/load_balancer_api.h",
-    "src/core/client_config/lb_policies/pick_first.h",
-    "src/core/client_config/lb_policies/round_robin.h",
-    "src/core/client_config/lb_policy.h",
-    "src/core/client_config/lb_policy_factory.h",
-    "src/core/client_config/lb_policy_registry.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/sockaddr_resolver.h",
-    "src/core/client_config/subchannel.h",
-    "src/core/client_config/subchannel_factory.h",
-    "src/core/client_config/subchannel_index.h",
-    "src/core/client_config/uri_parser.h",
-    "src/core/compression/algorithm_metadata.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/parser.h",
-    "src/core/iomgr/closure.h",
-    "src/core/iomgr/endpoint.h",
-    "src/core/iomgr/endpoint_pair.h",
-    "src/core/iomgr/exec_ctx.h",
-    "src/core/iomgr/executor.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_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/timer.h",
-    "src/core/iomgr/timer_heap.h",
-    "src/core/iomgr/udp_server.h",
-    "src/core/iomgr/wakeup_fd_pipe.h",
-    "src/core/iomgr/wakeup_fd_posix.h",
-    "src/core/iomgr/workqueue.h",
-    "src/core/iomgr/workqueue_posix.h",
-    "src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.h",
-    "src/core/statistics/census_interface.h",
-    "src/core/statistics/census_rpc_stats.h",
-    "src/core/surface/api_trace.h",
-    "src/core/surface/call.h",
-    "src/core/surface/call_test_only.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/byte_stream.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_encoder.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_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/metadata_batch.h",
-    "src/core/transport/static_metadata.h",
-    "src/core/transport/transport.h",
-    "src/core/transport/transport_impl.h",
-    "src/core/census/aggregation.h",
-    "src/core/census/mlog.h",
-    "src/core/census/rpc_metric_id.h",
-    "third_party/nanopb/pb.h",
-    "third_party/nanopb/pb_common.h",
-    "third_party/nanopb/pb_decode.h",
-    "third_party/nanopb/pb_encode.h",
-    "src/core/surface/init_unsecure.c",
-    "src/core/census/grpc_context.c",
-    "src/core/census/grpc_filter.c",
-    "src/core/channel/channel_args.c",
-    "src/core/channel/channel_stack.c",
-    "src/core/channel/client_channel.c",
-    "src/core/channel/client_uchannel.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/subchannel_call_holder.c",
-    "src/core/client_config/client_config.c",
-    "src/core/client_config/connector.c",
-    "src/core/client_config/default_initial_connect_string.c",
-    "src/core/client_config/initial_connect_string.c",
-    "src/core/client_config/lb_policies/load_balancer_api.c",
-    "src/core/client_config/lb_policies/pick_first.c",
-    "src/core/client_config/lb_policies/round_robin.c",
-    "src/core/client_config/lb_policy.c",
-    "src/core/client_config/lb_policy_factory.c",
-    "src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c",
-    "src/core/client_config/subchannel.c",
-    "src/core/client_config/subchannel_factory.c",
-    "src/core/client_config/subchannel_index.c",
-    "src/core/client_config/uri_parser.c",
-    "src/core/compression/compression_algorithm.c",
-    "src/core/compression/message_compress.c",
-    "src/core/debug/trace.c",
-    "src/core/httpcli/format_request.c",
-    "src/core/httpcli/httpcli.c",
-    "src/core/httpcli/parser.c",
-    "src/core/iomgr/closure.c",
-    "src/core/iomgr/endpoint.c",
-    "src/core/iomgr/endpoint_pair_posix.c",
-    "src/core/iomgr/endpoint_pair_windows.c",
-    "src/core/iomgr/exec_ctx.c",
-    "src/core/iomgr/executor.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_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/timer.c",
-    "src/core/iomgr/timer_heap.c",
-    "src/core/iomgr/udp_server.c",
-    "src/core/iomgr/wakeup_fd_eventfd.c",
-    "src/core/iomgr/wakeup_fd_nospecial.c",
-    "src/core/iomgr/wakeup_fd_pipe.c",
-    "src/core/iomgr/wakeup_fd_posix.c",
-    "src/core/iomgr/workqueue_posix.c",
-    "src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c",
-    "src/core/surface/alarm.c",
-    "src/core/surface/api_trace.c",
-    "src/core/surface/byte_buffer.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_connectivity.c",
-    "src/core/surface/channel_create.c",
-    "src/core/surface/channel_ping.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/validate_metadata.c",
-    "src/core/surface/version.c",
-    "src/core/transport/byte_stream.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_encoder.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_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/metadata_batch.c",
-    "src/core/transport/static_metadata.c",
-    "src/core/transport/transport.c",
-    "src/core/transport/transport_op_string.c",
-    "src/core/census/context.c",
-    "src/core/census/initialize.c",
-    "src/core/census/mlog.c",
-    "src/core/census/operation.c",
-    "src/core/census/placeholders.c",
-    "src/core/census/tracing.c",
-    "third_party/nanopb/pb_common.c",
-    "third_party/nanopb/pb_decode.c",
-    "third_party/nanopb/pb_encode.c",
+    "src/core/ext/transport/chttp2/transport/alpn.h",
+    "src/core/ext/transport/chttp2/transport/bin_encoder.h",
+    "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
+    "src/core/ext/transport/chttp2/transport/frame.h",
+    "src/core/ext/transport/chttp2/transport/frame_data.h",
+    "src/core/ext/transport/chttp2/transport/frame_goaway.h",
+    "src/core/ext/transport/chttp2/transport/frame_ping.h",
+    "src/core/ext/transport/chttp2/transport/frame_rst_stream.h",
+    "src/core/ext/transport/chttp2/transport/frame_settings.h",
+    "src/core/ext/transport/chttp2/transport/frame_window_update.h",
+    "src/core/ext/transport/chttp2/transport/hpack_encoder.h",
+    "src/core/ext/transport/chttp2/transport/hpack_parser.h",
+    "src/core/ext/transport/chttp2/transport/hpack_table.h",
+    "src/core/ext/transport/chttp2/transport/http2_errors.h",
+    "src/core/ext/transport/chttp2/transport/huffsyms.h",
+    "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
+    "src/core/ext/transport/chttp2/transport/internal.h",
+    "src/core/ext/transport/chttp2/transport/status_conversion.h",
+    "src/core/ext/transport/chttp2/transport/stream_map.h",
+    "src/core/ext/transport/chttp2/transport/timeout_encoding.h",
+    "src/core/ext/transport/chttp2/transport/varint.h",
+    "src/core/lib/census/aggregation.h",
+    "src/core/lib/census/grpc_filter.h",
+    "src/core/lib/census/grpc_plugin.h",
+    "src/core/lib/census/mlog.h",
+    "src/core/lib/census/rpc_metric_id.h",
+    "src/core/lib/channel/channel_args.h",
+    "src/core/lib/channel/channel_stack.h",
+    "src/core/lib/channel/channel_stack_builder.h",
+    "src/core/lib/channel/client_channel.h",
+    "src/core/lib/channel/compress_filter.h",
+    "src/core/lib/channel/connected_channel.h",
+    "src/core/lib/channel/context.h",
+    "src/core/lib/channel/http_client_filter.h",
+    "src/core/lib/channel/http_server_filter.h",
+    "src/core/lib/channel/subchannel_call_holder.h",
+    "src/core/lib/client_config/client_config.h",
+    "src/core/lib/client_config/connector.h",
+    "src/core/lib/client_config/initial_connect_string.h",
+    "src/core/lib/client_config/lb_policies/load_balancer_api.h",
+    "src/core/lib/client_config/lb_policies/pick_first.h",
+    "src/core/lib/client_config/lb_policies/round_robin.h",
+    "src/core/lib/client_config/lb_policy.h",
+    "src/core/lib/client_config/lb_policy_factory.h",
+    "src/core/lib/client_config/lb_policy_registry.h",
+    "src/core/lib/client_config/resolver.h",
+    "src/core/lib/client_config/resolver_factory.h",
+    "src/core/lib/client_config/resolver_registry.h",
+    "src/core/lib/client_config/resolvers/dns_resolver.h",
+    "src/core/lib/client_config/resolvers/sockaddr_resolver.h",
+    "src/core/lib/client_config/subchannel.h",
+    "src/core/lib/client_config/subchannel_factory.h",
+    "src/core/lib/client_config/subchannel_index.h",
+    "src/core/lib/client_config/uri_parser.h",
+    "src/core/lib/compression/algorithm_metadata.h",
+    "src/core/lib/compression/message_compress.h",
+    "src/core/lib/debug/trace.h",
+    "src/core/lib/http/format_request.h",
+    "src/core/lib/http/httpcli.h",
+    "src/core/lib/http/parser.h",
+    "src/core/lib/iomgr/closure.h",
+    "src/core/lib/iomgr/endpoint.h",
+    "src/core/lib/iomgr/endpoint_pair.h",
+    "src/core/lib/iomgr/exec_ctx.h",
+    "src/core/lib/iomgr/executor.h",
+    "src/core/lib/iomgr/fd_posix.h",
+    "src/core/lib/iomgr/iocp_windows.h",
+    "src/core/lib/iomgr/iomgr.h",
+    "src/core/lib/iomgr/iomgr_internal.h",
+    "src/core/lib/iomgr/iomgr_posix.h",
+    "src/core/lib/iomgr/pollset.h",
+    "src/core/lib/iomgr/pollset_posix.h",
+    "src/core/lib/iomgr/pollset_set.h",
+    "src/core/lib/iomgr/pollset_set_posix.h",
+    "src/core/lib/iomgr/pollset_set_windows.h",
+    "src/core/lib/iomgr/pollset_windows.h",
+    "src/core/lib/iomgr/resolve_address.h",
+    "src/core/lib/iomgr/sockaddr.h",
+    "src/core/lib/iomgr/sockaddr_posix.h",
+    "src/core/lib/iomgr/sockaddr_utils.h",
+    "src/core/lib/iomgr/sockaddr_win32.h",
+    "src/core/lib/iomgr/socket_utils_posix.h",
+    "src/core/lib/iomgr/socket_windows.h",
+    "src/core/lib/iomgr/tcp_client.h",
+    "src/core/lib/iomgr/tcp_posix.h",
+    "src/core/lib/iomgr/tcp_server.h",
+    "src/core/lib/iomgr/tcp_windows.h",
+    "src/core/lib/iomgr/time_averaged_stats.h",
+    "src/core/lib/iomgr/timer.h",
+    "src/core/lib/iomgr/timer_heap.h",
+    "src/core/lib/iomgr/udp_server.h",
+    "src/core/lib/iomgr/unix_sockets_posix.h",
+    "src/core/lib/iomgr/wakeup_fd_pipe.h",
+    "src/core/lib/iomgr/wakeup_fd_posix.h",
+    "src/core/lib/iomgr/workqueue.h",
+    "src/core/lib/iomgr/workqueue_posix.h",
+    "src/core/lib/iomgr/workqueue_windows.h",
+    "src/core/lib/json/json.h",
+    "src/core/lib/json/json_common.h",
+    "src/core/lib/json/json_reader.h",
+    "src/core/lib/json/json_writer.h",
+    "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h",
+    "src/core/lib/statistics/census_interface.h",
+    "src/core/lib/statistics/census_rpc_stats.h",
+    "src/core/lib/surface/api_trace.h",
+    "src/core/lib/surface/call.h",
+    "src/core/lib/surface/call_test_only.h",
+    "src/core/lib/surface/channel.h",
+    "src/core/lib/surface/channel_init.h",
+    "src/core/lib/surface/channel_stack_type.h",
+    "src/core/lib/surface/completion_queue.h",
+    "src/core/lib/surface/event_string.h",
+    "src/core/lib/surface/init.h",
+    "src/core/lib/surface/lame_client.h",
+    "src/core/lib/surface/server.h",
+    "src/core/lib/surface/surface_trace.h",
+    "src/core/lib/transport/byte_stream.h",
+    "src/core/lib/transport/connectivity_state.h",
+    "src/core/lib/transport/metadata.h",
+    "src/core/lib/transport/metadata_batch.h",
+    "src/core/lib/transport/static_metadata.h",
+    "src/core/lib/transport/transport.h",
+    "src/core/lib/transport/transport_impl.h",
+    "src/core/ext/transport/chttp2/client/insecure/channel_create.c",
+    "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
+    "src/core/ext/transport/chttp2/transport/alpn.c",
+    "src/core/ext/transport/chttp2/transport/bin_encoder.c",
+    "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
+    "src/core/ext/transport/chttp2/transport/frame_data.c",
+    "src/core/ext/transport/chttp2/transport/frame_goaway.c",
+    "src/core/ext/transport/chttp2/transport/frame_ping.c",
+    "src/core/ext/transport/chttp2/transport/frame_rst_stream.c",
+    "src/core/ext/transport/chttp2/transport/frame_settings.c",
+    "src/core/ext/transport/chttp2/transport/frame_window_update.c",
+    "src/core/ext/transport/chttp2/transport/hpack_encoder.c",
+    "src/core/ext/transport/chttp2/transport/hpack_parser.c",
+    "src/core/ext/transport/chttp2/transport/hpack_table.c",
+    "src/core/ext/transport/chttp2/transport/huffsyms.c",
+    "src/core/ext/transport/chttp2/transport/incoming_metadata.c",
+    "src/core/ext/transport/chttp2/transport/parsing.c",
+    "src/core/ext/transport/chttp2/transport/status_conversion.c",
+    "src/core/ext/transport/chttp2/transport/stream_lists.c",
+    "src/core/ext/transport/chttp2/transport/stream_map.c",
+    "src/core/ext/transport/chttp2/transport/timeout_encoding.c",
+    "src/core/ext/transport/chttp2/transport/varint.c",
+    "src/core/ext/transport/chttp2/transport/writing.c",
+    "src/core/lib/census/context.c",
+    "src/core/lib/census/grpc_context.c",
+    "src/core/lib/census/grpc_filter.c",
+    "src/core/lib/census/grpc_plugin.c",
+    "src/core/lib/census/initialize.c",
+    "src/core/lib/census/mlog.c",
+    "src/core/lib/census/operation.c",
+    "src/core/lib/census/placeholders.c",
+    "src/core/lib/census/tracing.c",
+    "src/core/lib/channel/channel_args.c",
+    "src/core/lib/channel/channel_stack.c",
+    "src/core/lib/channel/channel_stack_builder.c",
+    "src/core/lib/channel/client_channel.c",
+    "src/core/lib/channel/compress_filter.c",
+    "src/core/lib/channel/connected_channel.c",
+    "src/core/lib/channel/http_client_filter.c",
+    "src/core/lib/channel/http_server_filter.c",
+    "src/core/lib/channel/subchannel_call_holder.c",
+    "src/core/lib/client_config/client_config.c",
+    "src/core/lib/client_config/connector.c",
+    "src/core/lib/client_config/default_initial_connect_string.c",
+    "src/core/lib/client_config/initial_connect_string.c",
+    "src/core/lib/client_config/lb_policies/load_balancer_api.c",
+    "src/core/lib/client_config/lb_policies/pick_first.c",
+    "src/core/lib/client_config/lb_policies/round_robin.c",
+    "src/core/lib/client_config/lb_policy.c",
+    "src/core/lib/client_config/lb_policy_factory.c",
+    "src/core/lib/client_config/lb_policy_registry.c",
+    "src/core/lib/client_config/resolver.c",
+    "src/core/lib/client_config/resolver_factory.c",
+    "src/core/lib/client_config/resolver_registry.c",
+    "src/core/lib/client_config/resolvers/dns_resolver.c",
+    "src/core/lib/client_config/resolvers/sockaddr_resolver.c",
+    "src/core/lib/client_config/subchannel.c",
+    "src/core/lib/client_config/subchannel_factory.c",
+    "src/core/lib/client_config/subchannel_index.c",
+    "src/core/lib/client_config/uri_parser.c",
+    "src/core/lib/compression/compression_algorithm.c",
+    "src/core/lib/compression/message_compress.c",
+    "src/core/lib/debug/trace.c",
+    "src/core/lib/http/format_request.c",
+    "src/core/lib/http/httpcli.c",
+    "src/core/lib/http/parser.c",
+    "src/core/lib/iomgr/closure.c",
+    "src/core/lib/iomgr/endpoint.c",
+    "src/core/lib/iomgr/endpoint_pair_posix.c",
+    "src/core/lib/iomgr/endpoint_pair_windows.c",
+    "src/core/lib/iomgr/exec_ctx.c",
+    "src/core/lib/iomgr/executor.c",
+    "src/core/lib/iomgr/fd_posix.c",
+    "src/core/lib/iomgr/iocp_windows.c",
+    "src/core/lib/iomgr/iomgr.c",
+    "src/core/lib/iomgr/iomgr_posix.c",
+    "src/core/lib/iomgr/iomgr_windows.c",
+    "src/core/lib/iomgr/pollset_multipoller_with_epoll.c",
+    "src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c",
+    "src/core/lib/iomgr/pollset_posix.c",
+    "src/core/lib/iomgr/pollset_set_posix.c",
+    "src/core/lib/iomgr/pollset_set_windows.c",
+    "src/core/lib/iomgr/pollset_windows.c",
+    "src/core/lib/iomgr/resolve_address_posix.c",
+    "src/core/lib/iomgr/resolve_address_windows.c",
+    "src/core/lib/iomgr/sockaddr_utils.c",
+    "src/core/lib/iomgr/socket_utils_common_posix.c",
+    "src/core/lib/iomgr/socket_utils_linux.c",
+    "src/core/lib/iomgr/socket_utils_posix.c",
+    "src/core/lib/iomgr/socket_windows.c",
+    "src/core/lib/iomgr/tcp_client_posix.c",
+    "src/core/lib/iomgr/tcp_client_windows.c",
+    "src/core/lib/iomgr/tcp_posix.c",
+    "src/core/lib/iomgr/tcp_server_posix.c",
+    "src/core/lib/iomgr/tcp_server_windows.c",
+    "src/core/lib/iomgr/tcp_windows.c",
+    "src/core/lib/iomgr/time_averaged_stats.c",
+    "src/core/lib/iomgr/timer.c",
+    "src/core/lib/iomgr/timer_heap.c",
+    "src/core/lib/iomgr/udp_server.c",
+    "src/core/lib/iomgr/unix_sockets_posix.c",
+    "src/core/lib/iomgr/unix_sockets_posix_noop.c",
+    "src/core/lib/iomgr/wakeup_fd_eventfd.c",
+    "src/core/lib/iomgr/wakeup_fd_nospecial.c",
+    "src/core/lib/iomgr/wakeup_fd_pipe.c",
+    "src/core/lib/iomgr/wakeup_fd_posix.c",
+    "src/core/lib/iomgr/workqueue_posix.c",
+    "src/core/lib/iomgr/workqueue_windows.c",
+    "src/core/lib/json/json.c",
+    "src/core/lib/json/json_reader.c",
+    "src/core/lib/json/json_string.c",
+    "src/core/lib/json/json_writer.c",
+    "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c",
+    "src/core/lib/surface/alarm.c",
+    "src/core/lib/surface/api_trace.c",
+    "src/core/lib/surface/byte_buffer.c",
+    "src/core/lib/surface/byte_buffer_reader.c",
+    "src/core/lib/surface/call.c",
+    "src/core/lib/surface/call_details.c",
+    "src/core/lib/surface/call_log_batch.c",
+    "src/core/lib/surface/channel.c",
+    "src/core/lib/surface/channel_connectivity.c",
+    "src/core/lib/surface/channel_init.c",
+    "src/core/lib/surface/channel_ping.c",
+    "src/core/lib/surface/channel_stack_type.c",
+    "src/core/lib/surface/completion_queue.c",
+    "src/core/lib/surface/event_string.c",
+    "src/core/lib/surface/init.c",
+    "src/core/lib/surface/init_unsecure.c",
+    "src/core/lib/surface/lame_client.c",
+    "src/core/lib/surface/metadata_array.c",
+    "src/core/lib/surface/server.c",
+    "src/core/lib/surface/validate_metadata.c",
+    "src/core/lib/surface/version.c",
+    "src/core/lib/transport/byte_stream.c",
+    "src/core/lib/transport/connectivity_state.c",
+    "src/core/lib/transport/metadata.c",
+    "src/core/lib/transport/metadata_batch.c",
+    "src/core/lib/transport/static_metadata.c",
+    "src/core/lib/transport/transport.c",
+    "src/core/lib/transport/transport_op_string.c",
   ],
   hdrs = [
     "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",
     "include/grpc/impl/codegen/byte_buffer.h",
     "include/grpc/impl/codegen/compression_types.h",
     "include/grpc/impl/codegen/connectivity_state.h",
     "include/grpc/impl/codegen/grpc_types.h",
     "include/grpc/impl/codegen/propagation_bits.h",
     "include/grpc/impl/codegen/status.h",
-    "include/grpc/census.h",
+    "include/grpc/status.h",
   ],
   includes = [
     "include",
@@ -768,6 +815,7 @@
   ],
   deps = [
     ":gpr",
+    "//external:nanopb",
   ],
   copts = [
     "-std=gnu99",
@@ -775,11 +823,12 @@
 )
 
 
+
 cc_library(
   name = "grpc_zookeeper",
   srcs = [
-    "src/core/client_config/resolvers/zookeeper_resolver.h",
-    "src/core/client_config/resolvers/zookeeper_resolver.c",
+    "src/core/lib/client_config/resolvers/zookeeper_resolver.h",
+    "src/core/lib/client_config/resolvers/zookeeper_resolver.c",
   ],
   hdrs = [
     "include/grpc/grpc_zookeeper.h",
@@ -795,22 +844,18 @@
 )
 
 
+
 cc_library(
   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/create_channel_internal.h",
+    "src/cpp/client/secure_credentials.h",
+    "src/cpp/common/core_codegen.h",
     "src/cpp/common/create_auth_context.h",
+    "src/cpp/common/secure_auth_context.h",
     "src/cpp/server/dynamic_thread_pool.h",
+    "src/cpp/server/secure_server_credentials.h",
     "src/cpp/server/thread_pool_interface.h",
-    "src/cpp/client/secure_credentials.cc",
-    "src/cpp/common/auth_property_iterator.cc",
-    "src/cpp/common/secure_auth_context.cc",
-    "src/cpp/common/secure_channel_arguments.cc",
-    "src/cpp/common/secure_create_auth_context.cc",
-    "src/cpp/server/secure_server_credentials.cc",
     "src/cpp/client/channel.cc",
     "src/cpp/client/client_context.cc",
     "src/cpp/client/create_channel.cc",
@@ -818,15 +863,21 @@
     "src/cpp/client/credentials.cc",
     "src/cpp/client/generic_stub.cc",
     "src/cpp/client/insecure_credentials.cc",
-    "src/cpp/common/call.cc",
+    "src/cpp/client/secure_credentials.cc",
+    "src/cpp/codegen/codegen_init.cc",
+    "src/cpp/common/auth_property_iterator.cc",
     "src/cpp/common/channel_arguments.cc",
     "src/cpp/common/completion_queue.cc",
+    "src/cpp/common/core_codegen.cc",
     "src/cpp/common/rpc_method.cc",
-    "src/cpp/proto/proto_utils.cc",
+    "src/cpp/common/secure_auth_context.cc",
+    "src/cpp/common/secure_channel_arguments.cc",
+    "src/cpp/common/secure_create_auth_context.cc",
     "src/cpp/server/async_generic_service.cc",
     "src/cpp/server/create_default_thread_pool.cc",
     "src/cpp/server/dynamic_thread_pool.cc",
     "src/cpp/server/insecure_server_credentials.cc",
+    "src/cpp/server/secure_server_credentials.cc",
     "src/cpp/server/server.cc",
     "src/cpp/server/server_builder.cc",
     "src/cpp/server/server_context.cc",
@@ -836,7 +887,6 @@
     "src/cpp/util/status.cc",
     "src/cpp/util/string_ref.cc",
     "src/cpp/util/time.cc",
-    "src/cpp/codegen/grpc_library.cc",
   ],
   hdrs = [
     "include/grpc++/alarm.h",
@@ -849,6 +899,37 @@
     "include/grpc++/grpc++.h",
     "include/grpc++/impl/call.h",
     "include/grpc++/impl/client_unary_call.h",
+    "include/grpc++/impl/codegen/async_stream.h",
+    "include/grpc++/impl/codegen/async_unary_call.h",
+    "include/grpc++/impl/codegen/call.h",
+    "include/grpc++/impl/codegen/call_hook.h",
+    "include/grpc++/impl/codegen/channel_interface.h",
+    "include/grpc++/impl/codegen/client_context.h",
+    "include/grpc++/impl/codegen/client_unary_call.h",
+    "include/grpc++/impl/codegen/completion_queue.h",
+    "include/grpc++/impl/codegen/completion_queue_tag.h",
+    "include/grpc++/impl/codegen/config.h",
+    "include/grpc++/impl/codegen/config_protobuf.h",
+    "include/grpc++/impl/codegen/core_codegen_interface.h",
+    "include/grpc++/impl/codegen/grpc_library.h",
+    "include/grpc++/impl/codegen/method_handler_impl.h",
+    "include/grpc++/impl/codegen/proto_utils.h",
+    "include/grpc++/impl/codegen/rpc_method.h",
+    "include/grpc++/impl/codegen/rpc_service_method.h",
+    "include/grpc++/impl/codegen/security/auth_context.h",
+    "include/grpc++/impl/codegen/serialization_traits.h",
+    "include/grpc++/impl/codegen/server_context.h",
+    "include/grpc++/impl/codegen/server_interface.h",
+    "include/grpc++/impl/codegen/service_type.h",
+    "include/grpc++/impl/codegen/status.h",
+    "include/grpc++/impl/codegen/status_code_enum.h",
+    "include/grpc++/impl/codegen/string_ref.h",
+    "include/grpc++/impl/codegen/stub_options.h",
+    "include/grpc++/impl/codegen/sync.h",
+    "include/grpc++/impl/codegen/sync_cxx11.h",
+    "include/grpc++/impl/codegen/sync_no_cxx11.h",
+    "include/grpc++/impl/codegen/sync_stream.h",
+    "include/grpc++/impl/codegen/time.h",
     "include/grpc++/impl/grpc_library.h",
     "include/grpc++/impl/method_handler_impl.h",
     "include/grpc++/impl/proto_utils.h",
@@ -883,36 +964,6 @@
     "include/grpc++/support/stub_options.h",
     "include/grpc++/support/sync_stream.h",
     "include/grpc++/support/time.h",
-    "include/grpc++/impl/codegen/async_stream.h",
-    "include/grpc++/impl/codegen/async_unary_call.h",
-    "include/grpc++/impl/codegen/call.h",
-    "include/grpc++/impl/codegen/call_hook.h",
-    "include/grpc++/impl/codegen/channel_interface.h",
-    "include/grpc++/impl/codegen/client_context.h",
-    "include/grpc++/impl/codegen/client_unary_call.h",
-    "include/grpc++/impl/codegen/completion_queue.h",
-    "include/grpc++/impl/codegen/completion_queue_tag.h",
-    "include/grpc++/impl/codegen/config.h",
-    "include/grpc++/impl/codegen/config_protobuf.h",
-    "include/grpc++/impl/codegen/grpc_library.h",
-    "include/grpc++/impl/codegen/method_handler_impl.h",
-    "include/grpc++/impl/codegen/proto_utils.h",
-    "include/grpc++/impl/codegen/rpc_method.h",
-    "include/grpc++/impl/codegen/rpc_service_method.h",
-    "include/grpc++/impl/codegen/security/auth_context.h",
-    "include/grpc++/impl/codegen/serialization_traits.h",
-    "include/grpc++/impl/codegen/server_context.h",
-    "include/grpc++/impl/codegen/server_interface.h",
-    "include/grpc++/impl/codegen/service_type.h",
-    "include/grpc++/impl/codegen/status.h",
-    "include/grpc++/impl/codegen/status_code_enum.h",
-    "include/grpc++/impl/codegen/string_ref.h",
-    "include/grpc++/impl/codegen/stub_options.h",
-    "include/grpc++/impl/codegen/sync.h",
-    "include/grpc++/impl/codegen/sync_cxx11.h",
-    "include/grpc++/impl/codegen/sync_no_cxx11.h",
-    "include/grpc++/impl/codegen/sync_stream.h",
-    "include/grpc++/impl/codegen/time.h",
   ],
   includes = [
     "include",
@@ -926,14 +977,84 @@
 )
 
 
+
+cc_library(
+  name = "grpc++_codegen_lib",
+  srcs = [
+    "src/cpp/codegen/codegen_init.cc",
+  ],
+  hdrs = [
+    "include/grpc++/impl/codegen/async_stream.h",
+    "include/grpc++/impl/codegen/async_unary_call.h",
+    "include/grpc++/impl/codegen/call.h",
+    "include/grpc++/impl/codegen/call_hook.h",
+    "include/grpc++/impl/codegen/channel_interface.h",
+    "include/grpc++/impl/codegen/client_context.h",
+    "include/grpc++/impl/codegen/client_unary_call.h",
+    "include/grpc++/impl/codegen/completion_queue.h",
+    "include/grpc++/impl/codegen/completion_queue_tag.h",
+    "include/grpc++/impl/codegen/config.h",
+    "include/grpc++/impl/codegen/config_protobuf.h",
+    "include/grpc++/impl/codegen/core_codegen_interface.h",
+    "include/grpc++/impl/codegen/grpc_library.h",
+    "include/grpc++/impl/codegen/method_handler_impl.h",
+    "include/grpc++/impl/codegen/proto_utils.h",
+    "include/grpc++/impl/codegen/rpc_method.h",
+    "include/grpc++/impl/codegen/rpc_service_method.h",
+    "include/grpc++/impl/codegen/security/auth_context.h",
+    "include/grpc++/impl/codegen/serialization_traits.h",
+    "include/grpc++/impl/codegen/server_context.h",
+    "include/grpc++/impl/codegen/server_interface.h",
+    "include/grpc++/impl/codegen/service_type.h",
+    "include/grpc++/impl/codegen/status.h",
+    "include/grpc++/impl/codegen/status_code_enum.h",
+    "include/grpc++/impl/codegen/string_ref.h",
+    "include/grpc++/impl/codegen/stub_options.h",
+    "include/grpc++/impl/codegen/sync.h",
+    "include/grpc++/impl/codegen/sync_cxx11.h",
+    "include/grpc++/impl/codegen/sync_no_cxx11.h",
+    "include/grpc++/impl/codegen/sync_stream.h",
+    "include/grpc++/impl/codegen/time.h",
+    "include/grpc/impl/codegen/alloc.h",
+    "include/grpc/impl/codegen/atm.h",
+    "include/grpc/impl/codegen/atm_gcc_atomic.h",
+    "include/grpc/impl/codegen/atm_gcc_sync.h",
+    "include/grpc/impl/codegen/atm_win32.h",
+    "include/grpc/impl/codegen/byte_buffer.h",
+    "include/grpc/impl/codegen/compression_types.h",
+    "include/grpc/impl/codegen/connectivity_state.h",
+    "include/grpc/impl/codegen/grpc_types.h",
+    "include/grpc/impl/codegen/log.h",
+    "include/grpc/impl/codegen/port_platform.h",
+    "include/grpc/impl/codegen/propagation_bits.h",
+    "include/grpc/impl/codegen/slice.h",
+    "include/grpc/impl/codegen/slice_buffer.h",
+    "include/grpc/impl/codegen/status.h",
+    "include/grpc/impl/codegen/sync.h",
+    "include/grpc/impl/codegen/sync_generic.h",
+    "include/grpc/impl/codegen/sync_posix.h",
+    "include/grpc/impl/codegen/sync_win32.h",
+    "include/grpc/impl/codegen/time.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    "//external:protobuf_clib",
+  ],
+)
+
+
+
 cc_library(
   name = "grpc++_unsecure",
   srcs = [
     "src/cpp/client/create_channel_internal.h",
+    "src/cpp/common/core_codegen.h",
     "src/cpp/common/create_auth_context.h",
     "src/cpp/server/dynamic_thread_pool.h",
     "src/cpp/server/thread_pool_interface.h",
-    "src/cpp/common/insecure_create_auth_context.cc",
     "src/cpp/client/channel.cc",
     "src/cpp/client/client_context.cc",
     "src/cpp/client/create_channel.cc",
@@ -941,11 +1062,12 @@
     "src/cpp/client/credentials.cc",
     "src/cpp/client/generic_stub.cc",
     "src/cpp/client/insecure_credentials.cc",
-    "src/cpp/common/call.cc",
+    "src/cpp/codegen/codegen_init.cc",
     "src/cpp/common/channel_arguments.cc",
     "src/cpp/common/completion_queue.cc",
+    "src/cpp/common/core_codegen.cc",
+    "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/dynamic_thread_pool.cc",
@@ -959,7 +1081,6 @@
     "src/cpp/util/status.cc",
     "src/cpp/util/string_ref.cc",
     "src/cpp/util/time.cc",
-    "src/cpp/codegen/grpc_library.cc",
   ],
   hdrs = [
     "include/grpc++/alarm.h",
@@ -972,6 +1093,37 @@
     "include/grpc++/grpc++.h",
     "include/grpc++/impl/call.h",
     "include/grpc++/impl/client_unary_call.h",
+    "include/grpc++/impl/codegen/async_stream.h",
+    "include/grpc++/impl/codegen/async_unary_call.h",
+    "include/grpc++/impl/codegen/call.h",
+    "include/grpc++/impl/codegen/call_hook.h",
+    "include/grpc++/impl/codegen/channel_interface.h",
+    "include/grpc++/impl/codegen/client_context.h",
+    "include/grpc++/impl/codegen/client_unary_call.h",
+    "include/grpc++/impl/codegen/completion_queue.h",
+    "include/grpc++/impl/codegen/completion_queue_tag.h",
+    "include/grpc++/impl/codegen/config.h",
+    "include/grpc++/impl/codegen/config_protobuf.h",
+    "include/grpc++/impl/codegen/core_codegen_interface.h",
+    "include/grpc++/impl/codegen/grpc_library.h",
+    "include/grpc++/impl/codegen/method_handler_impl.h",
+    "include/grpc++/impl/codegen/proto_utils.h",
+    "include/grpc++/impl/codegen/rpc_method.h",
+    "include/grpc++/impl/codegen/rpc_service_method.h",
+    "include/grpc++/impl/codegen/security/auth_context.h",
+    "include/grpc++/impl/codegen/serialization_traits.h",
+    "include/grpc++/impl/codegen/server_context.h",
+    "include/grpc++/impl/codegen/server_interface.h",
+    "include/grpc++/impl/codegen/service_type.h",
+    "include/grpc++/impl/codegen/status.h",
+    "include/grpc++/impl/codegen/status_code_enum.h",
+    "include/grpc++/impl/codegen/string_ref.h",
+    "include/grpc++/impl/codegen/stub_options.h",
+    "include/grpc++/impl/codegen/sync.h",
+    "include/grpc++/impl/codegen/sync_cxx11.h",
+    "include/grpc++/impl/codegen/sync_no_cxx11.h",
+    "include/grpc++/impl/codegen/sync_stream.h",
+    "include/grpc++/impl/codegen/time.h",
     "include/grpc++/impl/grpc_library.h",
     "include/grpc++/impl/method_handler_impl.h",
     "include/grpc++/impl/proto_utils.h",
@@ -1006,36 +1158,6 @@
     "include/grpc++/support/stub_options.h",
     "include/grpc++/support/sync_stream.h",
     "include/grpc++/support/time.h",
-    "include/grpc++/impl/codegen/async_stream.h",
-    "include/grpc++/impl/codegen/async_unary_call.h",
-    "include/grpc++/impl/codegen/call.h",
-    "include/grpc++/impl/codegen/call_hook.h",
-    "include/grpc++/impl/codegen/channel_interface.h",
-    "include/grpc++/impl/codegen/client_context.h",
-    "include/grpc++/impl/codegen/client_unary_call.h",
-    "include/grpc++/impl/codegen/completion_queue.h",
-    "include/grpc++/impl/codegen/completion_queue_tag.h",
-    "include/grpc++/impl/codegen/config.h",
-    "include/grpc++/impl/codegen/config_protobuf.h",
-    "include/grpc++/impl/codegen/grpc_library.h",
-    "include/grpc++/impl/codegen/method_handler_impl.h",
-    "include/grpc++/impl/codegen/proto_utils.h",
-    "include/grpc++/impl/codegen/rpc_method.h",
-    "include/grpc++/impl/codegen/rpc_service_method.h",
-    "include/grpc++/impl/codegen/security/auth_context.h",
-    "include/grpc++/impl/codegen/serialization_traits.h",
-    "include/grpc++/impl/codegen/server_context.h",
-    "include/grpc++/impl/codegen/server_interface.h",
-    "include/grpc++/impl/codegen/service_type.h",
-    "include/grpc++/impl/codegen/status.h",
-    "include/grpc++/impl/codegen/status_code_enum.h",
-    "include/grpc++/impl/codegen/string_ref.h",
-    "include/grpc++/impl/codegen/stub_options.h",
-    "include/grpc++/impl/codegen/sync.h",
-    "include/grpc++/impl/codegen/sync_cxx11.h",
-    "include/grpc++/impl/codegen/sync_no_cxx11.h",
-    "include/grpc++/impl/codegen/sync_stream.h",
-    "include/grpc++/impl/codegen/time.h",
   ],
   includes = [
     "include",
@@ -1049,6 +1171,7 @@
 )
 
 
+
 cc_library(
   name = "grpc_plugin_support",
   srcs = [
@@ -1072,45 +1195,8 @@
     "src/compiler/objective_c_generator.cc",
     "src/compiler/python_generator.cc",
     "src/compiler/ruby_generator.cc",
-    "src/cpp/codegen/grpc_library.cc",
   ],
   hdrs = [
-    "include/grpc++/impl/codegen/async_stream.h",
-    "include/grpc++/impl/codegen/async_unary_call.h",
-    "include/grpc++/impl/codegen/call.h",
-    "include/grpc++/impl/codegen/call_hook.h",
-    "include/grpc++/impl/codegen/channel_interface.h",
-    "include/grpc++/impl/codegen/client_context.h",
-    "include/grpc++/impl/codegen/client_unary_call.h",
-    "include/grpc++/impl/codegen/completion_queue.h",
-    "include/grpc++/impl/codegen/completion_queue_tag.h",
-    "include/grpc++/impl/codegen/config.h",
-    "include/grpc++/impl/codegen/config_protobuf.h",
-    "include/grpc++/impl/codegen/grpc_library.h",
-    "include/grpc++/impl/codegen/method_handler_impl.h",
-    "include/grpc++/impl/codegen/proto_utils.h",
-    "include/grpc++/impl/codegen/rpc_method.h",
-    "include/grpc++/impl/codegen/rpc_service_method.h",
-    "include/grpc++/impl/codegen/security/auth_context.h",
-    "include/grpc++/impl/codegen/serialization_traits.h",
-    "include/grpc++/impl/codegen/server_context.h",
-    "include/grpc++/impl/codegen/server_interface.h",
-    "include/grpc++/impl/codegen/service_type.h",
-    "include/grpc++/impl/codegen/status.h",
-    "include/grpc++/impl/codegen/status_code_enum.h",
-    "include/grpc++/impl/codegen/string_ref.h",
-    "include/grpc++/impl/codegen/stub_options.h",
-    "include/grpc++/impl/codegen/sync.h",
-    "include/grpc++/impl/codegen/sync_cxx11.h",
-    "include/grpc++/impl/codegen/sync_no_cxx11.h",
-    "include/grpc++/impl/codegen/sync_stream.h",
-    "include/grpc++/impl/codegen/time.h",
-    "include/grpc/impl/codegen/byte_buffer.h",
-    "include/grpc/impl/codegen/compression_types.h",
-    "include/grpc/impl/codegen/connectivity_state.h",
-    "include/grpc/impl/codegen/grpc_types.h",
-    "include/grpc/impl/codegen/propagation_bits.h",
-    "include/grpc/impl/codegen/status.h",
     "include/grpc/impl/codegen/alloc.h",
     "include/grpc/impl/codegen/atm.h",
     "include/grpc/impl/codegen/atm_gcc_atomic.h",
@@ -1132,10 +1218,12 @@
   ],
   deps = [
     "//external:protobuf_compiler",
+    ":grpc++_codegen_lib",
   ],
 )
 
 
+
 cc_library(
   name = "grpc_csharp_ext",
   srcs = [
@@ -1155,54 +1243,70 @@
 
 
 
+
 objc_library(
   name = "gpr_objc",
   srcs = [
-    "src/core/profiling/basic_timers.c",
-    "src/core/profiling/stap_timers.c",
-    "src/core/support/alloc.c",
-    "src/core/support/avl.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/histogram.c",
-    "src/core/support/host_port.c",
-    "src/core/support/load_file.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/subprocess_windows.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_precise.c",
-    "src/core/support/time_win32.c",
-    "src/core/support/tls_pthread.c",
-    "src/core/support/tmpfile_posix.c",
-    "src/core/support/tmpfile_win32.c",
-    "src/core/support/wrap_memcpy.c",
+    "src/core/lib/profiling/basic_timers.c",
+    "src/core/lib/profiling/stap_timers.c",
+    "src/core/lib/support/alloc.c",
+    "src/core/lib/support/avl.c",
+    "src/core/lib/support/backoff.c",
+    "src/core/lib/support/cmdline.c",
+    "src/core/lib/support/cpu_iphone.c",
+    "src/core/lib/support/cpu_linux.c",
+    "src/core/lib/support/cpu_posix.c",
+    "src/core/lib/support/cpu_windows.c",
+    "src/core/lib/support/env_linux.c",
+    "src/core/lib/support/env_posix.c",
+    "src/core/lib/support/env_win32.c",
+    "src/core/lib/support/histogram.c",
+    "src/core/lib/support/host_port.c",
+    "src/core/lib/support/load_file.c",
+    "src/core/lib/support/log.c",
+    "src/core/lib/support/log_android.c",
+    "src/core/lib/support/log_linux.c",
+    "src/core/lib/support/log_posix.c",
+    "src/core/lib/support/log_win32.c",
+    "src/core/lib/support/murmur_hash.c",
+    "src/core/lib/support/slice.c",
+    "src/core/lib/support/slice_buffer.c",
+    "src/core/lib/support/stack_lockfree.c",
+    "src/core/lib/support/string.c",
+    "src/core/lib/support/string_posix.c",
+    "src/core/lib/support/string_win32.c",
+    "src/core/lib/support/subprocess_posix.c",
+    "src/core/lib/support/subprocess_windows.c",
+    "src/core/lib/support/sync.c",
+    "src/core/lib/support/sync_posix.c",
+    "src/core/lib/support/sync_win32.c",
+    "src/core/lib/support/thd.c",
+    "src/core/lib/support/thd_posix.c",
+    "src/core/lib/support/thd_win32.c",
+    "src/core/lib/support/time.c",
+    "src/core/lib/support/time_posix.c",
+    "src/core/lib/support/time_precise.c",
+    "src/core/lib/support/time_win32.c",
+    "src/core/lib/support/tls_pthread.c",
+    "src/core/lib/support/tmpfile_posix.c",
+    "src/core/lib/support/tmpfile_win32.c",
+    "src/core/lib/support/wrap_memcpy.c",
   ],
   hdrs = [
+    "include/grpc/impl/codegen/alloc.h",
+    "include/grpc/impl/codegen/atm.h",
+    "include/grpc/impl/codegen/atm_gcc_atomic.h",
+    "include/grpc/impl/codegen/atm_gcc_sync.h",
+    "include/grpc/impl/codegen/atm_win32.h",
+    "include/grpc/impl/codegen/log.h",
+    "include/grpc/impl/codegen/port_platform.h",
+    "include/grpc/impl/codegen/slice.h",
+    "include/grpc/impl/codegen/slice_buffer.h",
+    "include/grpc/impl/codegen/sync.h",
+    "include/grpc/impl/codegen/sync_generic.h",
+    "include/grpc/impl/codegen/sync_posix.h",
+    "include/grpc/impl/codegen/sync_win32.h",
+    "include/grpc/impl/codegen/time.h",
     "include/grpc/support/alloc.h",
     "include/grpc/support/atm.h",
     "include/grpc/support/atm_gcc_atomic.h",
@@ -1231,31 +1335,18 @@
     "include/grpc/support/tls_msvc.h",
     "include/grpc/support/tls_pthread.h",
     "include/grpc/support/useful.h",
-    "include/grpc/impl/codegen/alloc.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_win32.h",
-    "include/grpc/impl/codegen/log.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/slice_buffer.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_win32.h",
-    "include/grpc/impl/codegen/time.h",
-    "src/core/profiling/timers.h",
-    "src/core/support/block_annotate.h",
-    "src/core/support/env.h",
-    "src/core/support/load_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/time_precise.h",
-    "src/core/support/tmpfile.h",
+    "src/core/lib/profiling/timers.h",
+    "src/core/lib/support/backoff.h",
+    "src/core/lib/support/block_annotate.h",
+    "src/core/lib/support/env.h",
+    "src/core/lib/support/load_file.h",
+    "src/core/lib/support/murmur_hash.h",
+    "src/core/lib/support/stack_lockfree.h",
+    "src/core/lib/support/string.h",
+    "src/core/lib/support/string_win32.h",
+    "src/core/lib/support/thd_internal.h",
+    "src/core/lib/support/time_precise.h",
+    "src/core/lib/support/tmpfile.h",
   ],
   includes = [
     "include",
@@ -1266,171 +1357,178 @@
 )
 
 
+
 objc_library(
   name = "grpc_objc",
   srcs = [
-    "src/core/census/grpc_context.c",
-    "src/core/census/grpc_filter.c",
-    "src/core/channel/channel_args.c",
-    "src/core/channel/channel_stack.c",
-    "src/core/channel/client_channel.c",
-    "src/core/channel/client_uchannel.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/subchannel_call_holder.c",
-    "src/core/client_config/client_config.c",
-    "src/core/client_config/connector.c",
-    "src/core/client_config/default_initial_connect_string.c",
-    "src/core/client_config/initial_connect_string.c",
-    "src/core/client_config/lb_policies/load_balancer_api.c",
-    "src/core/client_config/lb_policies/pick_first.c",
-    "src/core/client_config/lb_policies/round_robin.c",
-    "src/core/client_config/lb_policy.c",
-    "src/core/client_config/lb_policy_factory.c",
-    "src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c",
-    "src/core/client_config/subchannel.c",
-    "src/core/client_config/subchannel_factory.c",
-    "src/core/client_config/subchannel_index.c",
-    "src/core/client_config/uri_parser.c",
-    "src/core/compression/compression_algorithm.c",
-    "src/core/compression/message_compress.c",
-    "src/core/debug/trace.c",
-    "src/core/httpcli/format_request.c",
-    "src/core/httpcli/httpcli.c",
-    "src/core/httpcli/parser.c",
-    "src/core/iomgr/closure.c",
-    "src/core/iomgr/endpoint.c",
-    "src/core/iomgr/endpoint_pair_posix.c",
-    "src/core/iomgr/endpoint_pair_windows.c",
-    "src/core/iomgr/exec_ctx.c",
-    "src/core/iomgr/executor.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_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/timer.c",
-    "src/core/iomgr/timer_heap.c",
-    "src/core/iomgr/udp_server.c",
-    "src/core/iomgr/wakeup_fd_eventfd.c",
-    "src/core/iomgr/wakeup_fd_nospecial.c",
-    "src/core/iomgr/wakeup_fd_pipe.c",
-    "src/core/iomgr/wakeup_fd_posix.c",
-    "src/core/iomgr/workqueue_posix.c",
-    "src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c",
-    "src/core/surface/alarm.c",
-    "src/core/surface/api_trace.c",
-    "src/core/surface/byte_buffer.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_connectivity.c",
-    "src/core/surface/channel_create.c",
-    "src/core/surface/channel_ping.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/validate_metadata.c",
-    "src/core/surface/version.c",
-    "src/core/transport/byte_stream.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_encoder.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_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/metadata_batch.c",
-    "src/core/transport/static_metadata.c",
-    "src/core/transport/transport.c",
-    "src/core/transport/transport_op_string.c",
-    "src/core/httpcli/httpcli_security_connector.c",
-    "src/core/security/b64.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/handshake.c",
-    "src/core/security/json_token.c",
-    "src/core/security/jwt_verifier.c",
-    "src/core/security/secure_endpoint.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/context.c",
-    "src/core/census/initialize.c",
-    "src/core/census/mlog.c",
-    "src/core/census/operation.c",
-    "src/core/census/placeholders.c",
-    "src/core/census/tracing.c",
-    "third_party/nanopb/pb_common.c",
-    "third_party/nanopb/pb_decode.c",
-    "third_party/nanopb/pb_encode.c",
+    "src/core/ext/transport/chttp2/client/insecure/channel_create.c",
+    "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c",
+    "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
+    "src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c",
+    "src/core/ext/transport/chttp2/transport/alpn.c",
+    "src/core/ext/transport/chttp2/transport/bin_encoder.c",
+    "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
+    "src/core/ext/transport/chttp2/transport/frame_data.c",
+    "src/core/ext/transport/chttp2/transport/frame_goaway.c",
+    "src/core/ext/transport/chttp2/transport/frame_ping.c",
+    "src/core/ext/transport/chttp2/transport/frame_rst_stream.c",
+    "src/core/ext/transport/chttp2/transport/frame_settings.c",
+    "src/core/ext/transport/chttp2/transport/frame_window_update.c",
+    "src/core/ext/transport/chttp2/transport/hpack_encoder.c",
+    "src/core/ext/transport/chttp2/transport/hpack_parser.c",
+    "src/core/ext/transport/chttp2/transport/hpack_table.c",
+    "src/core/ext/transport/chttp2/transport/huffsyms.c",
+    "src/core/ext/transport/chttp2/transport/incoming_metadata.c",
+    "src/core/ext/transport/chttp2/transport/parsing.c",
+    "src/core/ext/transport/chttp2/transport/status_conversion.c",
+    "src/core/ext/transport/chttp2/transport/stream_lists.c",
+    "src/core/ext/transport/chttp2/transport/stream_map.c",
+    "src/core/ext/transport/chttp2/transport/timeout_encoding.c",
+    "src/core/ext/transport/chttp2/transport/varint.c",
+    "src/core/ext/transport/chttp2/transport/writing.c",
+    "src/core/lib/census/context.c",
+    "src/core/lib/census/grpc_context.c",
+    "src/core/lib/census/grpc_filter.c",
+    "src/core/lib/census/grpc_plugin.c",
+    "src/core/lib/census/initialize.c",
+    "src/core/lib/census/mlog.c",
+    "src/core/lib/census/operation.c",
+    "src/core/lib/census/placeholders.c",
+    "src/core/lib/census/tracing.c",
+    "src/core/lib/channel/channel_args.c",
+    "src/core/lib/channel/channel_stack.c",
+    "src/core/lib/channel/channel_stack_builder.c",
+    "src/core/lib/channel/client_channel.c",
+    "src/core/lib/channel/compress_filter.c",
+    "src/core/lib/channel/connected_channel.c",
+    "src/core/lib/channel/http_client_filter.c",
+    "src/core/lib/channel/http_server_filter.c",
+    "src/core/lib/channel/subchannel_call_holder.c",
+    "src/core/lib/client_config/client_config.c",
+    "src/core/lib/client_config/connector.c",
+    "src/core/lib/client_config/default_initial_connect_string.c",
+    "src/core/lib/client_config/initial_connect_string.c",
+    "src/core/lib/client_config/lb_policies/load_balancer_api.c",
+    "src/core/lib/client_config/lb_policies/pick_first.c",
+    "src/core/lib/client_config/lb_policies/round_robin.c",
+    "src/core/lib/client_config/lb_policy.c",
+    "src/core/lib/client_config/lb_policy_factory.c",
+    "src/core/lib/client_config/lb_policy_registry.c",
+    "src/core/lib/client_config/resolver.c",
+    "src/core/lib/client_config/resolver_factory.c",
+    "src/core/lib/client_config/resolver_registry.c",
+    "src/core/lib/client_config/resolvers/dns_resolver.c",
+    "src/core/lib/client_config/resolvers/sockaddr_resolver.c",
+    "src/core/lib/client_config/subchannel.c",
+    "src/core/lib/client_config/subchannel_factory.c",
+    "src/core/lib/client_config/subchannel_index.c",
+    "src/core/lib/client_config/uri_parser.c",
+    "src/core/lib/compression/compression_algorithm.c",
+    "src/core/lib/compression/message_compress.c",
+    "src/core/lib/debug/trace.c",
+    "src/core/lib/http/format_request.c",
+    "src/core/lib/http/httpcli.c",
+    "src/core/lib/http/httpcli_security_connector.c",
+    "src/core/lib/http/parser.c",
+    "src/core/lib/iomgr/closure.c",
+    "src/core/lib/iomgr/endpoint.c",
+    "src/core/lib/iomgr/endpoint_pair_posix.c",
+    "src/core/lib/iomgr/endpoint_pair_windows.c",
+    "src/core/lib/iomgr/exec_ctx.c",
+    "src/core/lib/iomgr/executor.c",
+    "src/core/lib/iomgr/fd_posix.c",
+    "src/core/lib/iomgr/iocp_windows.c",
+    "src/core/lib/iomgr/iomgr.c",
+    "src/core/lib/iomgr/iomgr_posix.c",
+    "src/core/lib/iomgr/iomgr_windows.c",
+    "src/core/lib/iomgr/pollset_multipoller_with_epoll.c",
+    "src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c",
+    "src/core/lib/iomgr/pollset_posix.c",
+    "src/core/lib/iomgr/pollset_set_posix.c",
+    "src/core/lib/iomgr/pollset_set_windows.c",
+    "src/core/lib/iomgr/pollset_windows.c",
+    "src/core/lib/iomgr/resolve_address_posix.c",
+    "src/core/lib/iomgr/resolve_address_windows.c",
+    "src/core/lib/iomgr/sockaddr_utils.c",
+    "src/core/lib/iomgr/socket_utils_common_posix.c",
+    "src/core/lib/iomgr/socket_utils_linux.c",
+    "src/core/lib/iomgr/socket_utils_posix.c",
+    "src/core/lib/iomgr/socket_windows.c",
+    "src/core/lib/iomgr/tcp_client_posix.c",
+    "src/core/lib/iomgr/tcp_client_windows.c",
+    "src/core/lib/iomgr/tcp_posix.c",
+    "src/core/lib/iomgr/tcp_server_posix.c",
+    "src/core/lib/iomgr/tcp_server_windows.c",
+    "src/core/lib/iomgr/tcp_windows.c",
+    "src/core/lib/iomgr/time_averaged_stats.c",
+    "src/core/lib/iomgr/timer.c",
+    "src/core/lib/iomgr/timer_heap.c",
+    "src/core/lib/iomgr/udp_server.c",
+    "src/core/lib/iomgr/unix_sockets_posix.c",
+    "src/core/lib/iomgr/unix_sockets_posix_noop.c",
+    "src/core/lib/iomgr/wakeup_fd_eventfd.c",
+    "src/core/lib/iomgr/wakeup_fd_nospecial.c",
+    "src/core/lib/iomgr/wakeup_fd_pipe.c",
+    "src/core/lib/iomgr/wakeup_fd_posix.c",
+    "src/core/lib/iomgr/workqueue_posix.c",
+    "src/core/lib/iomgr/workqueue_windows.c",
+    "src/core/lib/json/json.c",
+    "src/core/lib/json/json_reader.c",
+    "src/core/lib/json/json_string.c",
+    "src/core/lib/json/json_writer.c",
+    "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c",
+    "src/core/lib/security/b64.c",
+    "src/core/lib/security/client_auth_filter.c",
+    "src/core/lib/security/credentials.c",
+    "src/core/lib/security/credentials_metadata.c",
+    "src/core/lib/security/credentials_posix.c",
+    "src/core/lib/security/credentials_win32.c",
+    "src/core/lib/security/google_default_credentials.c",
+    "src/core/lib/security/handshake.c",
+    "src/core/lib/security/json_token.c",
+    "src/core/lib/security/jwt_verifier.c",
+    "src/core/lib/security/secure_endpoint.c",
+    "src/core/lib/security/security_connector.c",
+    "src/core/lib/security/security_context.c",
+    "src/core/lib/security/server_auth_filter.c",
+    "src/core/lib/surface/alarm.c",
+    "src/core/lib/surface/api_trace.c",
+    "src/core/lib/surface/byte_buffer.c",
+    "src/core/lib/surface/byte_buffer_reader.c",
+    "src/core/lib/surface/call.c",
+    "src/core/lib/surface/call_details.c",
+    "src/core/lib/surface/call_log_batch.c",
+    "src/core/lib/surface/channel.c",
+    "src/core/lib/surface/channel_connectivity.c",
+    "src/core/lib/surface/channel_init.c",
+    "src/core/lib/surface/channel_ping.c",
+    "src/core/lib/surface/channel_stack_type.c",
+    "src/core/lib/surface/completion_queue.c",
+    "src/core/lib/surface/event_string.c",
+    "src/core/lib/surface/init.c",
+    "src/core/lib/surface/init_secure.c",
+    "src/core/lib/surface/lame_client.c",
+    "src/core/lib/surface/metadata_array.c",
+    "src/core/lib/surface/server.c",
+    "src/core/lib/surface/validate_metadata.c",
+    "src/core/lib/surface/version.c",
+    "src/core/lib/transport/byte_stream.c",
+    "src/core/lib/transport/connectivity_state.c",
+    "src/core/lib/transport/metadata.c",
+    "src/core/lib/transport/metadata_batch.c",
+    "src/core/lib/transport/static_metadata.c",
+    "src/core/lib/transport/transport.c",
+    "src/core/lib/transport/transport_op_string.c",
+    "src/core/lib/tsi/fake_transport_security.c",
+    "src/core/lib/tsi/ssl_transport_security.c",
+    "src/core/lib/tsi/transport_security.c",
   ],
   hdrs = [
+    "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/impl/codegen/byte_buffer.h",
     "include/grpc/impl/codegen/compression_types.h",
@@ -1438,148 +1536,144 @@
     "include/grpc/impl/codegen/grpc_types.h",
     "include/grpc/impl/codegen/propagation_bits.h",
     "include/grpc/impl/codegen/status.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/census/grpc_filter.h",
-    "src/core/channel/channel_args.h",
-    "src/core/channel/channel_stack.h",
-    "src/core/channel/client_channel.h",
-    "src/core/channel/client_uchannel.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/subchannel_call_holder.h",
-    "src/core/client_config/client_config.h",
-    "src/core/client_config/connector.h",
-    "src/core/client_config/initial_connect_string.h",
-    "src/core/client_config/lb_policies/load_balancer_api.h",
-    "src/core/client_config/lb_policies/pick_first.h",
-    "src/core/client_config/lb_policies/round_robin.h",
-    "src/core/client_config/lb_policy.h",
-    "src/core/client_config/lb_policy_factory.h",
-    "src/core/client_config/lb_policy_registry.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/sockaddr_resolver.h",
-    "src/core/client_config/subchannel.h",
-    "src/core/client_config/subchannel_factory.h",
-    "src/core/client_config/subchannel_index.h",
-    "src/core/client_config/uri_parser.h",
-    "src/core/compression/algorithm_metadata.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/parser.h",
-    "src/core/iomgr/closure.h",
-    "src/core/iomgr/endpoint.h",
-    "src/core/iomgr/endpoint_pair.h",
-    "src/core/iomgr/exec_ctx.h",
-    "src/core/iomgr/executor.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_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/timer.h",
-    "src/core/iomgr/timer_heap.h",
-    "src/core/iomgr/udp_server.h",
-    "src/core/iomgr/wakeup_fd_pipe.h",
-    "src/core/iomgr/wakeup_fd_posix.h",
-    "src/core/iomgr/workqueue.h",
-    "src/core/iomgr/workqueue_posix.h",
-    "src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.h",
-    "src/core/statistics/census_interface.h",
-    "src/core/statistics/census_rpc_stats.h",
-    "src/core/surface/api_trace.h",
-    "src/core/surface/call.h",
-    "src/core/surface/call_test_only.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/byte_stream.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_encoder.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_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/metadata_batch.h",
-    "src/core/transport/static_metadata.h",
-    "src/core/transport/transport.h",
-    "src/core/transport/transport_impl.h",
-    "src/core/security/auth_filters.h",
-    "src/core/security/b64.h",
-    "src/core/security/credentials.h",
-    "src/core/security/handshake.h",
-    "src/core/security/json_token.h",
-    "src/core/security/jwt_verifier.h",
-    "src/core/security/secure_endpoint.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/ssl_types.h",
-    "src/core/tsi/transport_security.h",
-    "src/core/tsi/transport_security_interface.h",
-    "src/core/census/aggregation.h",
-    "src/core/census/mlog.h",
-    "src/core/census/rpc_metric_id.h",
-    "third_party/nanopb/pb.h",
-    "third_party/nanopb/pb_common.h",
-    "third_party/nanopb/pb_decode.h",
-    "third_party/nanopb/pb_encode.h",
+    "src/core/ext/transport/chttp2/transport/alpn.h",
+    "src/core/ext/transport/chttp2/transport/bin_encoder.h",
+    "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
+    "src/core/ext/transport/chttp2/transport/frame.h",
+    "src/core/ext/transport/chttp2/transport/frame_data.h",
+    "src/core/ext/transport/chttp2/transport/frame_goaway.h",
+    "src/core/ext/transport/chttp2/transport/frame_ping.h",
+    "src/core/ext/transport/chttp2/transport/frame_rst_stream.h",
+    "src/core/ext/transport/chttp2/transport/frame_settings.h",
+    "src/core/ext/transport/chttp2/transport/frame_window_update.h",
+    "src/core/ext/transport/chttp2/transport/hpack_encoder.h",
+    "src/core/ext/transport/chttp2/transport/hpack_parser.h",
+    "src/core/ext/transport/chttp2/transport/hpack_table.h",
+    "src/core/ext/transport/chttp2/transport/http2_errors.h",
+    "src/core/ext/transport/chttp2/transport/huffsyms.h",
+    "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
+    "src/core/ext/transport/chttp2/transport/internal.h",
+    "src/core/ext/transport/chttp2/transport/status_conversion.h",
+    "src/core/ext/transport/chttp2/transport/stream_map.h",
+    "src/core/ext/transport/chttp2/transport/timeout_encoding.h",
+    "src/core/ext/transport/chttp2/transport/varint.h",
+    "src/core/lib/census/aggregation.h",
+    "src/core/lib/census/grpc_filter.h",
+    "src/core/lib/census/grpc_plugin.h",
+    "src/core/lib/census/mlog.h",
+    "src/core/lib/census/rpc_metric_id.h",
+    "src/core/lib/channel/channel_args.h",
+    "src/core/lib/channel/channel_stack.h",
+    "src/core/lib/channel/channel_stack_builder.h",
+    "src/core/lib/channel/client_channel.h",
+    "src/core/lib/channel/compress_filter.h",
+    "src/core/lib/channel/connected_channel.h",
+    "src/core/lib/channel/context.h",
+    "src/core/lib/channel/http_client_filter.h",
+    "src/core/lib/channel/http_server_filter.h",
+    "src/core/lib/channel/subchannel_call_holder.h",
+    "src/core/lib/client_config/client_config.h",
+    "src/core/lib/client_config/connector.h",
+    "src/core/lib/client_config/initial_connect_string.h",
+    "src/core/lib/client_config/lb_policies/load_balancer_api.h",
+    "src/core/lib/client_config/lb_policies/pick_first.h",
+    "src/core/lib/client_config/lb_policies/round_robin.h",
+    "src/core/lib/client_config/lb_policy.h",
+    "src/core/lib/client_config/lb_policy_factory.h",
+    "src/core/lib/client_config/lb_policy_registry.h",
+    "src/core/lib/client_config/resolver.h",
+    "src/core/lib/client_config/resolver_factory.h",
+    "src/core/lib/client_config/resolver_registry.h",
+    "src/core/lib/client_config/resolvers/dns_resolver.h",
+    "src/core/lib/client_config/resolvers/sockaddr_resolver.h",
+    "src/core/lib/client_config/subchannel.h",
+    "src/core/lib/client_config/subchannel_factory.h",
+    "src/core/lib/client_config/subchannel_index.h",
+    "src/core/lib/client_config/uri_parser.h",
+    "src/core/lib/compression/algorithm_metadata.h",
+    "src/core/lib/compression/message_compress.h",
+    "src/core/lib/debug/trace.h",
+    "src/core/lib/http/format_request.h",
+    "src/core/lib/http/httpcli.h",
+    "src/core/lib/http/parser.h",
+    "src/core/lib/iomgr/closure.h",
+    "src/core/lib/iomgr/endpoint.h",
+    "src/core/lib/iomgr/endpoint_pair.h",
+    "src/core/lib/iomgr/exec_ctx.h",
+    "src/core/lib/iomgr/executor.h",
+    "src/core/lib/iomgr/fd_posix.h",
+    "src/core/lib/iomgr/iocp_windows.h",
+    "src/core/lib/iomgr/iomgr.h",
+    "src/core/lib/iomgr/iomgr_internal.h",
+    "src/core/lib/iomgr/iomgr_posix.h",
+    "src/core/lib/iomgr/pollset.h",
+    "src/core/lib/iomgr/pollset_posix.h",
+    "src/core/lib/iomgr/pollset_set.h",
+    "src/core/lib/iomgr/pollset_set_posix.h",
+    "src/core/lib/iomgr/pollset_set_windows.h",
+    "src/core/lib/iomgr/pollset_windows.h",
+    "src/core/lib/iomgr/resolve_address.h",
+    "src/core/lib/iomgr/sockaddr.h",
+    "src/core/lib/iomgr/sockaddr_posix.h",
+    "src/core/lib/iomgr/sockaddr_utils.h",
+    "src/core/lib/iomgr/sockaddr_win32.h",
+    "src/core/lib/iomgr/socket_utils_posix.h",
+    "src/core/lib/iomgr/socket_windows.h",
+    "src/core/lib/iomgr/tcp_client.h",
+    "src/core/lib/iomgr/tcp_posix.h",
+    "src/core/lib/iomgr/tcp_server.h",
+    "src/core/lib/iomgr/tcp_windows.h",
+    "src/core/lib/iomgr/time_averaged_stats.h",
+    "src/core/lib/iomgr/timer.h",
+    "src/core/lib/iomgr/timer_heap.h",
+    "src/core/lib/iomgr/udp_server.h",
+    "src/core/lib/iomgr/unix_sockets_posix.h",
+    "src/core/lib/iomgr/wakeup_fd_pipe.h",
+    "src/core/lib/iomgr/wakeup_fd_posix.h",
+    "src/core/lib/iomgr/workqueue.h",
+    "src/core/lib/iomgr/workqueue_posix.h",
+    "src/core/lib/iomgr/workqueue_windows.h",
+    "src/core/lib/json/json.h",
+    "src/core/lib/json/json_common.h",
+    "src/core/lib/json/json_reader.h",
+    "src/core/lib/json/json_writer.h",
+    "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h",
+    "src/core/lib/security/auth_filters.h",
+    "src/core/lib/security/b64.h",
+    "src/core/lib/security/credentials.h",
+    "src/core/lib/security/handshake.h",
+    "src/core/lib/security/json_token.h",
+    "src/core/lib/security/jwt_verifier.h",
+    "src/core/lib/security/secure_endpoint.h",
+    "src/core/lib/security/security_connector.h",
+    "src/core/lib/security/security_context.h",
+    "src/core/lib/statistics/census_interface.h",
+    "src/core/lib/statistics/census_rpc_stats.h",
+    "src/core/lib/surface/api_trace.h",
+    "src/core/lib/surface/call.h",
+    "src/core/lib/surface/call_test_only.h",
+    "src/core/lib/surface/channel.h",
+    "src/core/lib/surface/channel_init.h",
+    "src/core/lib/surface/channel_stack_type.h",
+    "src/core/lib/surface/completion_queue.h",
+    "src/core/lib/surface/event_string.h",
+    "src/core/lib/surface/init.h",
+    "src/core/lib/surface/lame_client.h",
+    "src/core/lib/surface/server.h",
+    "src/core/lib/surface/surface_trace.h",
+    "src/core/lib/transport/byte_stream.h",
+    "src/core/lib/transport/connectivity_state.h",
+    "src/core/lib/transport/metadata.h",
+    "src/core/lib/transport/metadata_batch.h",
+    "src/core/lib/transport/static_metadata.h",
+    "src/core/lib/transport/transport.h",
+    "src/core/lib/transport/transport_impl.h",
+    "src/core/lib/tsi/fake_transport_security.h",
+    "src/core/lib/tsi/ssl_transport_security.h",
+    "src/core/lib/tsi/ssl_types.h",
+    "src/core/lib/tsi/transport_security.h",
+    "src/core/lib/tsi/transport_security_interface.h",
   ],
   includes = [
     "include",
@@ -1588,6 +1682,7 @@
   deps = [
     ":gpr_objc",
     "//external:libssl_objc",
+    "//external:nanopb",
   ],
   sdk_dylibs = ["libz"],
 )
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b4e958d..35eb5e6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -59,7 +59,7 @@
 and the Visual Studio project files are building only the C and C++ source code.
 In order to ease the maintenance of these files, we have a
 template system. Please do not contribute manual changes to any of the generated
-files. Instead, modify the template files, or the build.json file, and
+files. Instead, modify the template files, or the build.yaml file, and
 re-generate the project files using the following command:
 
 `./tools/buildgen/generate_projects.sh`
diff --git a/INSTALL.md b/INSTALL.md
index 454a8b7..66e6c33 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -52,6 +52,6 @@
  $ git clone https://github.com/grpc/grpc.git
  $ cd grpc
  $ git submodule update --init
- $ make 
+ $ make
  $ [sudo] make install
 ```
diff --git a/MANIFEST.md b/MANIFEST.md
index b523f8f..77e0140 100644
--- a/MANIFEST.md
+++ b/MANIFEST.md
@@ -1,14 +1,28 @@
 # Top-level Items by language
 
+## Bazel
+* [grpc.bzl](grpc.bzl)
+
 ## Node
 * [binding.gyp](binding.gyp)
+* [package.json](package.json)
 
 ## Objective-C
 * [gRPC.podspec](gRPC.podspec)
 
+## PHP
+* [composer.json](composer.json)
+* [config.m4](config.m4)
+* [package.xml](package.xml)
+
 ## Python
 * [requirements.txt](requirements.txt)
 * [setup.cfg](setup.cfg)
 * [setup.py](setup.py)
 * [tox.ini](tox.ini)
 * [PYTHON-MANIFEST.in](PYTHON-MANIFEST.in)
+
+## Ruby
+* [Gemfile](Gemfile)
+* [grpc.gemspec](grpc.gemspec)
+* [Rakefile](Rakefile)
diff --git a/Makefile b/Makefile
index 371a06b..2286abe 100644
--- a/Makefile
+++ b/Makefile
@@ -95,6 +95,56 @@
 CPPFLAGS_opt = -O2
 DEFINES_opt = NDEBUG
 
+VALID_CONFIG_asan-trace-cmp = 1
+REQUIRE_CUSTOM_LIBRARIES_asan-trace-cmp = 1
+CC_asan-trace-cmp = clang
+CXX_asan-trace-cmp = clang++
+LD_asan-trace-cmp = clang
+LDXX_asan-trace-cmp = clang++
+CPPFLAGS_asan-trace-cmp = -O0 -fsanitize-coverage=edge -fsanitize-coverage=trace-cmp -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
+LDFLAGS_asan-trace-cmp = -fsanitize=address
+DEFINES_asan-trace-cmp += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
+
+VALID_CONFIG_dbg = 1
+CC_dbg = $(DEFAULT_CC)
+CXX_dbg = $(DEFAULT_CXX)
+LD_dbg = $(DEFAULT_CC)
+LDXX_dbg = $(DEFAULT_CXX)
+CPPFLAGS_dbg = -O0
+DEFINES_dbg = _DEBUG DEBUG
+
+VALID_CONFIG_easan = 1
+REQUIRE_CUSTOM_LIBRARIES_easan = 1
+CC_easan = clang
+CXX_easan = clang++
+LD_easan = clang
+LDXX_easan = clang++
+CPPFLAGS_easan = -O0 -fsanitize-coverage=edge -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
+LDFLAGS_easan = -fsanitize=address
+DEFINES_easan = _DEBUG DEBUG GRPC_EXECUTION_CONTEXT_SANITIZER
+DEFINES_easan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
+
+VALID_CONFIG_asan = 1
+REQUIRE_CUSTOM_LIBRARIES_asan = 1
+CC_asan = clang
+CXX_asan = clang++
+LD_asan = clang
+LDXX_asan = clang++
+CPPFLAGS_asan = -O0 -fsanitize-coverage=edge -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
+LDFLAGS_asan = -fsanitize=address
+DEFINES_asan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
+
+VALID_CONFIG_msan = 1
+REQUIRE_CUSTOM_LIBRARIES_msan = 1
+CC_msan = clang
+CXX_msan = clang++
+LD_msan = clang
+LDXX_msan = clang++
+CPPFLAGS_msan = -O0 -fsanitize-coverage=edge -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
+LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
+DEFINES_msan = NDEBUG
+DEFINES_msan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=4
+
 VALID_CONFIG_basicprof = 1
 CC_basicprof = $(DEFAULT_CC)
 CXX_basicprof = $(DEFAULT_CXX)
@@ -119,28 +169,38 @@
 CXX_asan-noleaks = clang++
 LD_asan-noleaks = clang
 LDXX_asan-noleaks = clang++
-CPPFLAGS_asan-noleaks = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
+CPPFLAGS_asan-noleaks = -O0 -fsanitize-coverage=edge -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
 LDFLAGS_asan-noleaks = -fsanitize=address
 DEFINES_asan-noleaks += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
 
+VALID_CONFIG_edbg = 1
+CC_edbg = $(DEFAULT_CC)
+CXX_edbg = $(DEFAULT_CXX)
+LD_edbg = $(DEFAULT_CC)
+LDXX_edbg = $(DEFAULT_CXX)
+CPPFLAGS_edbg = -O0
+DEFINES_edbg = _DEBUG DEBUG GRPC_EXECUTION_CONTEXT_SANITIZER
+
 VALID_CONFIG_ubsan = 1
 REQUIRE_CUSTOM_LIBRARIES_ubsan = 1
 CC_ubsan = clang
 CXX_ubsan = clang++
 LD_ubsan = clang
 LDXX_ubsan = clang++
-CPPFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
+CPPFLAGS_ubsan = -O1 -fsanitize-coverage=edge -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
 LDFLAGS_ubsan = -fsanitize=undefined
 DEFINES_ubsan = NDEBUG
 DEFINES_ubsan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=1.5
 
-VALID_CONFIG_dbg = 1
-CC_dbg = $(DEFAULT_CC)
-CXX_dbg = $(DEFAULT_CXX)
-LD_dbg = $(DEFAULT_CC)
-LDXX_dbg = $(DEFAULT_CXX)
-CPPFLAGS_dbg = -O0
-DEFINES_dbg = _DEBUG DEBUG
+VALID_CONFIG_tsan = 1
+REQUIRE_CUSTOM_LIBRARIES_tsan = 1
+CC_tsan = clang
+CXX_tsan = clang++
+LD_tsan = clang
+LDXX_tsan = clang++
+CPPFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
+LDFLAGS_tsan = -fsanitize=thread
+DEFINES_tsan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=5
 
 VALID_CONFIG_stapprof = 1
 CC_stapprof = $(DEFAULT_CC)
@@ -150,14 +210,14 @@
 CPPFLAGS_stapprof = -O2 -DGRPC_STAP_PROFILER
 DEFINES_stapprof = NDEBUG
 
-VALID_CONFIG_gcov = 1
-CC_gcov = gcc
-CXX_gcov = g++
-LD_gcov = gcc
-LDXX_gcov = g++
-CPPFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
-LDFLAGS_gcov = -fprofile-arcs -ftest-coverage -rdynamic
-DEFINES_gcov = _DEBUG DEBUG GPR_GCOV
+VALID_CONFIG_mutrace = 1
+CC_mutrace = $(DEFAULT_CC)
+CXX_mutrace = $(DEFAULT_CXX)
+LD_mutrace = $(DEFAULT_CC)
+LDXX_mutrace = $(DEFAULT_CXX)
+CPPFLAGS_mutrace = -O0
+LDFLAGS_mutrace = -rdynamic
+DEFINES_mutrace = _DEBUG DEBUG
 
 VALID_CONFIG_memcheck = 1
 CC_memcheck = $(DEFAULT_CC)
@@ -169,45 +229,25 @@
 DEFINES_memcheck = _DEBUG DEBUG
 DEFINES_memcheck += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=10
 
-VALID_CONFIG_asan = 1
-REQUIRE_CUSTOM_LIBRARIES_asan = 1
-CC_asan = clang
-CXX_asan = clang++
-LD_asan = clang
-LDXX_asan = clang++
-CPPFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
-LDFLAGS_asan = -fsanitize=address
-DEFINES_asan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
+VALID_CONFIG_etsan = 1
+REQUIRE_CUSTOM_LIBRARIES_etsan = 1
+CC_etsan = clang
+CXX_etsan = clang++
+LD_etsan = clang
+LDXX_etsan = clang++
+CPPFLAGS_etsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
+LDFLAGS_etsan = -fsanitize=thread
+DEFINES_etsan = _DEBUG DEBUG GRPC_EXECUTION_CONTEXT_SANITIZER
+DEFINES_etsan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=5
 
-VALID_CONFIG_tsan = 1
-REQUIRE_CUSTOM_LIBRARIES_tsan = 1
-CC_tsan = clang
-CXX_tsan = clang++
-LD_tsan = clang
-LDXX_tsan = clang++
-CPPFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
-LDFLAGS_tsan = -fsanitize=thread -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
-DEFINES_tsan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=5
-
-VALID_CONFIG_msan = 1
-REQUIRE_CUSTOM_LIBRARIES_msan = 1
-CC_msan = clang
-CXX_msan = clang++
-LD_msan = clang
-LDXX_msan = clang++
-CPPFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
-LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
-DEFINES_msan = NDEBUG
-DEFINES_msan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=4
-
-VALID_CONFIG_mutrace = 1
-CC_mutrace = $(DEFAULT_CC)
-CXX_mutrace = $(DEFAULT_CXX)
-LD_mutrace = $(DEFAULT_CC)
-LDXX_mutrace = $(DEFAULT_CXX)
-CPPFLAGS_mutrace = -O0
-LDFLAGS_mutrace = -rdynamic
-DEFINES_mutrace = _DEBUG DEBUG
+VALID_CONFIG_gcov = 1
+CC_gcov = gcc
+CXX_gcov = g++
+LD_gcov = gcc
+LDXX_gcov = g++
+CPPFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
+LDFLAGS_gcov = -fprofile-arcs -ftest-coverage -rdynamic
+DEFINES_gcov = _DEBUG DEBUG GPR_GCOV
 
 
 
@@ -367,7 +407,7 @@
 Q = @
 endif
 
-VERSION = 0.13.1-pre1
+VERSION = 0.14.0-dev
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -849,6 +889,8 @@
 chttp2_stream_map_test: $(BINDIR)/$(CONFIG)/chttp2_stream_map_test
 chttp2_varint_test: $(BINDIR)/$(CONFIG)/chttp2_varint_test
 compression_test: $(BINDIR)/$(CONFIG)/compression_test
+concurrent_connectivity_test: $(BINDIR)/$(CONFIG)/concurrent_connectivity_test
+dns_resolver_connectivity_test: $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test
 dns_resolver_test: $(BINDIR)/$(CONFIG)/dns_resolver_test
 dualstack_socket_test: $(BINDIR)/$(CONFIG)/dualstack_socket_test
 endpoint_pair_test: $(BINDIR)/$(CONFIG)/endpoint_pair_test
@@ -861,6 +903,7 @@
 gen_hpack_tables: $(BINDIR)/$(CONFIG)/gen_hpack_tables
 gen_legal_metadata_characters: $(BINDIR)/$(CONFIG)/gen_legal_metadata_characters
 gpr_avl_test: $(BINDIR)/$(CONFIG)/gpr_avl_test
+gpr_backoff_test: $(BINDIR)/$(CONFIG)/gpr_backoff_test
 gpr_cmdline_test: $(BINDIR)/$(CONFIG)/gpr_cmdline_test
 gpr_cpu_test: $(BINDIR)/$(CONFIG)/gpr_cpu_test
 gpr_env_test: $(BINDIR)/$(CONFIG)/gpr_env_test
@@ -892,14 +935,17 @@
 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_verify_jwt: $(BINDIR)/$(CONFIG)/grpc_verify_jwt
+hpack_parser_fuzzer_test: $(BINDIR)/$(CONFIG)/hpack_parser_fuzzer_test
 hpack_parser_test: $(BINDIR)/$(CONFIG)/hpack_parser_test
 hpack_table_test: $(BINDIR)/$(CONFIG)/hpack_table_test
+http_fuzzer_test: $(BINDIR)/$(CONFIG)/http_fuzzer_test
+http_parser_test: $(BINDIR)/$(CONFIG)/http_parser_test
 httpcli_format_request_test: $(BINDIR)/$(CONFIG)/httpcli_format_request_test
-httpcli_parser_test: $(BINDIR)/$(CONFIG)/httpcli_parser_test
 httpcli_test: $(BINDIR)/$(CONFIG)/httpcli_test
 httpscli_test: $(BINDIR)/$(CONFIG)/httpscli_test
 init_test: $(BINDIR)/$(CONFIG)/init_test
 invalid_call_argument_test: $(BINDIR)/$(CONFIG)/invalid_call_argument_test
+json_fuzzer_test: $(BINDIR)/$(CONFIG)/json_fuzzer_test
 json_rewrite: $(BINDIR)/$(CONFIG)/json_rewrite
 json_rewrite_test: $(BINDIR)/$(CONFIG)/json_rewrite_test
 json_stream_error_test: $(BINDIR)/$(CONFIG)/json_stream_error_test
@@ -933,6 +979,7 @@
 transport_metadata_test: $(BINDIR)/$(CONFIG)/transport_metadata_test
 transport_security_test: $(BINDIR)/$(CONFIG)/transport_security_test
 udp_server_test: $(BINDIR)/$(CONFIG)/udp_server_test
+uri_fuzzer_test: $(BINDIR)/$(CONFIG)/uri_fuzzer_test
 uri_parser_test: $(BINDIR)/$(CONFIG)/uri_parser_test
 workqueue_test: $(BINDIR)/$(CONFIG)/workqueue_test
 alarm_cpp_test: $(BINDIR)/$(CONFIG)/alarm_cpp_test
@@ -944,6 +991,7 @@
 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
+codegen_test: $(BINDIR)/$(CONFIG)/codegen_test
 credentials_test: $(BINDIR)/$(CONFIG)/credentials_test
 cxx_byte_buffer_test: $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test
 cxx_slice_test: $(BINDIR)/$(CONFIG)/cxx_slice_test
@@ -986,6 +1034,7 @@
 zookeeper_test: $(BINDIR)/$(CONFIG)/zookeeper_test
 public_headers_must_be_c89: $(BINDIR)/$(CONFIG)/public_headers_must_be_c89
 boringssl_aes_test: $(BINDIR)/$(CONFIG)/boringssl_aes_test
+boringssl_asn1_test: $(BINDIR)/$(CONFIG)/boringssl_asn1_test
 boringssl_base64_test: $(BINDIR)/$(CONFIG)/boringssl_base64_test
 boringssl_bio_test: $(BINDIR)/$(CONFIG)/boringssl_bio_test
 boringssl_bn_test: $(BINDIR)/$(CONFIG)/boringssl_bn_test
@@ -1040,6 +1089,7 @@
 h2_full+pipe_test: $(BINDIR)/$(CONFIG)/h2_full+pipe_test
 h2_full+poll_test: $(BINDIR)/$(CONFIG)/h2_full+poll_test
 h2_full+poll+pipe_test: $(BINDIR)/$(CONFIG)/h2_full+poll+pipe_test
+h2_full+trace_test: $(BINDIR)/$(CONFIG)/h2_full+trace_test
 h2_oauth2_test: $(BINDIR)/$(CONFIG)/h2_oauth2_test
 h2_proxy_test: $(BINDIR)/$(CONFIG)/h2_proxy_test
 h2_sockpair_test: $(BINDIR)/$(CONFIG)/h2_sockpair_test
@@ -1048,7 +1098,6 @@
 h2_ssl_test: $(BINDIR)/$(CONFIG)/h2_ssl_test
 h2_ssl+poll_test: $(BINDIR)/$(CONFIG)/h2_ssl+poll_test
 h2_ssl_proxy_test: $(BINDIR)/$(CONFIG)/h2_ssl_proxy_test
-h2_uchannel_test: $(BINDIR)/$(CONFIG)/h2_uchannel_test
 h2_uds_test: $(BINDIR)/$(CONFIG)/h2_uds_test
 h2_uds+poll_test: $(BINDIR)/$(CONFIG)/h2_uds+poll_test
 h2_census_nosec_test: $(BINDIR)/$(CONFIG)/h2_census_nosec_test
@@ -1057,11 +1106,11 @@
 h2_full+pipe_nosec_test: $(BINDIR)/$(CONFIG)/h2_full+pipe_nosec_test
 h2_full+poll_nosec_test: $(BINDIR)/$(CONFIG)/h2_full+poll_nosec_test
 h2_full+poll+pipe_nosec_test: $(BINDIR)/$(CONFIG)/h2_full+poll+pipe_nosec_test
+h2_full+trace_nosec_test: $(BINDIR)/$(CONFIG)/h2_full+trace_nosec_test
 h2_proxy_nosec_test: $(BINDIR)/$(CONFIG)/h2_proxy_nosec_test
 h2_sockpair_nosec_test: $(BINDIR)/$(CONFIG)/h2_sockpair_nosec_test
 h2_sockpair+trace_nosec_test: $(BINDIR)/$(CONFIG)/h2_sockpair+trace_nosec_test
 h2_sockpair_1byte_nosec_test: $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_nosec_test
-h2_uchannel_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_nosec_test
 h2_uds_nosec_test: $(BINDIR)/$(CONFIG)/h2_uds_nosec_test
 h2_uds+poll_nosec_test: $(BINDIR)/$(CONFIG)/h2_uds+poll_nosec_test
 
@@ -1094,13 +1143,13 @@
 static_c: pc_c pc_c_unsecure cache.mk pc_c_zookeeper $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a static_zookeeper_libs
 
 
-static_cxx: pc_cxx pc_cxx_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
+static_cxx: pc_cxx pc_cxx_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
 
 shared: shared_c shared_cxx
 
 shared_c: pc_c pc_c_unsecure cache.mk pc_c_zookeeper $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) shared_zookeeper_libs
 
-shared_cxx: pc_cxx pc_cxx_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)
+shared_cxx: pc_cxx pc_cxx_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)
 
 shared_csharp: shared_c  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT)
 ifeq ($(HAS_ZOOKEEPER),true)
@@ -1120,7 +1169,7 @@
 
 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)/libreconnect_server.a $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libz.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a
+privatelibs_c:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libz.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a
 pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc
 
 pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc
@@ -1135,7 +1184,7 @@
 
 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 $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a
+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 $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a
 
 ifeq ($(HAS_ZOOKEEPER),true)
 privatelibs_zookeeper: 
@@ -1159,6 +1208,8 @@
   $(BINDIR)/$(CONFIG)/chttp2_stream_map_test \
   $(BINDIR)/$(CONFIG)/chttp2_varint_test \
   $(BINDIR)/$(CONFIG)/compression_test \
+  $(BINDIR)/$(CONFIG)/concurrent_connectivity_test \
+  $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test \
   $(BINDIR)/$(CONFIG)/dns_resolver_test \
   $(BINDIR)/$(CONFIG)/dualstack_socket_test \
   $(BINDIR)/$(CONFIG)/endpoint_pair_test \
@@ -1169,6 +1220,7 @@
   $(BINDIR)/$(CONFIG)/fling_stream_test \
   $(BINDIR)/$(CONFIG)/fling_test \
   $(BINDIR)/$(CONFIG)/gpr_avl_test \
+  $(BINDIR)/$(CONFIG)/gpr_backoff_test \
   $(BINDIR)/$(CONFIG)/gpr_cmdline_test \
   $(BINDIR)/$(CONFIG)/gpr_cpu_test \
   $(BINDIR)/$(CONFIG)/gpr_env_test \
@@ -1198,8 +1250,8 @@
   $(BINDIR)/$(CONFIG)/grpc_security_connector_test \
   $(BINDIR)/$(CONFIG)/hpack_parser_test \
   $(BINDIR)/$(CONFIG)/hpack_table_test \
+  $(BINDIR)/$(CONFIG)/http_parser_test \
   $(BINDIR)/$(CONFIG)/httpcli_format_request_test \
-  $(BINDIR)/$(CONFIG)/httpcli_parser_test \
   $(BINDIR)/$(CONFIG)/httpcli_test \
   $(BINDIR)/$(CONFIG)/httpscli_test \
   $(BINDIR)/$(CONFIG)/init_test \
@@ -1258,6 +1310,7 @@
   $(BINDIR)/$(CONFIG)/h2_full+pipe_test \
   $(BINDIR)/$(CONFIG)/h2_full+poll_test \
   $(BINDIR)/$(CONFIG)/h2_full+poll+pipe_test \
+  $(BINDIR)/$(CONFIG)/h2_full+trace_test \
   $(BINDIR)/$(CONFIG)/h2_oauth2_test \
   $(BINDIR)/$(CONFIG)/h2_proxy_test \
   $(BINDIR)/$(CONFIG)/h2_sockpair_test \
@@ -1266,7 +1319,6 @@
   $(BINDIR)/$(CONFIG)/h2_ssl_test \
   $(BINDIR)/$(CONFIG)/h2_ssl+poll_test \
   $(BINDIR)/$(CONFIG)/h2_ssl_proxy_test \
-  $(BINDIR)/$(CONFIG)/h2_uchannel_test \
   $(BINDIR)/$(CONFIG)/h2_uds_test \
   $(BINDIR)/$(CONFIG)/h2_uds+poll_test \
   $(BINDIR)/$(CONFIG)/h2_census_nosec_test \
@@ -1275,11 +1327,11 @@
   $(BINDIR)/$(CONFIG)/h2_full+pipe_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_full+poll_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_full+poll+pipe_nosec_test \
+  $(BINDIR)/$(CONFIG)/h2_full+trace_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_proxy_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_sockpair_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_sockpair+trace_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_nosec_test \
-  $(BINDIR)/$(CONFIG)/h2_uchannel_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_uds_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_uds+poll_nosec_test \
 
@@ -1294,6 +1346,7 @@
   $(BINDIR)/$(CONFIG)/cli_call_test \
   $(BINDIR)/$(CONFIG)/client_crash_test \
   $(BINDIR)/$(CONFIG)/client_crash_test_server \
+  $(BINDIR)/$(CONFIG)/codegen_test \
   $(BINDIR)/$(CONFIG)/credentials_test \
   $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test \
   $(BINDIR)/$(CONFIG)/cxx_slice_test \
@@ -1327,6 +1380,7 @@
   $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test \
   $(BINDIR)/$(CONFIG)/thread_stress_test \
   $(BINDIR)/$(CONFIG)/boringssl_aes_test \
+  $(BINDIR)/$(CONFIG)/boringssl_asn1_test \
   $(BINDIR)/$(CONFIG)/boringssl_base64_test \
   $(BINDIR)/$(CONFIG)/boringssl_bio_test \
   $(BINDIR)/$(CONFIG)/boringssl_bn_test \
@@ -1402,6 +1456,10 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_varint_test || ( echo test chttp2_varint_test failed ; exit 1 )
 	$(E) "[RUN]     Testing compression_test"
 	$(Q) $(BINDIR)/$(CONFIG)/compression_test || ( echo test compression_test failed ; exit 1 )
+	$(E) "[RUN]     Testing concurrent_connectivity_test"
+	$(Q) $(BINDIR)/$(CONFIG)/concurrent_connectivity_test || ( echo test concurrent_connectivity_test failed ; exit 1 )
+	$(E) "[RUN]     Testing dns_resolver_connectivity_test"
+	$(Q) $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test || ( echo test dns_resolver_connectivity_test failed ; exit 1 )
 	$(E) "[RUN]     Testing dns_resolver_test"
 	$(Q) $(BINDIR)/$(CONFIG)/dns_resolver_test || ( echo test dns_resolver_test failed ; exit 1 )
 	$(E) "[RUN]     Testing dualstack_socket_test"
@@ -1418,6 +1476,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/fling_test || ( echo test fling_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_avl_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_avl_test || ( echo test gpr_avl_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_backoff_test"
+	$(Q) $(BINDIR)/$(CONFIG)/gpr_backoff_test || ( echo test gpr_backoff_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_cmdline_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_cmdline_test || ( echo test gpr_cmdline_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_cpu_test"
@@ -1476,10 +1536,10 @@
 	$(Q) $(BINDIR)/$(CONFIG)/hpack_parser_test || ( echo test hpack_parser_test failed ; exit 1 )
 	$(E) "[RUN]     Testing hpack_table_test"
 	$(Q) $(BINDIR)/$(CONFIG)/hpack_table_test || ( echo test hpack_table_test failed ; exit 1 )
+	$(E) "[RUN]     Testing http_parser_test"
+	$(Q) $(BINDIR)/$(CONFIG)/http_parser_test || ( echo test http_parser_test failed ; exit 1 )
 	$(E) "[RUN]     Testing httpcli_format_request_test"
 	$(Q) $(BINDIR)/$(CONFIG)/httpcli_format_request_test || ( echo test httpcli_format_request_test failed ; exit 1 )
-	$(E) "[RUN]     Testing httpcli_parser_test"
-	$(Q) $(BINDIR)/$(CONFIG)/httpcli_parser_test || ( echo test httpcli_parser_test failed ; exit 1 )
 	$(E) "[RUN]     Testing httpcli_test"
 	$(Q) $(BINDIR)/$(CONFIG)/httpcli_test || ( echo test httpcli_test failed ; exit 1 )
 	$(E) "[RUN]     Testing httpscli_test"
@@ -1496,12 +1556,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/json_test || ( echo test json_test failed ; exit 1 )
 	$(E) "[RUN]     Testing lame_client_test"
 	$(Q) $(BINDIR)/$(CONFIG)/lame_client_test || ( echo test lame_client_test failed ; exit 1 )
-	$(E) "[RUN]     Testing lb_policies_test"
-	$(Q) $(BINDIR)/$(CONFIG)/lb_policies_test || ( echo test lb_policies_test failed ; exit 1 )
 	$(E) "[RUN]     Testing message_compress_test"
 	$(Q) $(BINDIR)/$(CONFIG)/message_compress_test || ( echo test message_compress_test failed ; exit 1 )
-	$(E) "[RUN]     Testing mlog_test"
-	$(Q) $(BINDIR)/$(CONFIG)/mlog_test || ( echo test mlog_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"
@@ -1579,6 +1635,10 @@
 
 
 flaky_test_c: buildtests_c
+	$(E) "[RUN]     Testing lb_policies_test"
+	$(Q) $(BINDIR)/$(CONFIG)/lb_policies_test || ( echo test lb_policies_test failed ; exit 1 )
+	$(E) "[RUN]     Testing mlog_test"
+	$(Q) $(BINDIR)/$(CONFIG)/mlog_test || ( echo test mlog_test failed ; exit 1 )
 
 
 test_cxx: test_zookeeper buildtests_cxx
@@ -1598,6 +1658,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/cli_call_test || ( echo test cli_call_test failed ; exit 1 )
 	$(E) "[RUN]     Testing client_crash_test"
 	$(Q) $(BINDIR)/$(CONFIG)/client_crash_test || ( echo test client_crash_test failed ; exit 1 )
+	$(E) "[RUN]     Testing codegen_test"
+	$(Q) $(BINDIR)/$(CONFIG)/codegen_test || ( echo test codegen_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"
@@ -1706,6 +1768,8 @@
 ifeq ($(CONFIG),opt)
 	$(E) "[STRIP]   Stripping libgrpc++.a"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc++.a
+	$(E) "[STRIP]   Stripping libgrpc++_codegen_lib.a"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a
 	$(E) "[STRIP]   Stripping libgrpc++_unsecure.a"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
 endif
@@ -1728,6 +1792,8 @@
 ifeq ($(CONFIG),opt)
 	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT)"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT)
 	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)"
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)
 endif
@@ -2039,6 +2105,9 @@
 	$(E) "[INSTALL] Installing libgrpc++.a"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(prefix)/lib/libgrpc++.a
+	$(E) "[INSTALL] Installing libgrpc++_codegen_lib.a"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a $(prefix)/lib/libgrpc++_codegen_lib.a
 	$(E) "[INSTALL] Installing libgrpc++_unsecure.a"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(prefix)/lib/libgrpc++_unsecure.a
@@ -2101,6 +2170,15 @@
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++.so.0
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++.so
 endif
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT)"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT)
+ifeq ($(SYSTEM),MINGW32)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib-imp.a $(prefix)/lib/libgrpc++_codegen_lib-imp.a
+else ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++_codegen_lib.so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++_codegen_lib.so
+endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)
@@ -2204,51 +2282,66 @@
 
 
 LIBGPR_SRC = \
-    src/core/profiling/basic_timers.c \
-    src/core/profiling/stap_timers.c \
-    src/core/support/alloc.c \
-    src/core/support/avl.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/histogram.c \
-    src/core/support/host_port.c \
-    src/core/support/load_file.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/subprocess_windows.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_precise.c \
-    src/core/support/time_win32.c \
-    src/core/support/tls_pthread.c \
-    src/core/support/tmpfile_posix.c \
-    src/core/support/tmpfile_win32.c \
-    src/core/support/wrap_memcpy.c \
+    src/core/lib/profiling/basic_timers.c \
+    src/core/lib/profiling/stap_timers.c \
+    src/core/lib/support/alloc.c \
+    src/core/lib/support/avl.c \
+    src/core/lib/support/backoff.c \
+    src/core/lib/support/cmdline.c \
+    src/core/lib/support/cpu_iphone.c \
+    src/core/lib/support/cpu_linux.c \
+    src/core/lib/support/cpu_posix.c \
+    src/core/lib/support/cpu_windows.c \
+    src/core/lib/support/env_linux.c \
+    src/core/lib/support/env_posix.c \
+    src/core/lib/support/env_win32.c \
+    src/core/lib/support/histogram.c \
+    src/core/lib/support/host_port.c \
+    src/core/lib/support/load_file.c \
+    src/core/lib/support/log.c \
+    src/core/lib/support/log_android.c \
+    src/core/lib/support/log_linux.c \
+    src/core/lib/support/log_posix.c \
+    src/core/lib/support/log_win32.c \
+    src/core/lib/support/murmur_hash.c \
+    src/core/lib/support/slice.c \
+    src/core/lib/support/slice_buffer.c \
+    src/core/lib/support/stack_lockfree.c \
+    src/core/lib/support/string.c \
+    src/core/lib/support/string_posix.c \
+    src/core/lib/support/string_win32.c \
+    src/core/lib/support/subprocess_posix.c \
+    src/core/lib/support/subprocess_windows.c \
+    src/core/lib/support/sync.c \
+    src/core/lib/support/sync_posix.c \
+    src/core/lib/support/sync_win32.c \
+    src/core/lib/support/thd.c \
+    src/core/lib/support/thd_posix.c \
+    src/core/lib/support/thd_win32.c \
+    src/core/lib/support/time.c \
+    src/core/lib/support/time_posix.c \
+    src/core/lib/support/time_precise.c \
+    src/core/lib/support/time_win32.c \
+    src/core/lib/support/tls_pthread.c \
+    src/core/lib/support/tmpfile_posix.c \
+    src/core/lib/support/tmpfile_win32.c \
+    src/core/lib/support/wrap_memcpy.c \
 
 PUBLIC_HEADERS_C += \
+    include/grpc/impl/codegen/alloc.h \
+    include/grpc/impl/codegen/atm.h \
+    include/grpc/impl/codegen/atm_gcc_atomic.h \
+    include/grpc/impl/codegen/atm_gcc_sync.h \
+    include/grpc/impl/codegen/atm_win32.h \
+    include/grpc/impl/codegen/log.h \
+    include/grpc/impl/codegen/port_platform.h \
+    include/grpc/impl/codegen/slice.h \
+    include/grpc/impl/codegen/slice_buffer.h \
+    include/grpc/impl/codegen/sync.h \
+    include/grpc/impl/codegen/sync_generic.h \
+    include/grpc/impl/codegen/sync_posix.h \
+    include/grpc/impl/codegen/sync_win32.h \
+    include/grpc/impl/codegen/time.h \
     include/grpc/support/alloc.h \
     include/grpc/support/atm.h \
     include/grpc/support/atm_gcc_atomic.h \
@@ -2277,20 +2370,6 @@
     include/grpc/support/tls_msvc.h \
     include/grpc/support/tls_pthread.h \
     include/grpc/support/useful.h \
-    include/grpc/impl/codegen/alloc.h \
-    include/grpc/impl/codegen/atm.h \
-    include/grpc/impl/codegen/atm_gcc_atomic.h \
-    include/grpc/impl/codegen/atm_gcc_sync.h \
-    include/grpc/impl/codegen/atm_win32.h \
-    include/grpc/impl/codegen/log.h \
-    include/grpc/impl/codegen/port_platform.h \
-    include/grpc/impl/codegen/slice.h \
-    include/grpc/impl/codegen/slice_buffer.h \
-    include/grpc/impl/codegen/sync.h \
-    include/grpc/impl/codegen/sync_generic.h \
-    include/grpc/impl/codegen/sync_posix.h \
-    include/grpc/impl/codegen/sync_win32.h \
-    include/grpc/impl/codegen/time.h \
 
 LIBGPR_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGPR_SRC))))
 
@@ -2332,6 +2411,7 @@
 LIBGPR_TEST_UTIL_SRC = \
     test/core/util/test_config.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBGPR_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGPR_TEST_UTIL_SRC))))
 
@@ -2354,168 +2434,177 @@
 
 
 LIBGRPC_SRC = \
-    src/core/census/grpc_context.c \
-    src/core/census/grpc_filter.c \
-    src/core/channel/channel_args.c \
-    src/core/channel/channel_stack.c \
-    src/core/channel/client_channel.c \
-    src/core/channel/client_uchannel.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/subchannel_call_holder.c \
-    src/core/client_config/client_config.c \
-    src/core/client_config/connector.c \
-    src/core/client_config/default_initial_connect_string.c \
-    src/core/client_config/initial_connect_string.c \
-    src/core/client_config/lb_policies/load_balancer_api.c \
-    src/core/client_config/lb_policies/pick_first.c \
-    src/core/client_config/lb_policies/round_robin.c \
-    src/core/client_config/lb_policy.c \
-    src/core/client_config/lb_policy_factory.c \
-    src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c \
-    src/core/client_config/subchannel.c \
-    src/core/client_config/subchannel_factory.c \
-    src/core/client_config/subchannel_index.c \
-    src/core/client_config/uri_parser.c \
-    src/core/compression/compression_algorithm.c \
-    src/core/compression/message_compress.c \
-    src/core/debug/trace.c \
-    src/core/httpcli/format_request.c \
-    src/core/httpcli/httpcli.c \
-    src/core/httpcli/parser.c \
-    src/core/iomgr/closure.c \
-    src/core/iomgr/endpoint.c \
-    src/core/iomgr/endpoint_pair_posix.c \
-    src/core/iomgr/endpoint_pair_windows.c \
-    src/core/iomgr/exec_ctx.c \
-    src/core/iomgr/executor.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_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/timer.c \
-    src/core/iomgr/timer_heap.c \
-    src/core/iomgr/udp_server.c \
-    src/core/iomgr/wakeup_fd_eventfd.c \
-    src/core/iomgr/wakeup_fd_nospecial.c \
-    src/core/iomgr/wakeup_fd_pipe.c \
-    src/core/iomgr/wakeup_fd_posix.c \
-    src/core/iomgr/workqueue_posix.c \
-    src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c \
-    src/core/surface/alarm.c \
-    src/core/surface/api_trace.c \
-    src/core/surface/byte_buffer.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_connectivity.c \
-    src/core/surface/channel_create.c \
-    src/core/surface/channel_ping.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/validate_metadata.c \
-    src/core/surface/version.c \
-    src/core/transport/byte_stream.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_encoder.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_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/metadata_batch.c \
-    src/core/transport/static_metadata.c \
-    src/core/transport/transport.c \
-    src/core/transport/transport_op_string.c \
-    src/core/httpcli/httpcli_security_connector.c \
-    src/core/security/b64.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/handshake.c \
-    src/core/security/json_token.c \
-    src/core/security/jwt_verifier.c \
-    src/core/security/secure_endpoint.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/context.c \
-    src/core/census/initialize.c \
-    src/core/census/mlog.c \
-    src/core/census/operation.c \
-    src/core/census/placeholders.c \
-    src/core/census/tracing.c \
+    src/core/ext/transport/chttp2/client/insecure/channel_create.c \
+    src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
+    src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
+    src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c \
+    src/core/ext/transport/chttp2/transport/alpn.c \
+    src/core/ext/transport/chttp2/transport/bin_encoder.c \
+    src/core/ext/transport/chttp2/transport/chttp2_transport.c \
+    src/core/ext/transport/chttp2/transport/frame_data.c \
+    src/core/ext/transport/chttp2/transport/frame_goaway.c \
+    src/core/ext/transport/chttp2/transport/frame_ping.c \
+    src/core/ext/transport/chttp2/transport/frame_rst_stream.c \
+    src/core/ext/transport/chttp2/transport/frame_settings.c \
+    src/core/ext/transport/chttp2/transport/frame_window_update.c \
+    src/core/ext/transport/chttp2/transport/hpack_encoder.c \
+    src/core/ext/transport/chttp2/transport/hpack_parser.c \
+    src/core/ext/transport/chttp2/transport/hpack_table.c \
+    src/core/ext/transport/chttp2/transport/huffsyms.c \
+    src/core/ext/transport/chttp2/transport/incoming_metadata.c \
+    src/core/ext/transport/chttp2/transport/parsing.c \
+    src/core/ext/transport/chttp2/transport/status_conversion.c \
+    src/core/ext/transport/chttp2/transport/stream_lists.c \
+    src/core/ext/transport/chttp2/transport/stream_map.c \
+    src/core/ext/transport/chttp2/transport/timeout_encoding.c \
+    src/core/ext/transport/chttp2/transport/varint.c \
+    src/core/ext/transport/chttp2/transport/writing.c \
+    src/core/lib/census/context.c \
+    src/core/lib/census/grpc_context.c \
+    src/core/lib/census/grpc_filter.c \
+    src/core/lib/census/grpc_plugin.c \
+    src/core/lib/census/initialize.c \
+    src/core/lib/census/mlog.c \
+    src/core/lib/census/operation.c \
+    src/core/lib/census/placeholders.c \
+    src/core/lib/census/tracing.c \
+    src/core/lib/channel/channel_args.c \
+    src/core/lib/channel/channel_stack.c \
+    src/core/lib/channel/channel_stack_builder.c \
+    src/core/lib/channel/client_channel.c \
+    src/core/lib/channel/compress_filter.c \
+    src/core/lib/channel/connected_channel.c \
+    src/core/lib/channel/http_client_filter.c \
+    src/core/lib/channel/http_server_filter.c \
+    src/core/lib/channel/subchannel_call_holder.c \
+    src/core/lib/client_config/client_config.c \
+    src/core/lib/client_config/connector.c \
+    src/core/lib/client_config/default_initial_connect_string.c \
+    src/core/lib/client_config/initial_connect_string.c \
+    src/core/lib/client_config/lb_policies/load_balancer_api.c \
+    src/core/lib/client_config/lb_policies/pick_first.c \
+    src/core/lib/client_config/lb_policies/round_robin.c \
+    src/core/lib/client_config/lb_policy.c \
+    src/core/lib/client_config/lb_policy_factory.c \
+    src/core/lib/client_config/lb_policy_registry.c \
+    src/core/lib/client_config/resolver.c \
+    src/core/lib/client_config/resolver_factory.c \
+    src/core/lib/client_config/resolver_registry.c \
+    src/core/lib/client_config/resolvers/dns_resolver.c \
+    src/core/lib/client_config/resolvers/sockaddr_resolver.c \
+    src/core/lib/client_config/subchannel.c \
+    src/core/lib/client_config/subchannel_factory.c \
+    src/core/lib/client_config/subchannel_index.c \
+    src/core/lib/client_config/uri_parser.c \
+    src/core/lib/compression/compression_algorithm.c \
+    src/core/lib/compression/message_compress.c \
+    src/core/lib/debug/trace.c \
+    src/core/lib/http/format_request.c \
+    src/core/lib/http/httpcli.c \
+    src/core/lib/http/httpcli_security_connector.c \
+    src/core/lib/http/parser.c \
+    src/core/lib/iomgr/closure.c \
+    src/core/lib/iomgr/endpoint.c \
+    src/core/lib/iomgr/endpoint_pair_posix.c \
+    src/core/lib/iomgr/endpoint_pair_windows.c \
+    src/core/lib/iomgr/exec_ctx.c \
+    src/core/lib/iomgr/executor.c \
+    src/core/lib/iomgr/fd_posix.c \
+    src/core/lib/iomgr/iocp_windows.c \
+    src/core/lib/iomgr/iomgr.c \
+    src/core/lib/iomgr/iomgr_posix.c \
+    src/core/lib/iomgr/iomgr_windows.c \
+    src/core/lib/iomgr/pollset_multipoller_with_epoll.c \
+    src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c \
+    src/core/lib/iomgr/pollset_posix.c \
+    src/core/lib/iomgr/pollset_set_posix.c \
+    src/core/lib/iomgr/pollset_set_windows.c \
+    src/core/lib/iomgr/pollset_windows.c \
+    src/core/lib/iomgr/resolve_address_posix.c \
+    src/core/lib/iomgr/resolve_address_windows.c \
+    src/core/lib/iomgr/sockaddr_utils.c \
+    src/core/lib/iomgr/socket_utils_common_posix.c \
+    src/core/lib/iomgr/socket_utils_linux.c \
+    src/core/lib/iomgr/socket_utils_posix.c \
+    src/core/lib/iomgr/socket_windows.c \
+    src/core/lib/iomgr/tcp_client_posix.c \
+    src/core/lib/iomgr/tcp_client_windows.c \
+    src/core/lib/iomgr/tcp_posix.c \
+    src/core/lib/iomgr/tcp_server_posix.c \
+    src/core/lib/iomgr/tcp_server_windows.c \
+    src/core/lib/iomgr/tcp_windows.c \
+    src/core/lib/iomgr/time_averaged_stats.c \
+    src/core/lib/iomgr/timer.c \
+    src/core/lib/iomgr/timer_heap.c \
+    src/core/lib/iomgr/udp_server.c \
+    src/core/lib/iomgr/unix_sockets_posix.c \
+    src/core/lib/iomgr/unix_sockets_posix_noop.c \
+    src/core/lib/iomgr/wakeup_fd_eventfd.c \
+    src/core/lib/iomgr/wakeup_fd_nospecial.c \
+    src/core/lib/iomgr/wakeup_fd_pipe.c \
+    src/core/lib/iomgr/wakeup_fd_posix.c \
+    src/core/lib/iomgr/workqueue_posix.c \
+    src/core/lib/iomgr/workqueue_windows.c \
+    src/core/lib/json/json.c \
+    src/core/lib/json/json_reader.c \
+    src/core/lib/json/json_string.c \
+    src/core/lib/json/json_writer.c \
+    src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c \
+    src/core/lib/security/b64.c \
+    src/core/lib/security/client_auth_filter.c \
+    src/core/lib/security/credentials.c \
+    src/core/lib/security/credentials_metadata.c \
+    src/core/lib/security/credentials_posix.c \
+    src/core/lib/security/credentials_win32.c \
+    src/core/lib/security/google_default_credentials.c \
+    src/core/lib/security/handshake.c \
+    src/core/lib/security/json_token.c \
+    src/core/lib/security/jwt_verifier.c \
+    src/core/lib/security/secure_endpoint.c \
+    src/core/lib/security/security_connector.c \
+    src/core/lib/security/security_context.c \
+    src/core/lib/security/server_auth_filter.c \
+    src/core/lib/surface/alarm.c \
+    src/core/lib/surface/api_trace.c \
+    src/core/lib/surface/byte_buffer.c \
+    src/core/lib/surface/byte_buffer_reader.c \
+    src/core/lib/surface/call.c \
+    src/core/lib/surface/call_details.c \
+    src/core/lib/surface/call_log_batch.c \
+    src/core/lib/surface/channel.c \
+    src/core/lib/surface/channel_connectivity.c \
+    src/core/lib/surface/channel_init.c \
+    src/core/lib/surface/channel_ping.c \
+    src/core/lib/surface/channel_stack_type.c \
+    src/core/lib/surface/completion_queue.c \
+    src/core/lib/surface/event_string.c \
+    src/core/lib/surface/init.c \
+    src/core/lib/surface/init_secure.c \
+    src/core/lib/surface/lame_client.c \
+    src/core/lib/surface/metadata_array.c \
+    src/core/lib/surface/server.c \
+    src/core/lib/surface/validate_metadata.c \
+    src/core/lib/surface/version.c \
+    src/core/lib/transport/byte_stream.c \
+    src/core/lib/transport/connectivity_state.c \
+    src/core/lib/transport/metadata.c \
+    src/core/lib/transport/metadata_batch.c \
+    src/core/lib/transport/static_metadata.c \
+    src/core/lib/transport/transport.c \
+    src/core/lib/transport/transport_op_string.c \
+    src/core/lib/tsi/fake_transport_security.c \
+    src/core/lib/tsi/ssl_transport_security.c \
+    src/core/lib/tsi/transport_security.c \
     third_party/nanopb/pb_common.c \
     third_party/nanopb/pb_decode.c \
     third_party/nanopb/pb_encode.c \
 
 PUBLIC_HEADERS_C += \
+    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/impl/codegen/byte_buffer.h \
     include/grpc/impl/codegen/compression_types.h \
@@ -2523,12 +2612,7 @@
     include/grpc/impl/codegen/grpc_types.h \
     include/grpc/impl/codegen/propagation_bits.h \
     include/grpc/impl/codegen/status.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 \
 
 LIBGRPC_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_SRC))))
 
@@ -2582,17 +2666,62 @@
 endif
 
 
+LIBGRPC_CODEGEN_LIB_SRC = \
+
+PUBLIC_HEADERS_C += \
+    include/grpc/impl/codegen/alloc.h \
+    include/grpc/impl/codegen/atm.h \
+    include/grpc/impl/codegen/atm_gcc_atomic.h \
+    include/grpc/impl/codegen/atm_gcc_sync.h \
+    include/grpc/impl/codegen/atm_win32.h \
+    include/grpc/impl/codegen/byte_buffer.h \
+    include/grpc/impl/codegen/compression_types.h \
+    include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/grpc_types.h \
+    include/grpc/impl/codegen/log.h \
+    include/grpc/impl/codegen/port_platform.h \
+    include/grpc/impl/codegen/propagation_bits.h \
+    include/grpc/impl/codegen/slice.h \
+    include/grpc/impl/codegen/slice_buffer.h \
+    include/grpc/impl/codegen/status.h \
+    include/grpc/impl/codegen/sync.h \
+    include/grpc/impl/codegen/sync_generic.h \
+    include/grpc/impl/codegen/sync_posix.h \
+    include/grpc/impl/codegen/sync_win32.h \
+    include/grpc/impl/codegen/time.h \
+
+LIBGRPC_CODEGEN_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_CODEGEN_LIB_SRC))))
+
+
+$(LIBDIR)/$(CONFIG)/libgrpc_codegen_lib.a: $(ZLIB_DEP)  $(LIBGRPC_CODEGEN_LIB_OBJS) 
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_codegen_lib.a
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_codegen_lib.a $(LIBGRPC_CODEGEN_LIB_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc_codegen_lib.a
+endif
+
+
+
+
+ifneq ($(NO_DEPS),true)
+-include $(LIBGRPC_CODEGEN_LIB_OBJS:.o=.dep)
+endif
+
+
 LIBGRPC_TEST_UTIL_SRC = \
+    test/core/end2end/cq_verifier.c \
     test/core/end2end/data/server1_cert.c \
     test/core/end2end/data/server1_key.c \
     test/core/end2end/data/test_root_cert.c \
-    test/core/security/oauth2_utils.c \
-    test/core/end2end/cq_verifier.c \
     test/core/end2end/fixtures/proxy.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 \
+    test/core/util/port_server_client.c \
     test/core/util/port_windows.c \
     test/core/util/slice_splitter.c \
 
@@ -2639,6 +2768,7 @@
     test/core/util/grpc_profiler.c \
     test/core/util/parse_hexstring.c \
     test/core/util/port_posix.c \
+    test/core/util/port_server_client.c \
     test/core/util/port_windows.c \
     test/core/util/slice_splitter.c \
 
@@ -2665,143 +2795,147 @@
 
 
 LIBGRPC_UNSECURE_SRC = \
-    src/core/surface/init_unsecure.c \
-    src/core/census/grpc_context.c \
-    src/core/census/grpc_filter.c \
-    src/core/channel/channel_args.c \
-    src/core/channel/channel_stack.c \
-    src/core/channel/client_channel.c \
-    src/core/channel/client_uchannel.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/subchannel_call_holder.c \
-    src/core/client_config/client_config.c \
-    src/core/client_config/connector.c \
-    src/core/client_config/default_initial_connect_string.c \
-    src/core/client_config/initial_connect_string.c \
-    src/core/client_config/lb_policies/load_balancer_api.c \
-    src/core/client_config/lb_policies/pick_first.c \
-    src/core/client_config/lb_policies/round_robin.c \
-    src/core/client_config/lb_policy.c \
-    src/core/client_config/lb_policy_factory.c \
-    src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c \
-    src/core/client_config/subchannel.c \
-    src/core/client_config/subchannel_factory.c \
-    src/core/client_config/subchannel_index.c \
-    src/core/client_config/uri_parser.c \
-    src/core/compression/compression_algorithm.c \
-    src/core/compression/message_compress.c \
-    src/core/debug/trace.c \
-    src/core/httpcli/format_request.c \
-    src/core/httpcli/httpcli.c \
-    src/core/httpcli/parser.c \
-    src/core/iomgr/closure.c \
-    src/core/iomgr/endpoint.c \
-    src/core/iomgr/endpoint_pair_posix.c \
-    src/core/iomgr/endpoint_pair_windows.c \
-    src/core/iomgr/exec_ctx.c \
-    src/core/iomgr/executor.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_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/timer.c \
-    src/core/iomgr/timer_heap.c \
-    src/core/iomgr/udp_server.c \
-    src/core/iomgr/wakeup_fd_eventfd.c \
-    src/core/iomgr/wakeup_fd_nospecial.c \
-    src/core/iomgr/wakeup_fd_pipe.c \
-    src/core/iomgr/wakeup_fd_posix.c \
-    src/core/iomgr/workqueue_posix.c \
-    src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c \
-    src/core/surface/alarm.c \
-    src/core/surface/api_trace.c \
-    src/core/surface/byte_buffer.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_connectivity.c \
-    src/core/surface/channel_create.c \
-    src/core/surface/channel_ping.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/validate_metadata.c \
-    src/core/surface/version.c \
-    src/core/transport/byte_stream.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_encoder.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_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/metadata_batch.c \
-    src/core/transport/static_metadata.c \
-    src/core/transport/transport.c \
-    src/core/transport/transport_op_string.c \
-    src/core/census/context.c \
-    src/core/census/initialize.c \
-    src/core/census/mlog.c \
-    src/core/census/operation.c \
-    src/core/census/placeholders.c \
-    src/core/census/tracing.c \
+    src/core/ext/transport/chttp2/client/insecure/channel_create.c \
+    src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
+    src/core/ext/transport/chttp2/transport/alpn.c \
+    src/core/ext/transport/chttp2/transport/bin_encoder.c \
+    src/core/ext/transport/chttp2/transport/chttp2_transport.c \
+    src/core/ext/transport/chttp2/transport/frame_data.c \
+    src/core/ext/transport/chttp2/transport/frame_goaway.c \
+    src/core/ext/transport/chttp2/transport/frame_ping.c \
+    src/core/ext/transport/chttp2/transport/frame_rst_stream.c \
+    src/core/ext/transport/chttp2/transport/frame_settings.c \
+    src/core/ext/transport/chttp2/transport/frame_window_update.c \
+    src/core/ext/transport/chttp2/transport/hpack_encoder.c \
+    src/core/ext/transport/chttp2/transport/hpack_parser.c \
+    src/core/ext/transport/chttp2/transport/hpack_table.c \
+    src/core/ext/transport/chttp2/transport/huffsyms.c \
+    src/core/ext/transport/chttp2/transport/incoming_metadata.c \
+    src/core/ext/transport/chttp2/transport/parsing.c \
+    src/core/ext/transport/chttp2/transport/status_conversion.c \
+    src/core/ext/transport/chttp2/transport/stream_lists.c \
+    src/core/ext/transport/chttp2/transport/stream_map.c \
+    src/core/ext/transport/chttp2/transport/timeout_encoding.c \
+    src/core/ext/transport/chttp2/transport/varint.c \
+    src/core/ext/transport/chttp2/transport/writing.c \
+    src/core/lib/census/context.c \
+    src/core/lib/census/grpc_context.c \
+    src/core/lib/census/grpc_filter.c \
+    src/core/lib/census/grpc_plugin.c \
+    src/core/lib/census/initialize.c \
+    src/core/lib/census/mlog.c \
+    src/core/lib/census/operation.c \
+    src/core/lib/census/placeholders.c \
+    src/core/lib/census/tracing.c \
+    src/core/lib/channel/channel_args.c \
+    src/core/lib/channel/channel_stack.c \
+    src/core/lib/channel/channel_stack_builder.c \
+    src/core/lib/channel/client_channel.c \
+    src/core/lib/channel/compress_filter.c \
+    src/core/lib/channel/connected_channel.c \
+    src/core/lib/channel/http_client_filter.c \
+    src/core/lib/channel/http_server_filter.c \
+    src/core/lib/channel/subchannel_call_holder.c \
+    src/core/lib/client_config/client_config.c \
+    src/core/lib/client_config/connector.c \
+    src/core/lib/client_config/default_initial_connect_string.c \
+    src/core/lib/client_config/initial_connect_string.c \
+    src/core/lib/client_config/lb_policies/load_balancer_api.c \
+    src/core/lib/client_config/lb_policies/pick_first.c \
+    src/core/lib/client_config/lb_policies/round_robin.c \
+    src/core/lib/client_config/lb_policy.c \
+    src/core/lib/client_config/lb_policy_factory.c \
+    src/core/lib/client_config/lb_policy_registry.c \
+    src/core/lib/client_config/resolver.c \
+    src/core/lib/client_config/resolver_factory.c \
+    src/core/lib/client_config/resolver_registry.c \
+    src/core/lib/client_config/resolvers/dns_resolver.c \
+    src/core/lib/client_config/resolvers/sockaddr_resolver.c \
+    src/core/lib/client_config/subchannel.c \
+    src/core/lib/client_config/subchannel_factory.c \
+    src/core/lib/client_config/subchannel_index.c \
+    src/core/lib/client_config/uri_parser.c \
+    src/core/lib/compression/compression_algorithm.c \
+    src/core/lib/compression/message_compress.c \
+    src/core/lib/debug/trace.c \
+    src/core/lib/http/format_request.c \
+    src/core/lib/http/httpcli.c \
+    src/core/lib/http/parser.c \
+    src/core/lib/iomgr/closure.c \
+    src/core/lib/iomgr/endpoint.c \
+    src/core/lib/iomgr/endpoint_pair_posix.c \
+    src/core/lib/iomgr/endpoint_pair_windows.c \
+    src/core/lib/iomgr/exec_ctx.c \
+    src/core/lib/iomgr/executor.c \
+    src/core/lib/iomgr/fd_posix.c \
+    src/core/lib/iomgr/iocp_windows.c \
+    src/core/lib/iomgr/iomgr.c \
+    src/core/lib/iomgr/iomgr_posix.c \
+    src/core/lib/iomgr/iomgr_windows.c \
+    src/core/lib/iomgr/pollset_multipoller_with_epoll.c \
+    src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c \
+    src/core/lib/iomgr/pollset_posix.c \
+    src/core/lib/iomgr/pollset_set_posix.c \
+    src/core/lib/iomgr/pollset_set_windows.c \
+    src/core/lib/iomgr/pollset_windows.c \
+    src/core/lib/iomgr/resolve_address_posix.c \
+    src/core/lib/iomgr/resolve_address_windows.c \
+    src/core/lib/iomgr/sockaddr_utils.c \
+    src/core/lib/iomgr/socket_utils_common_posix.c \
+    src/core/lib/iomgr/socket_utils_linux.c \
+    src/core/lib/iomgr/socket_utils_posix.c \
+    src/core/lib/iomgr/socket_windows.c \
+    src/core/lib/iomgr/tcp_client_posix.c \
+    src/core/lib/iomgr/tcp_client_windows.c \
+    src/core/lib/iomgr/tcp_posix.c \
+    src/core/lib/iomgr/tcp_server_posix.c \
+    src/core/lib/iomgr/tcp_server_windows.c \
+    src/core/lib/iomgr/tcp_windows.c \
+    src/core/lib/iomgr/time_averaged_stats.c \
+    src/core/lib/iomgr/timer.c \
+    src/core/lib/iomgr/timer_heap.c \
+    src/core/lib/iomgr/udp_server.c \
+    src/core/lib/iomgr/unix_sockets_posix.c \
+    src/core/lib/iomgr/unix_sockets_posix_noop.c \
+    src/core/lib/iomgr/wakeup_fd_eventfd.c \
+    src/core/lib/iomgr/wakeup_fd_nospecial.c \
+    src/core/lib/iomgr/wakeup_fd_pipe.c \
+    src/core/lib/iomgr/wakeup_fd_posix.c \
+    src/core/lib/iomgr/workqueue_posix.c \
+    src/core/lib/iomgr/workqueue_windows.c \
+    src/core/lib/json/json.c \
+    src/core/lib/json/json_reader.c \
+    src/core/lib/json/json_string.c \
+    src/core/lib/json/json_writer.c \
+    src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c \
+    src/core/lib/surface/alarm.c \
+    src/core/lib/surface/api_trace.c \
+    src/core/lib/surface/byte_buffer.c \
+    src/core/lib/surface/byte_buffer_reader.c \
+    src/core/lib/surface/call.c \
+    src/core/lib/surface/call_details.c \
+    src/core/lib/surface/call_log_batch.c \
+    src/core/lib/surface/channel.c \
+    src/core/lib/surface/channel_connectivity.c \
+    src/core/lib/surface/channel_init.c \
+    src/core/lib/surface/channel_ping.c \
+    src/core/lib/surface/channel_stack_type.c \
+    src/core/lib/surface/completion_queue.c \
+    src/core/lib/surface/event_string.c \
+    src/core/lib/surface/init.c \
+    src/core/lib/surface/init_unsecure.c \
+    src/core/lib/surface/lame_client.c \
+    src/core/lib/surface/metadata_array.c \
+    src/core/lib/surface/server.c \
+    src/core/lib/surface/validate_metadata.c \
+    src/core/lib/surface/version.c \
+    src/core/lib/transport/byte_stream.c \
+    src/core/lib/transport/connectivity_state.c \
+    src/core/lib/transport/metadata.c \
+    src/core/lib/transport/metadata_batch.c \
+    src/core/lib/transport/static_metadata.c \
+    src/core/lib/transport/transport.c \
+    src/core/lib/transport/transport_op_string.c \
     third_party/nanopb/pb_common.c \
     third_party/nanopb/pb_decode.c \
     third_party/nanopb/pb_encode.c \
@@ -2809,16 +2943,16 @@
 PUBLIC_HEADERS_C += \
     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 \
     include/grpc/impl/codegen/byte_buffer.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
     include/grpc/impl/codegen/grpc_types.h \
     include/grpc/impl/codegen/propagation_bits.h \
     include/grpc/impl/codegen/status.h \
-    include/grpc/census.h \
+    include/grpc/status.h \
 
 LIBGRPC_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_UNSECURE_SRC))))
 
@@ -2858,7 +2992,7 @@
 
 
 LIBGRPC_ZOOKEEPER_SRC = \
-    src/core/client_config/resolvers/zookeeper_resolver.c \
+    src/core/lib/client_config/resolvers/zookeeper_resolver.c \
 
 PUBLIC_HEADERS_C += \
     include/grpc/grpc_zookeeper.h \
@@ -2903,6 +3037,7 @@
 LIBRECONNECT_SERVER_SRC = \
     test/core/util/reconnect_server.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBRECONNECT_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBRECONNECT_SERVER_SRC))))
 
@@ -2941,6 +3076,7 @@
 LIBTEST_TCP_SERVER_SRC = \
     test/core/util/test_tcp_server.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBTEST_TCP_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBTEST_TCP_SERVER_SRC))))
 
@@ -2977,12 +3113,6 @@
 
 
 LIBGRPC++_SRC = \
-    src/cpp/client/secure_credentials.cc \
-    src/cpp/common/auth_property_iterator.cc \
-    src/cpp/common/secure_auth_context.cc \
-    src/cpp/common/secure_channel_arguments.cc \
-    src/cpp/common/secure_create_auth_context.cc \
-    src/cpp/server/secure_server_credentials.cc \
     src/cpp/client/channel.cc \
     src/cpp/client/client_context.cc \
     src/cpp/client/create_channel.cc \
@@ -2990,15 +3120,21 @@
     src/cpp/client/credentials.cc \
     src/cpp/client/generic_stub.cc \
     src/cpp/client/insecure_credentials.cc \
-    src/cpp/common/call.cc \
+    src/cpp/client/secure_credentials.cc \
+    src/cpp/codegen/codegen_init.cc \
+    src/cpp/common/auth_property_iterator.cc \
     src/cpp/common/channel_arguments.cc \
     src/cpp/common/completion_queue.cc \
+    src/cpp/common/core_codegen.cc \
     src/cpp/common/rpc_method.cc \
-    src/cpp/proto/proto_utils.cc \
+    src/cpp/common/secure_auth_context.cc \
+    src/cpp/common/secure_channel_arguments.cc \
+    src/cpp/common/secure_create_auth_context.cc \
     src/cpp/server/async_generic_service.cc \
     src/cpp/server/create_default_thread_pool.cc \
     src/cpp/server/dynamic_thread_pool.cc \
     src/cpp/server/insecure_server_credentials.cc \
+    src/cpp/server/secure_server_credentials.cc \
     src/cpp/server/server.cc \
     src/cpp/server/server_builder.cc \
     src/cpp/server/server_context.cc \
@@ -3008,7 +3144,6 @@
     src/cpp/util/status.cc \
     src/cpp/util/string_ref.cc \
     src/cpp/util/time.cc \
-    src/cpp/codegen/grpc_library.cc \
 
 PUBLIC_HEADERS_CXX += \
     include/grpc++/alarm.h \
@@ -3021,6 +3156,37 @@
     include/grpc++/grpc++.h \
     include/grpc++/impl/call.h \
     include/grpc++/impl/client_unary_call.h \
+    include/grpc++/impl/codegen/async_stream.h \
+    include/grpc++/impl/codegen/async_unary_call.h \
+    include/grpc++/impl/codegen/call.h \
+    include/grpc++/impl/codegen/call_hook.h \
+    include/grpc++/impl/codegen/channel_interface.h \
+    include/grpc++/impl/codegen/client_context.h \
+    include/grpc++/impl/codegen/client_unary_call.h \
+    include/grpc++/impl/codegen/completion_queue.h \
+    include/grpc++/impl/codegen/completion_queue_tag.h \
+    include/grpc++/impl/codegen/config.h \
+    include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpc++/impl/codegen/core_codegen_interface.h \
+    include/grpc++/impl/codegen/grpc_library.h \
+    include/grpc++/impl/codegen/method_handler_impl.h \
+    include/grpc++/impl/codegen/proto_utils.h \
+    include/grpc++/impl/codegen/rpc_method.h \
+    include/grpc++/impl/codegen/rpc_service_method.h \
+    include/grpc++/impl/codegen/security/auth_context.h \
+    include/grpc++/impl/codegen/serialization_traits.h \
+    include/grpc++/impl/codegen/server_context.h \
+    include/grpc++/impl/codegen/server_interface.h \
+    include/grpc++/impl/codegen/service_type.h \
+    include/grpc++/impl/codegen/status.h \
+    include/grpc++/impl/codegen/status_code_enum.h \
+    include/grpc++/impl/codegen/string_ref.h \
+    include/grpc++/impl/codegen/stub_options.h \
+    include/grpc++/impl/codegen/sync.h \
+    include/grpc++/impl/codegen/sync_cxx11.h \
+    include/grpc++/impl/codegen/sync_no_cxx11.h \
+    include/grpc++/impl/codegen/sync_stream.h \
+    include/grpc++/impl/codegen/time.h \
     include/grpc++/impl/grpc_library.h \
     include/grpc++/impl/method_handler_impl.h \
     include/grpc++/impl/proto_utils.h \
@@ -3055,36 +3221,6 @@
     include/grpc++/support/stub_options.h \
     include/grpc++/support/sync_stream.h \
     include/grpc++/support/time.h \
-    include/grpc++/impl/codegen/async_stream.h \
-    include/grpc++/impl/codegen/async_unary_call.h \
-    include/grpc++/impl/codegen/call.h \
-    include/grpc++/impl/codegen/call_hook.h \
-    include/grpc++/impl/codegen/channel_interface.h \
-    include/grpc++/impl/codegen/client_context.h \
-    include/grpc++/impl/codegen/client_unary_call.h \
-    include/grpc++/impl/codegen/completion_queue.h \
-    include/grpc++/impl/codegen/completion_queue_tag.h \
-    include/grpc++/impl/codegen/config.h \
-    include/grpc++/impl/codegen/config_protobuf.h \
-    include/grpc++/impl/codegen/grpc_library.h \
-    include/grpc++/impl/codegen/method_handler_impl.h \
-    include/grpc++/impl/codegen/proto_utils.h \
-    include/grpc++/impl/codegen/rpc_method.h \
-    include/grpc++/impl/codegen/rpc_service_method.h \
-    include/grpc++/impl/codegen/security/auth_context.h \
-    include/grpc++/impl/codegen/serialization_traits.h \
-    include/grpc++/impl/codegen/server_context.h \
-    include/grpc++/impl/codegen/server_interface.h \
-    include/grpc++/impl/codegen/service_type.h \
-    include/grpc++/impl/codegen/status.h \
-    include/grpc++/impl/codegen/status_code_enum.h \
-    include/grpc++/impl/codegen/string_ref.h \
-    include/grpc++/impl/codegen/stub_options.h \
-    include/grpc++/impl/codegen/sync.h \
-    include/grpc++/impl/codegen/sync_cxx11.h \
-    include/grpc++/impl/codegen/sync_no_cxx11.h \
-    include/grpc++/impl/codegen/sync_stream.h \
-    include/grpc++/impl/codegen/time.h \
 
 LIBGRPC++_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_SRC))))
 
@@ -3149,9 +3285,115 @@
 endif
 
 
+LIBGRPC++_CODEGEN_LIB_SRC = \
+    src/cpp/codegen/codegen_init.cc \
+
+PUBLIC_HEADERS_CXX += \
+    include/grpc++/impl/codegen/async_stream.h \
+    include/grpc++/impl/codegen/async_unary_call.h \
+    include/grpc++/impl/codegen/call.h \
+    include/grpc++/impl/codegen/call_hook.h \
+    include/grpc++/impl/codegen/channel_interface.h \
+    include/grpc++/impl/codegen/client_context.h \
+    include/grpc++/impl/codegen/client_unary_call.h \
+    include/grpc++/impl/codegen/completion_queue.h \
+    include/grpc++/impl/codegen/completion_queue_tag.h \
+    include/grpc++/impl/codegen/config.h \
+    include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpc++/impl/codegen/core_codegen_interface.h \
+    include/grpc++/impl/codegen/grpc_library.h \
+    include/grpc++/impl/codegen/method_handler_impl.h \
+    include/grpc++/impl/codegen/proto_utils.h \
+    include/grpc++/impl/codegen/rpc_method.h \
+    include/grpc++/impl/codegen/rpc_service_method.h \
+    include/grpc++/impl/codegen/security/auth_context.h \
+    include/grpc++/impl/codegen/serialization_traits.h \
+    include/grpc++/impl/codegen/server_context.h \
+    include/grpc++/impl/codegen/server_interface.h \
+    include/grpc++/impl/codegen/service_type.h \
+    include/grpc++/impl/codegen/status.h \
+    include/grpc++/impl/codegen/status_code_enum.h \
+    include/grpc++/impl/codegen/string_ref.h \
+    include/grpc++/impl/codegen/stub_options.h \
+    include/grpc++/impl/codegen/sync.h \
+    include/grpc++/impl/codegen/sync_cxx11.h \
+    include/grpc++/impl/codegen/sync_no_cxx11.h \
+    include/grpc++/impl/codegen/sync_stream.h \
+    include/grpc++/impl/codegen/time.h \
+    include/grpc/impl/codegen/alloc.h \
+    include/grpc/impl/codegen/atm.h \
+    include/grpc/impl/codegen/atm_gcc_atomic.h \
+    include/grpc/impl/codegen/atm_gcc_sync.h \
+    include/grpc/impl/codegen/atm_win32.h \
+    include/grpc/impl/codegen/byte_buffer.h \
+    include/grpc/impl/codegen/compression_types.h \
+    include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/grpc_types.h \
+    include/grpc/impl/codegen/log.h \
+    include/grpc/impl/codegen/port_platform.h \
+    include/grpc/impl/codegen/propagation_bits.h \
+    include/grpc/impl/codegen/slice.h \
+    include/grpc/impl/codegen/slice_buffer.h \
+    include/grpc/impl/codegen/status.h \
+    include/grpc/impl/codegen/sync.h \
+    include/grpc/impl/codegen/sync_generic.h \
+    include/grpc/impl/codegen/sync_posix.h \
+    include/grpc/impl/codegen/sync_win32.h \
+    include/grpc/impl/codegen/time.h \
+
+LIBGRPC++_CODEGEN_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_CODEGEN_LIB_SRC))))
+
+
+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++_codegen_lib.a: protobuf_dep_error
+
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT): protobuf_dep_error
+
+else
+
+$(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBGRPC++_CODEGEN_LIB_OBJS) 
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a $(LIBGRPC++_CODEGEN_LIB_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a
+endif
+
+
+
+ifeq ($(SYSTEM),MINGW32)
+$(LIBDIR)/$(CONFIG)/grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_CODEGEN_LIB_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP)
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_codegen_lib.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_codegen_lib$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_CODEGEN_LIB_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF)
+else
+$(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_CODEGEN_LIB_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP)
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+ifeq ($(SYSTEM),Darwin)
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_CODEGEN_LIB_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF)
+else
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_codegen_lib.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_CODEGEN_LIB_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib$(SHARED_VERSION).so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_codegen_lib$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib$(SHARED_VERSION).so
+endif
+endif
+
+endif
+
+ifneq ($(NO_DEPS),true)
+-include $(LIBGRPC++_CODEGEN_LIB_OBJS:.o=.dep)
+endif
+
+
 LIBGRPC++_TEST_CONFIG_SRC = \
     test/cpp/util/test_config.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBGRPC++_TEST_CONFIG_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_TEST_CONFIG_SRC))))
 
@@ -3198,9 +3440,9 @@
 
 
 LIBGRPC++_TEST_UTIL_SRC = \
-    $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc \
-    $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \
     $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc \
     test/cpp/end2end/test_service_impl.cc \
     test/cpp/util/byte_buffer_proto_helper.cc \
     test/cpp/util/cli_call.cc \
@@ -3209,6 +3451,7 @@
     test/cpp/util/subprocess.cc \
     test/cpp/util/test_credentials_provider.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBGRPC++_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_TEST_UTIL_SRC))))
 
@@ -3252,17 +3495,16 @@
 -include $(LIBGRPC++_TEST_UTIL_OBJS:.o=.dep)
 endif
 endif
-$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_service_impl.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/byte_buffer_proto_helper.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/cli_call.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/subprocess.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/test_credentials_provider.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_service_impl.o: $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/byte_buffer_proto_helper.o: $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/cli_call.o: $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/subprocess.o: $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/test_credentials_provider.o: $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
 
 
 LIBGRPC++_UNSECURE_SRC = \
-    src/cpp/common/insecure_create_auth_context.cc \
     src/cpp/client/channel.cc \
     src/cpp/client/client_context.cc \
     src/cpp/client/create_channel.cc \
@@ -3270,11 +3512,12 @@
     src/cpp/client/credentials.cc \
     src/cpp/client/generic_stub.cc \
     src/cpp/client/insecure_credentials.cc \
-    src/cpp/common/call.cc \
+    src/cpp/codegen/codegen_init.cc \
     src/cpp/common/channel_arguments.cc \
     src/cpp/common/completion_queue.cc \
+    src/cpp/common/core_codegen.cc \
+    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/dynamic_thread_pool.cc \
@@ -3288,7 +3531,6 @@
     src/cpp/util/status.cc \
     src/cpp/util/string_ref.cc \
     src/cpp/util/time.cc \
-    src/cpp/codegen/grpc_library.cc \
 
 PUBLIC_HEADERS_CXX += \
     include/grpc++/alarm.h \
@@ -3301,6 +3543,37 @@
     include/grpc++/grpc++.h \
     include/grpc++/impl/call.h \
     include/grpc++/impl/client_unary_call.h \
+    include/grpc++/impl/codegen/async_stream.h \
+    include/grpc++/impl/codegen/async_unary_call.h \
+    include/grpc++/impl/codegen/call.h \
+    include/grpc++/impl/codegen/call_hook.h \
+    include/grpc++/impl/codegen/channel_interface.h \
+    include/grpc++/impl/codegen/client_context.h \
+    include/grpc++/impl/codegen/client_unary_call.h \
+    include/grpc++/impl/codegen/completion_queue.h \
+    include/grpc++/impl/codegen/completion_queue_tag.h \
+    include/grpc++/impl/codegen/config.h \
+    include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpc++/impl/codegen/core_codegen_interface.h \
+    include/grpc++/impl/codegen/grpc_library.h \
+    include/grpc++/impl/codegen/method_handler_impl.h \
+    include/grpc++/impl/codegen/proto_utils.h \
+    include/grpc++/impl/codegen/rpc_method.h \
+    include/grpc++/impl/codegen/rpc_service_method.h \
+    include/grpc++/impl/codegen/security/auth_context.h \
+    include/grpc++/impl/codegen/serialization_traits.h \
+    include/grpc++/impl/codegen/server_context.h \
+    include/grpc++/impl/codegen/server_interface.h \
+    include/grpc++/impl/codegen/service_type.h \
+    include/grpc++/impl/codegen/status.h \
+    include/grpc++/impl/codegen/status_code_enum.h \
+    include/grpc++/impl/codegen/string_ref.h \
+    include/grpc++/impl/codegen/stub_options.h \
+    include/grpc++/impl/codegen/sync.h \
+    include/grpc++/impl/codegen/sync_cxx11.h \
+    include/grpc++/impl/codegen/sync_no_cxx11.h \
+    include/grpc++/impl/codegen/sync_stream.h \
+    include/grpc++/impl/codegen/time.h \
     include/grpc++/impl/grpc_library.h \
     include/grpc++/impl/method_handler_impl.h \
     include/grpc++/impl/proto_utils.h \
@@ -3335,36 +3608,6 @@
     include/grpc++/support/stub_options.h \
     include/grpc++/support/sync_stream.h \
     include/grpc++/support/time.h \
-    include/grpc++/impl/codegen/async_stream.h \
-    include/grpc++/impl/codegen/async_unary_call.h \
-    include/grpc++/impl/codegen/call.h \
-    include/grpc++/impl/codegen/call_hook.h \
-    include/grpc++/impl/codegen/channel_interface.h \
-    include/grpc++/impl/codegen/client_context.h \
-    include/grpc++/impl/codegen/client_unary_call.h \
-    include/grpc++/impl/codegen/completion_queue.h \
-    include/grpc++/impl/codegen/completion_queue_tag.h \
-    include/grpc++/impl/codegen/config.h \
-    include/grpc++/impl/codegen/config_protobuf.h \
-    include/grpc++/impl/codegen/grpc_library.h \
-    include/grpc++/impl/codegen/method_handler_impl.h \
-    include/grpc++/impl/codegen/proto_utils.h \
-    include/grpc++/impl/codegen/rpc_method.h \
-    include/grpc++/impl/codegen/rpc_service_method.h \
-    include/grpc++/impl/codegen/security/auth_context.h \
-    include/grpc++/impl/codegen/serialization_traits.h \
-    include/grpc++/impl/codegen/server_context.h \
-    include/grpc++/impl/codegen/server_interface.h \
-    include/grpc++/impl/codegen/service_type.h \
-    include/grpc++/impl/codegen/status.h \
-    include/grpc++/impl/codegen/status_code_enum.h \
-    include/grpc++/impl/codegen/string_ref.h \
-    include/grpc++/impl/codegen/stub_options.h \
-    include/grpc++/impl/codegen/sync.h \
-    include/grpc++/impl/codegen/sync_cxx11.h \
-    include/grpc++/impl/codegen/sync_no_cxx11.h \
-    include/grpc++/impl/codegen/sync_stream.h \
-    include/grpc++/impl/codegen/time.h \
 
 LIBGRPC++_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_UNSECURE_SRC))))
 
@@ -3421,45 +3664,8 @@
     src/compiler/objective_c_generator.cc \
     src/compiler/python_generator.cc \
     src/compiler/ruby_generator.cc \
-    src/cpp/codegen/grpc_library.cc \
 
 PUBLIC_HEADERS_CXX += \
-    include/grpc++/impl/codegen/async_stream.h \
-    include/grpc++/impl/codegen/async_unary_call.h \
-    include/grpc++/impl/codegen/call.h \
-    include/grpc++/impl/codegen/call_hook.h \
-    include/grpc++/impl/codegen/channel_interface.h \
-    include/grpc++/impl/codegen/client_context.h \
-    include/grpc++/impl/codegen/client_unary_call.h \
-    include/grpc++/impl/codegen/completion_queue.h \
-    include/grpc++/impl/codegen/completion_queue_tag.h \
-    include/grpc++/impl/codegen/config.h \
-    include/grpc++/impl/codegen/config_protobuf.h \
-    include/grpc++/impl/codegen/grpc_library.h \
-    include/grpc++/impl/codegen/method_handler_impl.h \
-    include/grpc++/impl/codegen/proto_utils.h \
-    include/grpc++/impl/codegen/rpc_method.h \
-    include/grpc++/impl/codegen/rpc_service_method.h \
-    include/grpc++/impl/codegen/security/auth_context.h \
-    include/grpc++/impl/codegen/serialization_traits.h \
-    include/grpc++/impl/codegen/server_context.h \
-    include/grpc++/impl/codegen/server_interface.h \
-    include/grpc++/impl/codegen/service_type.h \
-    include/grpc++/impl/codegen/status.h \
-    include/grpc++/impl/codegen/status_code_enum.h \
-    include/grpc++/impl/codegen/string_ref.h \
-    include/grpc++/impl/codegen/stub_options.h \
-    include/grpc++/impl/codegen/sync.h \
-    include/grpc++/impl/codegen/sync_cxx11.h \
-    include/grpc++/impl/codegen/sync_no_cxx11.h \
-    include/grpc++/impl/codegen/sync_stream.h \
-    include/grpc++/impl/codegen/time.h \
-    include/grpc/impl/codegen/byte_buffer.h \
-    include/grpc/impl/codegen/compression_types.h \
-    include/grpc/impl/codegen/connectivity_state.h \
-    include/grpc/impl/codegen/grpc_types.h \
-    include/grpc/impl/codegen/propagation_bits.h \
-    include/grpc/impl/codegen/status.h \
     include/grpc/impl/codegen/alloc.h \
     include/grpc/impl/codegen/atm.h \
     include/grpc/impl/codegen/atm_gcc_atomic.h \
@@ -3510,6 +3716,7 @@
     $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc \
     test/cpp/interop/client_helper.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBINTEROP_CLIENT_HELPER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBINTEROP_CLIENT_HELPER_SRC))))
 
@@ -3563,6 +3770,7 @@
     test/cpp/interop/client.cc \
     test/cpp/interop/interop_client.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBINTEROP_CLIENT_MAIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBINTEROP_CLIENT_MAIN_SRC))))
 
@@ -3613,6 +3821,7 @@
 LIBINTEROP_SERVER_HELPER_SRC = \
     test/cpp/interop/server_helper.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBINTEROP_SERVER_HELPER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBINTEROP_SERVER_HELPER_SRC))))
 
@@ -3664,6 +3873,7 @@
     $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc \
     test/cpp/interop/server_main.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBINTEROP_SERVER_MAIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBINTEROP_SERVER_MAIN_SRC))))
 
@@ -3711,12 +3921,12 @@
 
 
 LIBQPS_SRC = \
+    $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc \
     $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc \
     $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc \
-    $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc \
-    $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc \
-    $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc \
     $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc \
     test/cpp/qps/client_async.cc \
     test/cpp/qps/client_sync.cc \
     test/cpp/qps/driver.cc \
@@ -3729,6 +3939,7 @@
     test/cpp/qps/usage_timer.cc \
     test/cpp/util/benchmark_config.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBQPS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBQPS_SRC))))
 
@@ -3772,22 +3983,23 @@
 -include $(LIBQPS_OBJS:.o=.dep)
 endif
 endif
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_async.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_sync.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/limit_cores.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/perf_db_client.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_worker.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_async.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_sync.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/usage_timer.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/util/benchmark_config.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_async.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/client_sync.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/limit_cores.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/perf_db_client.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_worker.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_async.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/server_sync.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/usage_timer.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/benchmark_config.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
 
 
 LIBGRPC_CSHARP_EXT_SRC = \
     src/csharp/ext/grpc_csharp_ext.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBGRPC_CSHARP_EXT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_CSHARP_EXT_SRC))))
 
@@ -4137,6 +4349,7 @@
     third_party/boringssl/ssl/t1_lib.c \
     third_party/boringssl/ssl/tls_record.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_SRC))))
 
@@ -4165,6 +4378,7 @@
     third_party/boringssl/crypto/test/malloc.cc \
     third_party/boringssl/crypto/test/test_util.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_TEST_UTIL_SRC))))
 
@@ -4202,6 +4416,7 @@
 LIBBORINGSSL_AES_TEST_LIB_SRC = \
     third_party/boringssl/crypto/aes/aes_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_AES_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_AES_TEST_LIB_SRC))))
 
@@ -4236,9 +4451,48 @@
 endif
 
 
+LIBBORINGSSL_ASN1_TEST_LIB_SRC = \
+    third_party/boringssl/crypto/asn1/asn1_test.cc \
+
+PUBLIC_HEADERS_CXX += \
+
+LIBBORINGSSL_ASN1_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_ASN1_TEST_LIB_SRC))))
+
+$(LIBBORINGSSL_ASN1_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_ASN1_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
+
+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)/libboringssl_asn1_test_lib.a: protobuf_dep_error
+
+
+else
+
+$(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ASN1_TEST_LIB_OBJS) 
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBBORINGSSL_ASN1_TEST_LIB_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a
+endif
+
+
+
+
+endif
+
+ifneq ($(NO_DEPS),true)
+-include $(LIBBORINGSSL_ASN1_TEST_LIB_OBJS:.o=.dep)
+endif
+
+
 LIBBORINGSSL_BASE64_TEST_LIB_SRC = \
     third_party/boringssl/crypto/base64/base64_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_BASE64_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_BASE64_TEST_LIB_SRC))))
 
@@ -4276,6 +4530,7 @@
 LIBBORINGSSL_BIO_TEST_LIB_SRC = \
     third_party/boringssl/crypto/bio/bio_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_BIO_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_BIO_TEST_LIB_SRC))))
 
@@ -4313,6 +4568,7 @@
 LIBBORINGSSL_BN_TEST_LIB_SRC = \
     third_party/boringssl/crypto/bn/bn_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_BN_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_BN_TEST_LIB_SRC))))
 
@@ -4350,6 +4606,7 @@
 LIBBORINGSSL_BYTESTRING_TEST_LIB_SRC = \
     third_party/boringssl/crypto/bytestring/bytestring_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_BYTESTRING_TEST_LIB_SRC))))
 
@@ -4387,6 +4644,7 @@
 LIBBORINGSSL_AEAD_TEST_LIB_SRC = \
     third_party/boringssl/crypto/cipher/aead_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_AEAD_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_AEAD_TEST_LIB_SRC))))
 
@@ -4424,6 +4682,7 @@
 LIBBORINGSSL_CIPHER_TEST_LIB_SRC = \
     third_party/boringssl/crypto/cipher/cipher_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_CIPHER_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_CIPHER_TEST_LIB_SRC))))
 
@@ -4461,6 +4720,7 @@
 LIBBORINGSSL_CMAC_TEST_LIB_SRC = \
     third_party/boringssl/crypto/cmac/cmac_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_CMAC_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_CMAC_TEST_LIB_SRC))))
 
@@ -4498,6 +4758,7 @@
 LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_SRC = \
     third_party/boringssl/crypto/constant_time_test.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_SRC))))
 
@@ -4524,6 +4785,7 @@
 LIBBORINGSSL_ED25519_TEST_LIB_SRC = \
     third_party/boringssl/crypto/curve25519/ed25519_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_ED25519_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_ED25519_TEST_LIB_SRC))))
 
@@ -4561,6 +4823,7 @@
 LIBBORINGSSL_X25519_TEST_LIB_SRC = \
     third_party/boringssl/crypto/curve25519/x25519_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_X25519_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_X25519_TEST_LIB_SRC))))
 
@@ -4598,6 +4861,7 @@
 LIBBORINGSSL_DH_TEST_LIB_SRC = \
     third_party/boringssl/crypto/dh/dh_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_DH_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_DH_TEST_LIB_SRC))))
 
@@ -4635,6 +4899,7 @@
 LIBBORINGSSL_DIGEST_TEST_LIB_SRC = \
     third_party/boringssl/crypto/digest/digest_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_DIGEST_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_DIGEST_TEST_LIB_SRC))))
 
@@ -4672,6 +4937,7 @@
 LIBBORINGSSL_DSA_TEST_LIB_SRC = \
     third_party/boringssl/crypto/dsa/dsa_test.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_DSA_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_DSA_TEST_LIB_SRC))))
 
@@ -4698,6 +4964,7 @@
 LIBBORINGSSL_EC_TEST_LIB_SRC = \
     third_party/boringssl/crypto/ec/ec_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_EC_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_EC_TEST_LIB_SRC))))
 
@@ -4735,6 +5002,7 @@
 LIBBORINGSSL_EXAMPLE_MUL_LIB_SRC = \
     third_party/boringssl/crypto/ec/example_mul.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_EXAMPLE_MUL_LIB_SRC))))
 
@@ -4761,6 +5029,7 @@
 LIBBORINGSSL_ECDSA_TEST_LIB_SRC = \
     third_party/boringssl/crypto/ecdsa/ecdsa_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_ECDSA_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_ECDSA_TEST_LIB_SRC))))
 
@@ -4798,6 +5067,7 @@
 LIBBORINGSSL_ERR_TEST_LIB_SRC = \
     third_party/boringssl/crypto/err/err_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_ERR_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_ERR_TEST_LIB_SRC))))
 
@@ -4835,6 +5105,7 @@
 LIBBORINGSSL_EVP_EXTRA_TEST_LIB_SRC = \
     third_party/boringssl/crypto/evp/evp_extra_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_SRC))))
 
@@ -4872,6 +5143,7 @@
 LIBBORINGSSL_EVP_TEST_LIB_SRC = \
     third_party/boringssl/crypto/evp/evp_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_EVP_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_EVP_TEST_LIB_SRC))))
 
@@ -4909,6 +5181,7 @@
 LIBBORINGSSL_PBKDF_TEST_LIB_SRC = \
     third_party/boringssl/crypto/evp/pbkdf_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_PBKDF_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_PBKDF_TEST_LIB_SRC))))
 
@@ -4946,6 +5219,7 @@
 LIBBORINGSSL_HKDF_TEST_LIB_SRC = \
     third_party/boringssl/crypto/hkdf/hkdf_test.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_HKDF_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_HKDF_TEST_LIB_SRC))))
 
@@ -4972,6 +5246,7 @@
 LIBBORINGSSL_HMAC_TEST_LIB_SRC = \
     third_party/boringssl/crypto/hmac/hmac_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_HMAC_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_HMAC_TEST_LIB_SRC))))
 
@@ -5009,6 +5284,7 @@
 LIBBORINGSSL_LHASH_TEST_LIB_SRC = \
     third_party/boringssl/crypto/lhash/lhash_test.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_LHASH_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_LHASH_TEST_LIB_SRC))))
 
@@ -5035,6 +5311,7 @@
 LIBBORINGSSL_GCM_TEST_LIB_SRC = \
     third_party/boringssl/crypto/modes/gcm_test.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_GCM_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_GCM_TEST_LIB_SRC))))
 
@@ -5061,6 +5338,7 @@
 LIBBORINGSSL_PKCS12_TEST_LIB_SRC = \
     third_party/boringssl/crypto/pkcs8/pkcs12_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_PKCS12_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_PKCS12_TEST_LIB_SRC))))
 
@@ -5098,6 +5376,7 @@
 LIBBORINGSSL_PKCS8_TEST_LIB_SRC = \
     third_party/boringssl/crypto/pkcs8/pkcs8_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_PKCS8_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_PKCS8_TEST_LIB_SRC))))
 
@@ -5135,6 +5414,7 @@
 LIBBORINGSSL_POLY1305_TEST_LIB_SRC = \
     third_party/boringssl/crypto/poly1305/poly1305_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_POLY1305_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_POLY1305_TEST_LIB_SRC))))
 
@@ -5172,6 +5452,7 @@
 LIBBORINGSSL_REFCOUNT_TEST_LIB_SRC = \
     third_party/boringssl/crypto/refcount_test.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_REFCOUNT_TEST_LIB_SRC))))
 
@@ -5198,6 +5479,7 @@
 LIBBORINGSSL_RSA_TEST_LIB_SRC = \
     third_party/boringssl/crypto/rsa/rsa_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_RSA_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_RSA_TEST_LIB_SRC))))
 
@@ -5235,6 +5517,7 @@
 LIBBORINGSSL_THREAD_TEST_LIB_SRC = \
     third_party/boringssl/crypto/thread_test.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_THREAD_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_THREAD_TEST_LIB_SRC))))
 
@@ -5261,6 +5544,7 @@
 LIBBORINGSSL_PKCS7_TEST_LIB_SRC = \
     third_party/boringssl/crypto/x509/pkcs7_test.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_PKCS7_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_PKCS7_TEST_LIB_SRC))))
 
@@ -5287,6 +5571,7 @@
 LIBBORINGSSL_TAB_TEST_LIB_SRC = \
     third_party/boringssl/crypto/x509v3/tab_test.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_TAB_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_TAB_TEST_LIB_SRC))))
 
@@ -5313,6 +5598,7 @@
 LIBBORINGSSL_V3NAME_TEST_LIB_SRC = \
     third_party/boringssl/crypto/x509v3/v3name_test.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_V3NAME_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_V3NAME_TEST_LIB_SRC))))
 
@@ -5339,6 +5625,7 @@
 LIBBORINGSSL_PQUEUE_TEST_LIB_SRC = \
     third_party/boringssl/ssl/pqueue/pqueue_test.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_PQUEUE_TEST_LIB_SRC))))
 
@@ -5365,6 +5652,7 @@
 LIBBORINGSSL_SSL_TEST_LIB_SRC = \
     third_party/boringssl/ssl/ssl_test.cc \
 
+PUBLIC_HEADERS_CXX += \
 
 LIBBORINGSSL_SSL_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_SSL_TEST_LIB_SRC))))
 
@@ -5416,6 +5704,7 @@
     third_party/zlib/uncompr.c \
     third_party/zlib/zutil.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBZ_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBZ_SRC))))
 
@@ -5441,6 +5730,7 @@
 LIBBAD_CLIENT_TEST_SRC = \
     test/core/bad_client/bad_client.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBAD_CLIENT_TEST_SRC))))
 
@@ -5479,6 +5769,7 @@
 LIBBAD_SSL_TEST_SERVER_SRC = \
     test/core/bad_ssl/server_common.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBBAD_SSL_TEST_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBAD_SSL_TEST_SERVER_SRC))))
 
@@ -5553,6 +5844,7 @@
     test/core/end2end/tests/simple_request.c \
     test/core/end2end/tests/trailing_metadata.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBEND2END_TESTS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBEND2END_TESTS_SRC))))
 
@@ -5626,6 +5918,7 @@
     test/core/end2end/tests/simple_request.c \
     test/core/end2end/tests/trailing_metadata.c \
 
+PUBLIC_HEADERS_C += \
 
 LIBEND2END_NOSEC_TESTS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBEND2END_NOSEC_TESTS_SRC))))
 
@@ -5647,46 +5940,6 @@
 endif
 
 
-LIBEND2END_CERTS_SRC = \
-    test/core/end2end/data/test_root_cert.c \
-    test/core/end2end/data/server1_cert.c \
-    test/core/end2end/data/server1_key.c \
-
-
-LIBEND2END_CERTS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBEND2END_CERTS_SRC))))
-
-
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure libraries if you don't have OpenSSL.
-
-$(LIBDIR)/$(CONFIG)/libend2end_certs.a: openssl_dep_error
-
-
-else
-
-
-$(LIBDIR)/$(CONFIG)/libend2end_certs.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBEND2END_CERTS_OBJS) 
-	$(E) "[AR]      Creating $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libend2end_certs.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBEND2END_CERTS_OBJS) 
-ifeq ($(SYSTEM),Darwin)
-	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libend2end_certs.a
-endif
-
-
-
-
-endif
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(LIBEND2END_CERTS_OBJS:.o=.dep)
-endif
-endif
-
-
 
 # All of the test targets, and protoc plugins
 
@@ -6075,6 +6328,70 @@
 endif
 
 
+CONCURRENT_CONNECTIVITY_TEST_SRC = \
+    test/core/surface/concurrent_connectivity_test.c \
+
+CONCURRENT_CONNECTIVITY_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CONCURRENT_CONNECTIVITY_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/concurrent_connectivity_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/concurrent_connectivity_test: $(CONCURRENT_CONNECTIVITY_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) $(CONCURRENT_CONNECTIVITY_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)/concurrent_connectivity_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/surface/concurrent_connectivity_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_concurrent_connectivity_test: $(CONCURRENT_CONNECTIVITY_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CONCURRENT_CONNECTIVITY_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+DNS_RESOLVER_CONNECTIVITY_TEST_SRC = \
+    test/core/client_config/resolvers/dns_resolver_connectivity_test.c \
+
+DNS_RESOLVER_CONNECTIVITY_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(DNS_RESOLVER_CONNECTIVITY_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test: $(DNS_RESOLVER_CONNECTIVITY_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) $(DNS_RESOLVER_CONNECTIVITY_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)/dns_resolver_connectivity_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/client_config/resolvers/dns_resolver_connectivity_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_dns_resolver_connectivity_test: $(DNS_RESOLVER_CONNECTIVITY_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(DNS_RESOLVER_CONNECTIVITY_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 DNS_RESOLVER_TEST_SRC = \
     test/core/client_config/resolvers/dns_resolver_test.c \
 
@@ -6459,6 +6776,38 @@
 endif
 
 
+GPR_BACKOFF_TEST_SRC = \
+    test/core/support/backoff_test.c \
+
+GPR_BACKOFF_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_BACKOFF_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/gpr_backoff_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/gpr_backoff_test: $(GPR_BACKOFF_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(GPR_BACKOFF_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_backoff_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/support/backoff_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_gpr_backoff_test: $(GPR_BACKOFF_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GPR_BACKOFF_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 GPR_CMDLINE_TEST_SRC = \
     test/core/support/cmdline_test.c \
 
@@ -7451,6 +7800,38 @@
 endif
 
 
+HPACK_PARSER_FUZZER_TEST_SRC = \
+    test/core/transport/chttp2/hpack_parser_fuzzer_test.c \
+
+HPACK_PARSER_FUZZER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HPACK_PARSER_FUZZER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/hpack_parser_fuzzer_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/hpack_parser_fuzzer_test: $(HPACK_PARSER_FUZZER_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) $(LDXX) $(LDFLAGS) $(HPACK_PARSER_FUZZER_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) -lFuzzer -o $(BINDIR)/$(CONFIG)/hpack_parser_fuzzer_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/transport/chttp2/hpack_parser_fuzzer_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_hpack_parser_fuzzer_test: $(HPACK_PARSER_FUZZER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(HPACK_PARSER_FUZZER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 HPACK_PARSER_TEST_SRC = \
     test/core/transport/chttp2/hpack_parser_test.c \
 
@@ -7515,8 +7896,72 @@
 endif
 
 
+HTTP_FUZZER_TEST_SRC = \
+    test/core/http/fuzzer.c \
+
+HTTP_FUZZER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HTTP_FUZZER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/http_fuzzer_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/http_fuzzer_test: $(HTTP_FUZZER_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) $(LDXX) $(LDFLAGS) $(HTTP_FUZZER_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) -lFuzzer -o $(BINDIR)/$(CONFIG)/http_fuzzer_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/http/fuzzer.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_http_fuzzer_test: $(HTTP_FUZZER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(HTTP_FUZZER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+HTTP_PARSER_TEST_SRC = \
+    test/core/http/parser_test.c \
+
+HTTP_PARSER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HTTP_PARSER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/http_parser_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/http_parser_test: $(HTTP_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) $(HTTP_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)/http_parser_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/http/parser_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_http_parser_test: $(HTTP_PARSER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(HTTP_PARSER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 HTTPCLI_FORMAT_REQUEST_TEST_SRC = \
-    test/core/httpcli/format_request_test.c \
+    test/core/http/format_request_test.c \
 
 HTTPCLI_FORMAT_REQUEST_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HTTPCLI_FORMAT_REQUEST_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
@@ -7536,7 +7981,7 @@
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/httpcli/format_request_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/http/format_request_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_httpcli_format_request_test: $(HTTPCLI_FORMAT_REQUEST_TEST_OBJS:.o=.dep)
 
@@ -7547,40 +7992,8 @@
 endif
 
 
-HTTPCLI_PARSER_TEST_SRC = \
-    test/core/httpcli/parser_test.c \
-
-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.
-
-$(BINDIR)/$(CONFIG)/httpcli_parser_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/httpcli_parser_test: $(HTTPCLI_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) $(HTTPCLI_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)/httpcli_parser_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/httpcli/parser_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_httpcli_parser_test: $(HTTPCLI_PARSER_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(HTTPCLI_PARSER_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 HTTPCLI_TEST_SRC = \
-    test/core/httpcli/httpcli_test.c \
+    test/core/http/httpcli_test.c \
 
 HTTPCLI_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HTTPCLI_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
@@ -7600,7 +8013,7 @@
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/httpcli/httpcli_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/http/httpcli_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_httpcli_test: $(HTTPCLI_TEST_OBJS:.o=.dep)
 
@@ -7612,7 +8025,7 @@
 
 
 HTTPSCLI_TEST_SRC = \
-    test/core/httpcli/httpscli_test.c \
+    test/core/http/httpscli_test.c \
 
 HTTPSCLI_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HTTPSCLI_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
@@ -7632,7 +8045,7 @@
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/httpcli/httpscli_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/http/httpscli_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_httpscli_test: $(HTTPSCLI_TEST_OBJS:.o=.dep)
 
@@ -7707,6 +8120,38 @@
 endif
 
 
+JSON_FUZZER_TEST_SRC = \
+    test/core/json/fuzzer.c \
+
+JSON_FUZZER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(JSON_FUZZER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/json_fuzzer_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/json_fuzzer_test: $(JSON_FUZZER_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) $(LDXX) $(LDFLAGS) $(JSON_FUZZER_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) -lFuzzer -o $(BINDIR)/$(CONFIG)/json_fuzzer_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/json/fuzzer.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_json_fuzzer_test: $(JSON_FUZZER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(JSON_FUZZER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 JSON_REWRITE_SRC = \
     test/core/json/json_rewrite.c \
 
@@ -8763,6 +9208,38 @@
 endif
 
 
+URI_FUZZER_TEST_SRC = \
+    test/core/client_config/uri_fuzzer_test.c \
+
+URI_FUZZER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(URI_FUZZER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/uri_fuzzer_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/uri_fuzzer_test: $(URI_FUZZER_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) $(LDXX) $(LDFLAGS) $(URI_FUZZER_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) -lFuzzer -o $(BINDIR)/$(CONFIG)/uri_fuzzer_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/client_config/uri_fuzzer_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_uri_fuzzer_test: $(URI_FUZZER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(URI_FUZZER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 URI_PARSER_TEST_SRC = \
     test/core/client_config/uri_parser_test.c \
 
@@ -9214,6 +9691,68 @@
 endif
 
 
+CODEGEN_TEST_SRC = \
+    $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc \
+    test/cpp/codegen/codegen_test.cc \
+
+CODEGEN_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CODEGEN_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/codegen_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)/codegen_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/codegen_test: $(PROTOBUF_DEP) $(CODEGEN_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(CODEGEN_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/codegen_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/control.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/messages.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/payloads.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/perf_db.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/services.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/stats.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/codegen/codegen_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_codegen_lib.a
+
+deps_codegen_test: $(CODEGEN_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CODEGEN_TEST_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/test/cpp/codegen/codegen_test.o: $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
+
+
 CREDENTIALS_TEST_SRC = \
     test/cpp/client/credentials_test.cc \
 
@@ -10974,6 +11513,33 @@
 # boringssl needs an override to ensure that it does not include
 # system openssl headers regardless of other configuration
 # we do so here with a target specific variable assignment
+$(BORINGSSL_ASN1_TEST_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value
+$(BORINGSSL_ASN1_TEST_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS)
+$(BORINGSSL_ASN1_TEST_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+
+
+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)/boringssl_asn1_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/boringssl_asn1_test:  $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/boringssl_asn1_test
+
+endif
+
+
+
+
+
+# boringssl needs an override to ensure that it does not include
+# system openssl headers regardless of other configuration
+# we do so here with a target specific variable assignment
 $(BORINGSSL_BASE64_TEST_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value
 $(BORINGSSL_BASE64_TEST_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS)
 $(BORINGSSL_BASE64_TEST_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
@@ -12217,14 +12783,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_census_test: $(H2_CENSUS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_census_test: $(H2_CENSUS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_CENSUS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_census_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_CENSUS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_census_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_census.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_census.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_census_test: $(H2_CENSUS_TEST_OBJS:.o=.dep)
 
@@ -12249,14 +12815,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_compress_test: $(H2_COMPRESS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_compress_test: $(H2_COMPRESS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_COMPRESS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_compress_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_COMPRESS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_compress_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_compress.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_compress.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_compress_test: $(H2_COMPRESS_TEST_OBJS:.o=.dep)
 
@@ -12281,14 +12847,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_fakesec_test: $(H2_FAKESEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_fakesec_test: $(H2_FAKESEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_FAKESEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_fakesec_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_FAKESEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_fakesec_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_fakesec.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_fakesec.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_fakesec_test: $(H2_FAKESEC_TEST_OBJS:.o=.dep)
 
@@ -12313,14 +12879,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_full_test: $(H2_FULL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_full_test: $(H2_FULL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_FULL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_full_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_FULL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_full_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_full.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_full.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_full_test: $(H2_FULL_TEST_OBJS:.o=.dep)
 
@@ -12345,14 +12911,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_full+pipe_test: $(H2_FULL+PIPE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_full+pipe_test: $(H2_FULL+PIPE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_FULL+PIPE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_full+pipe_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_FULL+PIPE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_full+pipe_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_full+pipe.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_full+pipe.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_full+pipe_test: $(H2_FULL+PIPE_TEST_OBJS:.o=.dep)
 
@@ -12377,14 +12943,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_full+poll_test: $(H2_FULL+POLL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_full+poll_test: $(H2_FULL+POLL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_FULL+POLL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_full+poll_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_FULL+POLL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_full+poll_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_full+poll.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_full+poll.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_full+poll_test: $(H2_FULL+POLL_TEST_OBJS:.o=.dep)
 
@@ -12409,14 +12975,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_full+poll+pipe_test: $(H2_FULL+POLL+PIPE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_full+poll+pipe_test: $(H2_FULL+POLL+PIPE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_FULL+POLL+PIPE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_full+poll+pipe_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_FULL+POLL+PIPE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_full+poll+pipe_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_full+poll+pipe.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_full+poll+pipe.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_full+poll+pipe_test: $(H2_FULL+POLL+PIPE_TEST_OBJS:.o=.dep)
 
@@ -12427,6 +12993,38 @@
 endif
 
 
+H2_FULL+TRACE_TEST_SRC = \
+    test/core/end2end/fixtures/h2_full+trace.c \
+
+H2_FULL+TRACE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_FULL+TRACE_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/h2_full+trace_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/h2_full+trace_test: $(H2_FULL+TRACE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_FULL+TRACE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_full+trace_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_full+trace.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_h2_full+trace_test: $(H2_FULL+TRACE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(H2_FULL+TRACE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 H2_OAUTH2_TEST_SRC = \
     test/core/end2end/fixtures/h2_oauth2.c \
 
@@ -12441,14 +13039,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_oauth2_test: $(H2_OAUTH2_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_oauth2_test: $(H2_OAUTH2_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_OAUTH2_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_oauth2_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_OAUTH2_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_oauth2_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_oauth2.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_oauth2.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_oauth2_test: $(H2_OAUTH2_TEST_OBJS:.o=.dep)
 
@@ -12473,14 +13071,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_proxy_test: $(H2_PROXY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_proxy_test: $(H2_PROXY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_PROXY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_proxy_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_PROXY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_proxy_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_proxy.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_proxy.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_proxy_test: $(H2_PROXY_TEST_OBJS:.o=.dep)
 
@@ -12505,14 +13103,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_sockpair_test: $(H2_SOCKPAIR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_sockpair_test: $(H2_SOCKPAIR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_SOCKPAIR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_sockpair_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_SOCKPAIR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_sockpair_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_sockpair.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_sockpair.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_sockpair_test: $(H2_SOCKPAIR_TEST_OBJS:.o=.dep)
 
@@ -12537,14 +13135,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_sockpair+trace_test: $(H2_SOCKPAIR+TRACE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_sockpair+trace_test: $(H2_SOCKPAIR+TRACE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_SOCKPAIR+TRACE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_sockpair+trace_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_SOCKPAIR+TRACE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_sockpair+trace_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_sockpair+trace.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_sockpair+trace.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_sockpair+trace_test: $(H2_SOCKPAIR+TRACE_TEST_OBJS:.o=.dep)
 
@@ -12569,14 +13167,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_sockpair_1byte_test: $(H2_SOCKPAIR_1BYTE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_sockpair_1byte_test: $(H2_SOCKPAIR_1BYTE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_SOCKPAIR_1BYTE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_sockpair_1byte_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_SOCKPAIR_1BYTE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_sockpair_1byte_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_sockpair_1byte.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_sockpair_1byte.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_sockpair_1byte_test: $(H2_SOCKPAIR_1BYTE_TEST_OBJS:.o=.dep)
 
@@ -12601,14 +13199,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_ssl_test: $(H2_SSL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_ssl_test: $(H2_SSL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_SSL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_ssl_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_SSL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_ssl_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_ssl.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_ssl.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_ssl_test: $(H2_SSL_TEST_OBJS:.o=.dep)
 
@@ -12633,14 +13231,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_ssl+poll_test: $(H2_SSL+POLL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_ssl+poll_test: $(H2_SSL+POLL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_SSL+POLL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_ssl+poll_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_SSL+POLL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_ssl+poll_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_ssl+poll.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_ssl+poll.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_ssl+poll_test: $(H2_SSL+POLL_TEST_OBJS:.o=.dep)
 
@@ -12665,14 +13263,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_ssl_proxy_test: $(H2_SSL_PROXY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_ssl_proxy_test: $(H2_SSL_PROXY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_SSL_PROXY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_ssl_proxy_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_SSL_PROXY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_ssl_proxy_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_ssl_proxy.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_ssl_proxy.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_ssl_proxy_test: $(H2_SSL_PROXY_TEST_OBJS:.o=.dep)
 
@@ -12683,38 +13281,6 @@
 endif
 
 
-H2_UCHANNEL_TEST_SRC = \
-    test/core/end2end/fixtures/h2_uchannel.c \
-
-H2_UCHANNEL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_UCHANNEL_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/h2_uchannel_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/h2_uchannel_test: $(H2_UCHANNEL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_UCHANNEL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_uchannel_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_uchannel.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
-
-deps_h2_uchannel_test: $(H2_UCHANNEL_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(H2_UCHANNEL_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 H2_UDS_TEST_SRC = \
     test/core/end2end/fixtures/h2_uds.c \
 
@@ -12729,14 +13295,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_uds_test: $(H2_UDS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_uds_test: $(H2_UDS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_UDS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_uds_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_UDS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_uds_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_uds.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_uds.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_uds_test: $(H2_UDS_TEST_OBJS:.o=.dep)
 
@@ -12761,14 +13327,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/h2_uds+poll_test: $(H2_UDS+POLL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(BINDIR)/$(CONFIG)/h2_uds+poll_test: $(H2_UDS+POLL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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) $(H2_UDS+POLL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_uds+poll_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_UDS+POLL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.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)/h2_uds+poll_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_uds+poll.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.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
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_uds+poll.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_h2_uds+poll_test: $(H2_UDS+POLL_TEST_OBJS:.o=.dep)
 
@@ -12899,6 +13465,26 @@
 endif
 
 
+H2_FULL+TRACE_NOSEC_TEST_SRC = \
+    test/core/end2end/fixtures/h2_full+trace.c \
+
+H2_FULL+TRACE_NOSEC_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_FULL+TRACE_NOSEC_TEST_SRC))))
+
+
+$(BINDIR)/$(CONFIG)/h2_full+trace_nosec_test: $(H2_FULL+TRACE_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.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) $(H2_FULL+TRACE_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.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)/h2_full+trace_nosec_test
+
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_full+trace.o:  $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_h2_full+trace_nosec_test: $(H2_FULL+TRACE_NOSEC_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_DEPS),true)
+-include $(H2_FULL+TRACE_NOSEC_TEST_OBJS:.o=.dep)
+endif
+
+
 H2_PROXY_NOSEC_TEST_SRC = \
     test/core/end2end/fixtures/h2_proxy.c \
 
@@ -12979,26 +13565,6 @@
 endif
 
 
-H2_UCHANNEL_NOSEC_TEST_SRC = \
-    test/core/end2end/fixtures/h2_uchannel.c \
-
-H2_UCHANNEL_NOSEC_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_UCHANNEL_NOSEC_TEST_SRC))))
-
-
-$(BINDIR)/$(CONFIG)/h2_uchannel_nosec_test: $(H2_UCHANNEL_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.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) $(H2_UCHANNEL_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.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)/h2_uchannel_nosec_test
-
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_uchannel.o:  $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_h2_uchannel_nosec_test: $(H2_UCHANNEL_NOSEC_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_DEPS),true)
--include $(H2_UCHANNEL_NOSEC_TEST_OBJS:.o=.dep)
-endif
-
-
 H2_UDS_NOSEC_TEST_SRC = \
     test/core/end2end/fixtures/h2_uds.c \
 
@@ -13047,27 +13613,27 @@
 # This is to ensure the embedded OpenSSL is built beforehand, properly
 # installing headers to their final destination on the drive. We need this
 # otherwise parallel compilation will fail if a source is compiled first.
-src/core/httpcli/httpcli_security_connector.c: $(OPENSSL_DEP)
-src/core/security/b64.c: $(OPENSSL_DEP)
-src/core/security/client_auth_filter.c: $(OPENSSL_DEP)
-src/core/security/credentials.c: $(OPENSSL_DEP)
-src/core/security/credentials_metadata.c: $(OPENSSL_DEP)
-src/core/security/credentials_posix.c: $(OPENSSL_DEP)
-src/core/security/credentials_win32.c: $(OPENSSL_DEP)
-src/core/security/google_default_credentials.c: $(OPENSSL_DEP)
-src/core/security/handshake.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/security_connector.c: $(OPENSSL_DEP)
-src/core/security/security_context.c: $(OPENSSL_DEP)
-src/core/security/server_auth_filter.c: $(OPENSSL_DEP)
-src/core/security/server_secure_chttp2.c: $(OPENSSL_DEP)
-src/core/surface/init_secure.c: $(OPENSSL_DEP)
-src/core/surface/secure_channel_create.c: $(OPENSSL_DEP)
-src/core/tsi/fake_transport_security.c: $(OPENSSL_DEP)
-src/core/tsi/ssl_transport_security.c: $(OPENSSL_DEP)
-src/core/tsi/transport_security.c: $(OPENSSL_DEP)
+src/core/ext/transport/chttp2/client/secure/secure_channel_create.c: $(OPENSSL_DEP)
+src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c: $(OPENSSL_DEP)
+src/core/lib/http/httpcli_security_connector.c: $(OPENSSL_DEP)
+src/core/lib/security/b64.c: $(OPENSSL_DEP)
+src/core/lib/security/client_auth_filter.c: $(OPENSSL_DEP)
+src/core/lib/security/credentials.c: $(OPENSSL_DEP)
+src/core/lib/security/credentials_metadata.c: $(OPENSSL_DEP)
+src/core/lib/security/credentials_posix.c: $(OPENSSL_DEP)
+src/core/lib/security/credentials_win32.c: $(OPENSSL_DEP)
+src/core/lib/security/google_default_credentials.c: $(OPENSSL_DEP)
+src/core/lib/security/handshake.c: $(OPENSSL_DEP)
+src/core/lib/security/json_token.c: $(OPENSSL_DEP)
+src/core/lib/security/jwt_verifier.c: $(OPENSSL_DEP)
+src/core/lib/security/secure_endpoint.c: $(OPENSSL_DEP)
+src/core/lib/security/security_connector.c: $(OPENSSL_DEP)
+src/core/lib/security/security_context.c: $(OPENSSL_DEP)
+src/core/lib/security/server_auth_filter.c: $(OPENSSL_DEP)
+src/core/lib/surface/init_secure.c: $(OPENSSL_DEP)
+src/core/lib/tsi/fake_transport_security.c: $(OPENSSL_DEP)
+src/core/lib/tsi/ssl_transport_security.c: $(OPENSSL_DEP)
+src/core/lib/tsi/transport_security.c: $(OPENSSL_DEP)
 src/cpp/client/secure_credentials.cc: $(OPENSSL_DEP)
 src/cpp/common/auth_property_iterator.cc: $(OPENSSL_DEP)
 src/cpp/common/secure_auth_context.cc: $(OPENSSL_DEP)
diff --git a/binding.gyp b/binding.gyp
index d1e086c..a1cdf2e 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -492,49 +492,50 @@
       'dependencies': [
       ],
       'sources': [
-        'src/core/profiling/basic_timers.c',
-        'src/core/profiling/stap_timers.c',
-        'src/core/support/alloc.c',
-        'src/core/support/avl.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/histogram.c',
-        'src/core/support/host_port.c',
-        'src/core/support/load_file.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/subprocess_windows.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_precise.c',
-        'src/core/support/time_win32.c',
-        'src/core/support/tls_pthread.c',
-        'src/core/support/tmpfile_posix.c',
-        'src/core/support/tmpfile_win32.c',
-        'src/core/support/wrap_memcpy.c',
+        'src/core/lib/profiling/basic_timers.c',
+        'src/core/lib/profiling/stap_timers.c',
+        'src/core/lib/support/alloc.c',
+        'src/core/lib/support/avl.c',
+        'src/core/lib/support/backoff.c',
+        'src/core/lib/support/cmdline.c',
+        'src/core/lib/support/cpu_iphone.c',
+        'src/core/lib/support/cpu_linux.c',
+        'src/core/lib/support/cpu_posix.c',
+        'src/core/lib/support/cpu_windows.c',
+        'src/core/lib/support/env_linux.c',
+        'src/core/lib/support/env_posix.c',
+        'src/core/lib/support/env_win32.c',
+        'src/core/lib/support/histogram.c',
+        'src/core/lib/support/host_port.c',
+        'src/core/lib/support/load_file.c',
+        'src/core/lib/support/log.c',
+        'src/core/lib/support/log_android.c',
+        'src/core/lib/support/log_linux.c',
+        'src/core/lib/support/log_posix.c',
+        'src/core/lib/support/log_win32.c',
+        'src/core/lib/support/murmur_hash.c',
+        'src/core/lib/support/slice.c',
+        'src/core/lib/support/slice_buffer.c',
+        'src/core/lib/support/stack_lockfree.c',
+        'src/core/lib/support/string.c',
+        'src/core/lib/support/string_posix.c',
+        'src/core/lib/support/string_win32.c',
+        'src/core/lib/support/subprocess_posix.c',
+        'src/core/lib/support/subprocess_windows.c',
+        'src/core/lib/support/sync.c',
+        'src/core/lib/support/sync_posix.c',
+        'src/core/lib/support/sync_win32.c',
+        'src/core/lib/support/thd.c',
+        'src/core/lib/support/thd_posix.c',
+        'src/core/lib/support/thd_win32.c',
+        'src/core/lib/support/time.c',
+        'src/core/lib/support/time_posix.c',
+        'src/core/lib/support/time_precise.c',
+        'src/core/lib/support/time_win32.c',
+        'src/core/lib/support/tls_pthread.c',
+        'src/core/lib/support/tmpfile_posix.c',
+        'src/core/lib/support/tmpfile_win32.c',
+        'src/core/lib/support/wrap_memcpy.c',
       ],
       "conditions": [
         ['OS == "mac"', {
@@ -557,163 +558,167 @@
         'gpr',
       ],
       'sources': [
-        'src/core/census/grpc_context.c',
-        'src/core/census/grpc_filter.c',
-        'src/core/channel/channel_args.c',
-        'src/core/channel/channel_stack.c',
-        'src/core/channel/client_channel.c',
-        'src/core/channel/client_uchannel.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/subchannel_call_holder.c',
-        'src/core/client_config/client_config.c',
-        'src/core/client_config/connector.c',
-        'src/core/client_config/default_initial_connect_string.c',
-        'src/core/client_config/initial_connect_string.c',
-        'src/core/client_config/lb_policies/load_balancer_api.c',
-        'src/core/client_config/lb_policies/pick_first.c',
-        'src/core/client_config/lb_policies/round_robin.c',
-        'src/core/client_config/lb_policy.c',
-        'src/core/client_config/lb_policy_factory.c',
-        'src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c',
-        'src/core/client_config/subchannel.c',
-        'src/core/client_config/subchannel_factory.c',
-        'src/core/client_config/subchannel_index.c',
-        'src/core/client_config/uri_parser.c',
-        'src/core/compression/compression_algorithm.c',
-        'src/core/compression/message_compress.c',
-        'src/core/debug/trace.c',
-        'src/core/httpcli/format_request.c',
-        'src/core/httpcli/httpcli.c',
-        'src/core/httpcli/parser.c',
-        'src/core/iomgr/closure.c',
-        'src/core/iomgr/endpoint.c',
-        'src/core/iomgr/endpoint_pair_posix.c',
-        'src/core/iomgr/endpoint_pair_windows.c',
-        'src/core/iomgr/exec_ctx.c',
-        'src/core/iomgr/executor.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_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/timer.c',
-        'src/core/iomgr/timer_heap.c',
-        'src/core/iomgr/udp_server.c',
-        'src/core/iomgr/wakeup_fd_eventfd.c',
-        'src/core/iomgr/wakeup_fd_nospecial.c',
-        'src/core/iomgr/wakeup_fd_pipe.c',
-        'src/core/iomgr/wakeup_fd_posix.c',
-        'src/core/iomgr/workqueue_posix.c',
-        'src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c',
-        'src/core/surface/alarm.c',
-        'src/core/surface/api_trace.c',
-        'src/core/surface/byte_buffer.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_connectivity.c',
-        'src/core/surface/channel_create.c',
-        'src/core/surface/channel_ping.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/validate_metadata.c',
-        'src/core/surface/version.c',
-        'src/core/transport/byte_stream.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_encoder.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_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/metadata_batch.c',
-        'src/core/transport/static_metadata.c',
-        'src/core/transport/transport.c',
-        'src/core/transport/transport_op_string.c',
-        'src/core/httpcli/httpcli_security_connector.c',
-        'src/core/security/b64.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/handshake.c',
-        'src/core/security/json_token.c',
-        'src/core/security/jwt_verifier.c',
-        'src/core/security/secure_endpoint.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/context.c',
-        'src/core/census/initialize.c',
-        'src/core/census/mlog.c',
-        'src/core/census/operation.c',
-        'src/core/census/placeholders.c',
-        'src/core/census/tracing.c',
+        'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
+        'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
+        'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
+        'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c',
+        'src/core/ext/transport/chttp2/transport/alpn.c',
+        'src/core/ext/transport/chttp2/transport/bin_encoder.c',
+        'src/core/ext/transport/chttp2/transport/chttp2_transport.c',
+        'src/core/ext/transport/chttp2/transport/frame_data.c',
+        'src/core/ext/transport/chttp2/transport/frame_goaway.c',
+        'src/core/ext/transport/chttp2/transport/frame_ping.c',
+        'src/core/ext/transport/chttp2/transport/frame_rst_stream.c',
+        'src/core/ext/transport/chttp2/transport/frame_settings.c',
+        'src/core/ext/transport/chttp2/transport/frame_window_update.c',
+        'src/core/ext/transport/chttp2/transport/hpack_encoder.c',
+        'src/core/ext/transport/chttp2/transport/hpack_parser.c',
+        'src/core/ext/transport/chttp2/transport/hpack_table.c',
+        'src/core/ext/transport/chttp2/transport/huffsyms.c',
+        'src/core/ext/transport/chttp2/transport/incoming_metadata.c',
+        'src/core/ext/transport/chttp2/transport/parsing.c',
+        'src/core/ext/transport/chttp2/transport/status_conversion.c',
+        'src/core/ext/transport/chttp2/transport/stream_lists.c',
+        'src/core/ext/transport/chttp2/transport/stream_map.c',
+        'src/core/ext/transport/chttp2/transport/timeout_encoding.c',
+        'src/core/ext/transport/chttp2/transport/varint.c',
+        'src/core/ext/transport/chttp2/transport/writing.c',
+        'src/core/lib/census/context.c',
+        'src/core/lib/census/grpc_context.c',
+        'src/core/lib/census/grpc_filter.c',
+        'src/core/lib/census/grpc_plugin.c',
+        'src/core/lib/census/initialize.c',
+        'src/core/lib/census/mlog.c',
+        'src/core/lib/census/operation.c',
+        'src/core/lib/census/placeholders.c',
+        'src/core/lib/census/tracing.c',
+        'src/core/lib/channel/channel_args.c',
+        'src/core/lib/channel/channel_stack.c',
+        'src/core/lib/channel/channel_stack_builder.c',
+        'src/core/lib/channel/client_channel.c',
+        'src/core/lib/channel/compress_filter.c',
+        'src/core/lib/channel/connected_channel.c',
+        'src/core/lib/channel/http_client_filter.c',
+        'src/core/lib/channel/http_server_filter.c',
+        'src/core/lib/channel/subchannel_call_holder.c',
+        'src/core/lib/client_config/client_config.c',
+        'src/core/lib/client_config/connector.c',
+        'src/core/lib/client_config/default_initial_connect_string.c',
+        'src/core/lib/client_config/initial_connect_string.c',
+        'src/core/lib/client_config/lb_policies/load_balancer_api.c',
+        'src/core/lib/client_config/lb_policies/pick_first.c',
+        'src/core/lib/client_config/lb_policies/round_robin.c',
+        'src/core/lib/client_config/lb_policy.c',
+        'src/core/lib/client_config/lb_policy_factory.c',
+        'src/core/lib/client_config/lb_policy_registry.c',
+        'src/core/lib/client_config/resolver.c',
+        'src/core/lib/client_config/resolver_factory.c',
+        'src/core/lib/client_config/resolver_registry.c',
+        'src/core/lib/client_config/resolvers/dns_resolver.c',
+        'src/core/lib/client_config/resolvers/sockaddr_resolver.c',
+        'src/core/lib/client_config/subchannel.c',
+        'src/core/lib/client_config/subchannel_factory.c',
+        'src/core/lib/client_config/subchannel_index.c',
+        'src/core/lib/client_config/uri_parser.c',
+        'src/core/lib/compression/compression_algorithm.c',
+        'src/core/lib/compression/message_compress.c',
+        'src/core/lib/debug/trace.c',
+        'src/core/lib/http/format_request.c',
+        'src/core/lib/http/httpcli.c',
+        'src/core/lib/http/httpcli_security_connector.c',
+        'src/core/lib/http/parser.c',
+        'src/core/lib/iomgr/closure.c',
+        'src/core/lib/iomgr/endpoint.c',
+        'src/core/lib/iomgr/endpoint_pair_posix.c',
+        'src/core/lib/iomgr/endpoint_pair_windows.c',
+        'src/core/lib/iomgr/exec_ctx.c',
+        'src/core/lib/iomgr/executor.c',
+        'src/core/lib/iomgr/fd_posix.c',
+        'src/core/lib/iomgr/iocp_windows.c',
+        'src/core/lib/iomgr/iomgr.c',
+        'src/core/lib/iomgr/iomgr_posix.c',
+        'src/core/lib/iomgr/iomgr_windows.c',
+        'src/core/lib/iomgr/pollset_multipoller_with_epoll.c',
+        'src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c',
+        'src/core/lib/iomgr/pollset_posix.c',
+        'src/core/lib/iomgr/pollset_set_posix.c',
+        'src/core/lib/iomgr/pollset_set_windows.c',
+        'src/core/lib/iomgr/pollset_windows.c',
+        'src/core/lib/iomgr/resolve_address_posix.c',
+        'src/core/lib/iomgr/resolve_address_windows.c',
+        'src/core/lib/iomgr/sockaddr_utils.c',
+        'src/core/lib/iomgr/socket_utils_common_posix.c',
+        'src/core/lib/iomgr/socket_utils_linux.c',
+        'src/core/lib/iomgr/socket_utils_posix.c',
+        'src/core/lib/iomgr/socket_windows.c',
+        'src/core/lib/iomgr/tcp_client_posix.c',
+        'src/core/lib/iomgr/tcp_client_windows.c',
+        'src/core/lib/iomgr/tcp_posix.c',
+        'src/core/lib/iomgr/tcp_server_posix.c',
+        'src/core/lib/iomgr/tcp_server_windows.c',
+        'src/core/lib/iomgr/tcp_windows.c',
+        'src/core/lib/iomgr/time_averaged_stats.c',
+        'src/core/lib/iomgr/timer.c',
+        'src/core/lib/iomgr/timer_heap.c',
+        'src/core/lib/iomgr/udp_server.c',
+        'src/core/lib/iomgr/unix_sockets_posix.c',
+        'src/core/lib/iomgr/unix_sockets_posix_noop.c',
+        'src/core/lib/iomgr/wakeup_fd_eventfd.c',
+        'src/core/lib/iomgr/wakeup_fd_nospecial.c',
+        'src/core/lib/iomgr/wakeup_fd_pipe.c',
+        'src/core/lib/iomgr/wakeup_fd_posix.c',
+        'src/core/lib/iomgr/workqueue_posix.c',
+        'src/core/lib/iomgr/workqueue_windows.c',
+        'src/core/lib/json/json.c',
+        'src/core/lib/json/json_reader.c',
+        'src/core/lib/json/json_string.c',
+        'src/core/lib/json/json_writer.c',
+        'src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c',
+        'src/core/lib/security/b64.c',
+        'src/core/lib/security/client_auth_filter.c',
+        'src/core/lib/security/credentials.c',
+        'src/core/lib/security/credentials_metadata.c',
+        'src/core/lib/security/credentials_posix.c',
+        'src/core/lib/security/credentials_win32.c',
+        'src/core/lib/security/google_default_credentials.c',
+        'src/core/lib/security/handshake.c',
+        'src/core/lib/security/json_token.c',
+        'src/core/lib/security/jwt_verifier.c',
+        'src/core/lib/security/secure_endpoint.c',
+        'src/core/lib/security/security_connector.c',
+        'src/core/lib/security/security_context.c',
+        'src/core/lib/security/server_auth_filter.c',
+        'src/core/lib/surface/alarm.c',
+        'src/core/lib/surface/api_trace.c',
+        'src/core/lib/surface/byte_buffer.c',
+        'src/core/lib/surface/byte_buffer_reader.c',
+        'src/core/lib/surface/call.c',
+        'src/core/lib/surface/call_details.c',
+        'src/core/lib/surface/call_log_batch.c',
+        'src/core/lib/surface/channel.c',
+        'src/core/lib/surface/channel_connectivity.c',
+        'src/core/lib/surface/channel_init.c',
+        'src/core/lib/surface/channel_ping.c',
+        'src/core/lib/surface/channel_stack_type.c',
+        'src/core/lib/surface/completion_queue.c',
+        'src/core/lib/surface/event_string.c',
+        'src/core/lib/surface/init.c',
+        'src/core/lib/surface/init_secure.c',
+        'src/core/lib/surface/lame_client.c',
+        'src/core/lib/surface/metadata_array.c',
+        'src/core/lib/surface/server.c',
+        'src/core/lib/surface/validate_metadata.c',
+        'src/core/lib/surface/version.c',
+        'src/core/lib/transport/byte_stream.c',
+        'src/core/lib/transport/connectivity_state.c',
+        'src/core/lib/transport/metadata.c',
+        'src/core/lib/transport/metadata_batch.c',
+        'src/core/lib/transport/static_metadata.c',
+        'src/core/lib/transport/transport.c',
+        'src/core/lib/transport/transport_op_string.c',
+        'src/core/lib/tsi/fake_transport_security.c',
+        'src/core/lib/tsi/ssl_transport_security.c',
+        'src/core/lib/tsi/transport_security.c',
         'third_party/nanopb/pb_common.c',
         'third_party/nanopb/pb_decode.c',
         'third_party/nanopb/pb_encode.c',
diff --git a/build.yaml b/build.yaml
index eaaa622..43d3c68 100644
--- a/build.yaml
+++ b/build.yaml
@@ -7,22 +7,22 @@
   '#3': Use "-preN" suffixes to identify pre-release versions
   '#4': Per-language overrides are possible with (eg) ruby_version tag here
   '#5': See the expand_version.py for all the quirks here
-  version: 0.13.1-pre1
+  version: 0.14.0-dev
 filegroups:
 - name: census
   public_headers:
   - include/grpc/census.h
   headers:
-  - src/core/census/aggregation.h
-  - src/core/census/mlog.h
-  - src/core/census/rpc_metric_id.h
+  - src/core/lib/census/aggregation.h
+  - src/core/lib/census/mlog.h
+  - src/core/lib/census/rpc_metric_id.h
   src:
-  - src/core/census/context.c
-  - src/core/census/initialize.c
-  - src/core/census/mlog.c
-  - src/core/census/operation.c
-  - src/core/census/placeholders.c
-  - src/core/census/tracing.c
+  - src/core/lib/census/context.c
+  - src/core/lib/census/initialize.c
+  - src/core/lib/census/mlog.c
+  - src/core/lib/census/operation.c
+  - src/core/lib/census/placeholders.c
+  - src/core/lib/census/tracing.c
 - name: gpr
   public_headers:
   - include/grpc/support/alloc.h
@@ -54,61 +54,63 @@
   - include/grpc/support/tls_pthread.h
   - include/grpc/support/useful.h
   headers:
-  - src/core/profiling/timers.h
-  - src/core/support/block_annotate.h
-  - src/core/support/env.h
-  - src/core/support/load_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/time_precise.h
-  - src/core/support/tmpfile.h
+  - src/core/lib/profiling/timers.h
+  - src/core/lib/support/backoff.h
+  - src/core/lib/support/block_annotate.h
+  - src/core/lib/support/env.h
+  - src/core/lib/support/load_file.h
+  - src/core/lib/support/murmur_hash.h
+  - src/core/lib/support/stack_lockfree.h
+  - src/core/lib/support/string.h
+  - src/core/lib/support/string_win32.h
+  - src/core/lib/support/thd_internal.h
+  - src/core/lib/support/time_precise.h
+  - src/core/lib/support/tmpfile.h
   src:
-  - src/core/profiling/basic_timers.c
-  - src/core/profiling/stap_timers.c
-  - src/core/support/alloc.c
-  - src/core/support/avl.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/histogram.c
-  - src/core/support/host_port.c
-  - src/core/support/load_file.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/subprocess_windows.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_precise.c
-  - src/core/support/time_win32.c
-  - src/core/support/tls_pthread.c
-  - src/core/support/tmpfile_posix.c
-  - src/core/support/tmpfile_win32.c
-  - src/core/support/wrap_memcpy.c
+  - src/core/lib/profiling/basic_timers.c
+  - src/core/lib/profiling/stap_timers.c
+  - src/core/lib/support/alloc.c
+  - src/core/lib/support/avl.c
+  - src/core/lib/support/backoff.c
+  - src/core/lib/support/cmdline.c
+  - src/core/lib/support/cpu_iphone.c
+  - src/core/lib/support/cpu_linux.c
+  - src/core/lib/support/cpu_posix.c
+  - src/core/lib/support/cpu_windows.c
+  - src/core/lib/support/env_linux.c
+  - src/core/lib/support/env_posix.c
+  - src/core/lib/support/env_win32.c
+  - src/core/lib/support/histogram.c
+  - src/core/lib/support/host_port.c
+  - src/core/lib/support/load_file.c
+  - src/core/lib/support/log.c
+  - src/core/lib/support/log_android.c
+  - src/core/lib/support/log_linux.c
+  - src/core/lib/support/log_posix.c
+  - src/core/lib/support/log_win32.c
+  - src/core/lib/support/murmur_hash.c
+  - src/core/lib/support/slice.c
+  - src/core/lib/support/slice_buffer.c
+  - src/core/lib/support/stack_lockfree.c
+  - src/core/lib/support/string.c
+  - src/core/lib/support/string_posix.c
+  - src/core/lib/support/string_win32.c
+  - src/core/lib/support/subprocess_posix.c
+  - src/core/lib/support/subprocess_windows.c
+  - src/core/lib/support/sync.c
+  - src/core/lib/support/sync_posix.c
+  - src/core/lib/support/sync_win32.c
+  - src/core/lib/support/thd.c
+  - src/core/lib/support/thd_posix.c
+  - src/core/lib/support/thd_win32.c
+  - src/core/lib/support/time.c
+  - src/core/lib/support/time_posix.c
+  - src/core/lib/support/time_precise.c
+  - src/core/lib/support/time_win32.c
+  - src/core/lib/support/tls_pthread.c
+  - src/core/lib/support/tmpfile_posix.c
+  - src/core/lib/support/tmpfile_win32.c
+  - src/core/lib/support/wrap_memcpy.c
 - name: gpr_codegen
   public_headers:
   - include/grpc/impl/codegen/alloc.h
@@ -173,6 +175,7 @@
   - include/grpc++/support/time.h
   headers:
   - src/cpp/client/create_channel_internal.h
+  - src/cpp/common/core_codegen.h
   - src/cpp/common/create_auth_context.h
   - src/cpp/server/dynamic_thread_pool.h
   - src/cpp/server/thread_pool_interface.h
@@ -184,11 +187,10 @@
   - src/cpp/client/credentials.cc
   - src/cpp/client/generic_stub.cc
   - src/cpp/client/insecure_credentials.cc
-  - src/cpp/common/call.cc
   - src/cpp/common/channel_arguments.cc
   - src/cpp/common/completion_queue.cc
+  - src/cpp/common/core_codegen.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/dynamic_thread_pool.cc
@@ -215,6 +217,7 @@
   - include/grpc++/impl/codegen/completion_queue_tag.h
   - include/grpc++/impl/codegen/config.h
   - include/grpc++/impl/codegen/config_protobuf.h
+  - include/grpc++/impl/codegen/core_codegen_interface.h
   - include/grpc++/impl/codegen/grpc_library.h
   - include/grpc++/impl/codegen/method_handler_impl.h
   - include/grpc++/impl/codegen/proto_utils.h
@@ -235,7 +238,7 @@
   - include/grpc++/impl/codegen/sync_stream.h
   - include/grpc++/impl/codegen/time.h
   src:
-  - src/cpp/codegen/grpc_library.cc
+  - src/cpp/codegen/codegen_init.cc
 - name: grpc_base
   public_headers:
   - include/grpc/byte_buffer.h
@@ -244,252 +247,217 @@
   - include/grpc/grpc.h
   - include/grpc/status.h
   headers:
-  - src/core/census/grpc_filter.h
-  - src/core/channel/channel_args.h
-  - src/core/channel/channel_stack.h
-  - src/core/channel/client_channel.h
-  - src/core/channel/client_uchannel.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/subchannel_call_holder.h
-  - src/core/client_config/client_config.h
-  - src/core/client_config/connector.h
-  - src/core/client_config/initial_connect_string.h
-  - src/core/client_config/lb_policies/load_balancer_api.h
-  - src/core/client_config/lb_policies/pick_first.h
-  - src/core/client_config/lb_policies/round_robin.h
-  - src/core/client_config/lb_policy.h
-  - src/core/client_config/lb_policy_factory.h
-  - src/core/client_config/lb_policy_registry.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/sockaddr_resolver.h
-  - src/core/client_config/subchannel.h
-  - src/core/client_config/subchannel_factory.h
-  - src/core/client_config/subchannel_index.h
-  - src/core/client_config/uri_parser.h
-  - src/core/compression/algorithm_metadata.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/parser.h
-  - src/core/iomgr/closure.h
-  - src/core/iomgr/endpoint.h
-  - src/core/iomgr/endpoint_pair.h
-  - src/core/iomgr/exec_ctx.h
-  - src/core/iomgr/executor.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_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/timer.h
-  - src/core/iomgr/timer_heap.h
-  - src/core/iomgr/udp_server.h
-  - src/core/iomgr/wakeup_fd_pipe.h
-  - src/core/iomgr/wakeup_fd_posix.h
-  - src/core/iomgr/workqueue.h
-  - src/core/iomgr/workqueue_posix.h
-  - src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.h
-  - src/core/statistics/census_interface.h
-  - src/core/statistics/census_rpc_stats.h
-  - src/core/surface/api_trace.h
-  - src/core/surface/call.h
-  - src/core/surface/call_test_only.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/byte_stream.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_encoder.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_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/metadata_batch.h
-  - src/core/transport/static_metadata.h
-  - src/core/transport/transport.h
-  - src/core/transport/transport_impl.h
+  - src/core/lib/census/grpc_filter.h
+  - src/core/lib/census/grpc_plugin.h
+  - src/core/lib/channel/channel_args.h
+  - src/core/lib/channel/channel_stack.h
+  - src/core/lib/channel/channel_stack_builder.h
+  - src/core/lib/channel/client_channel.h
+  - src/core/lib/channel/compress_filter.h
+  - src/core/lib/channel/connected_channel.h
+  - src/core/lib/channel/context.h
+  - src/core/lib/channel/http_client_filter.h
+  - src/core/lib/channel/http_server_filter.h
+  - src/core/lib/channel/subchannel_call_holder.h
+  - src/core/lib/client_config/client_config.h
+  - src/core/lib/client_config/connector.h
+  - src/core/lib/client_config/initial_connect_string.h
+  - src/core/lib/client_config/lb_policies/load_balancer_api.h
+  - src/core/lib/client_config/lb_policies/pick_first.h
+  - src/core/lib/client_config/lb_policies/round_robin.h
+  - src/core/lib/client_config/lb_policy.h
+  - src/core/lib/client_config/lb_policy_factory.h
+  - src/core/lib/client_config/lb_policy_registry.h
+  - src/core/lib/client_config/resolver.h
+  - src/core/lib/client_config/resolver_factory.h
+  - src/core/lib/client_config/resolver_registry.h
+  - src/core/lib/client_config/resolvers/dns_resolver.h
+  - src/core/lib/client_config/resolvers/sockaddr_resolver.h
+  - src/core/lib/client_config/subchannel.h
+  - src/core/lib/client_config/subchannel_factory.h
+  - src/core/lib/client_config/subchannel_index.h
+  - src/core/lib/client_config/uri_parser.h
+  - src/core/lib/compression/algorithm_metadata.h
+  - src/core/lib/compression/message_compress.h
+  - src/core/lib/debug/trace.h
+  - src/core/lib/http/format_request.h
+  - src/core/lib/http/httpcli.h
+  - src/core/lib/http/parser.h
+  - src/core/lib/iomgr/closure.h
+  - src/core/lib/iomgr/endpoint.h
+  - src/core/lib/iomgr/endpoint_pair.h
+  - src/core/lib/iomgr/exec_ctx.h
+  - src/core/lib/iomgr/executor.h
+  - src/core/lib/iomgr/fd_posix.h
+  - src/core/lib/iomgr/iocp_windows.h
+  - src/core/lib/iomgr/iomgr.h
+  - src/core/lib/iomgr/iomgr_internal.h
+  - src/core/lib/iomgr/iomgr_posix.h
+  - src/core/lib/iomgr/pollset.h
+  - src/core/lib/iomgr/pollset_posix.h
+  - src/core/lib/iomgr/pollset_set.h
+  - src/core/lib/iomgr/pollset_set_posix.h
+  - src/core/lib/iomgr/pollset_set_windows.h
+  - src/core/lib/iomgr/pollset_windows.h
+  - src/core/lib/iomgr/resolve_address.h
+  - src/core/lib/iomgr/sockaddr.h
+  - src/core/lib/iomgr/sockaddr_posix.h
+  - src/core/lib/iomgr/sockaddr_utils.h
+  - src/core/lib/iomgr/sockaddr_win32.h
+  - src/core/lib/iomgr/socket_utils_posix.h
+  - src/core/lib/iomgr/socket_windows.h
+  - src/core/lib/iomgr/tcp_client.h
+  - src/core/lib/iomgr/tcp_posix.h
+  - src/core/lib/iomgr/tcp_server.h
+  - src/core/lib/iomgr/tcp_windows.h
+  - src/core/lib/iomgr/time_averaged_stats.h
+  - src/core/lib/iomgr/timer.h
+  - src/core/lib/iomgr/timer_heap.h
+  - src/core/lib/iomgr/udp_server.h
+  - src/core/lib/iomgr/unix_sockets_posix.h
+  - src/core/lib/iomgr/wakeup_fd_pipe.h
+  - src/core/lib/iomgr/wakeup_fd_posix.h
+  - src/core/lib/iomgr/workqueue.h
+  - src/core/lib/iomgr/workqueue_posix.h
+  - src/core/lib/iomgr/workqueue_windows.h
+  - src/core/lib/json/json.h
+  - src/core/lib/json/json_common.h
+  - src/core/lib/json/json_reader.h
+  - src/core/lib/json/json_writer.h
+  - src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h
+  - src/core/lib/statistics/census_interface.h
+  - src/core/lib/statistics/census_rpc_stats.h
+  - src/core/lib/surface/api_trace.h
+  - src/core/lib/surface/call.h
+  - src/core/lib/surface/call_test_only.h
+  - src/core/lib/surface/channel.h
+  - src/core/lib/surface/channel_init.h
+  - src/core/lib/surface/channel_stack_type.h
+  - src/core/lib/surface/completion_queue.h
+  - src/core/lib/surface/event_string.h
+  - src/core/lib/surface/init.h
+  - src/core/lib/surface/lame_client.h
+  - src/core/lib/surface/server.h
+  - src/core/lib/surface/surface_trace.h
+  - src/core/lib/transport/byte_stream.h
+  - src/core/lib/transport/connectivity_state.h
+  - src/core/lib/transport/metadata.h
+  - src/core/lib/transport/metadata_batch.h
+  - src/core/lib/transport/static_metadata.h
+  - src/core/lib/transport/transport.h
+  - src/core/lib/transport/transport_impl.h
   src:
-  - src/core/census/grpc_context.c
-  - src/core/census/grpc_filter.c
-  - src/core/channel/channel_args.c
-  - src/core/channel/channel_stack.c
-  - src/core/channel/client_channel.c
-  - src/core/channel/client_uchannel.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/subchannel_call_holder.c
-  - src/core/client_config/client_config.c
-  - src/core/client_config/connector.c
-  - src/core/client_config/default_initial_connect_string.c
-  - src/core/client_config/initial_connect_string.c
-  - src/core/client_config/lb_policies/load_balancer_api.c
-  - src/core/client_config/lb_policies/pick_first.c
-  - src/core/client_config/lb_policies/round_robin.c
-  - src/core/client_config/lb_policy.c
-  - src/core/client_config/lb_policy_factory.c
-  - src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c
-  - src/core/client_config/subchannel.c
-  - src/core/client_config/subchannel_factory.c
-  - src/core/client_config/subchannel_index.c
-  - src/core/client_config/uri_parser.c
-  - src/core/compression/compression_algorithm.c
-  - src/core/compression/message_compress.c
-  - src/core/debug/trace.c
-  - src/core/httpcli/format_request.c
-  - src/core/httpcli/httpcli.c
-  - src/core/httpcli/parser.c
-  - src/core/iomgr/closure.c
-  - src/core/iomgr/endpoint.c
-  - src/core/iomgr/endpoint_pair_posix.c
-  - src/core/iomgr/endpoint_pair_windows.c
-  - src/core/iomgr/exec_ctx.c
-  - src/core/iomgr/executor.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_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/timer.c
-  - src/core/iomgr/timer_heap.c
-  - src/core/iomgr/udp_server.c
-  - src/core/iomgr/wakeup_fd_eventfd.c
-  - src/core/iomgr/wakeup_fd_nospecial.c
-  - src/core/iomgr/wakeup_fd_pipe.c
-  - src/core/iomgr/wakeup_fd_posix.c
-  - src/core/iomgr/workqueue_posix.c
-  - src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c
-  - src/core/surface/alarm.c
-  - src/core/surface/api_trace.c
-  - src/core/surface/byte_buffer.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_connectivity.c
-  - src/core/surface/channel_create.c
-  - src/core/surface/channel_ping.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/validate_metadata.c
-  - src/core/surface/version.c
-  - src/core/transport/byte_stream.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_encoder.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_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/metadata_batch.c
-  - src/core/transport/static_metadata.c
-  - src/core/transport/transport.c
-  - src/core/transport/transport_op_string.c
+  - src/core/lib/census/grpc_context.c
+  - src/core/lib/census/grpc_filter.c
+  - src/core/lib/census/grpc_plugin.c
+  - src/core/lib/channel/channel_args.c
+  - src/core/lib/channel/channel_stack.c
+  - src/core/lib/channel/channel_stack_builder.c
+  - src/core/lib/channel/client_channel.c
+  - src/core/lib/channel/compress_filter.c
+  - src/core/lib/channel/connected_channel.c
+  - src/core/lib/channel/http_client_filter.c
+  - src/core/lib/channel/http_server_filter.c
+  - src/core/lib/channel/subchannel_call_holder.c
+  - src/core/lib/client_config/client_config.c
+  - src/core/lib/client_config/connector.c
+  - src/core/lib/client_config/default_initial_connect_string.c
+  - src/core/lib/client_config/initial_connect_string.c
+  - src/core/lib/client_config/lb_policies/load_balancer_api.c
+  - src/core/lib/client_config/lb_policies/pick_first.c
+  - src/core/lib/client_config/lb_policies/round_robin.c
+  - src/core/lib/client_config/lb_policy.c
+  - src/core/lib/client_config/lb_policy_factory.c
+  - src/core/lib/client_config/lb_policy_registry.c
+  - src/core/lib/client_config/resolver.c
+  - src/core/lib/client_config/resolver_factory.c
+  - src/core/lib/client_config/resolver_registry.c
+  - src/core/lib/client_config/resolvers/dns_resolver.c
+  - src/core/lib/client_config/resolvers/sockaddr_resolver.c
+  - src/core/lib/client_config/subchannel.c
+  - src/core/lib/client_config/subchannel_factory.c
+  - src/core/lib/client_config/subchannel_index.c
+  - src/core/lib/client_config/uri_parser.c
+  - src/core/lib/compression/compression_algorithm.c
+  - src/core/lib/compression/message_compress.c
+  - src/core/lib/debug/trace.c
+  - src/core/lib/http/format_request.c
+  - src/core/lib/http/httpcli.c
+  - src/core/lib/http/parser.c
+  - src/core/lib/iomgr/closure.c
+  - src/core/lib/iomgr/endpoint.c
+  - src/core/lib/iomgr/endpoint_pair_posix.c
+  - src/core/lib/iomgr/endpoint_pair_windows.c
+  - src/core/lib/iomgr/exec_ctx.c
+  - src/core/lib/iomgr/executor.c
+  - src/core/lib/iomgr/fd_posix.c
+  - src/core/lib/iomgr/iocp_windows.c
+  - src/core/lib/iomgr/iomgr.c
+  - src/core/lib/iomgr/iomgr_posix.c
+  - src/core/lib/iomgr/iomgr_windows.c
+  - src/core/lib/iomgr/pollset_multipoller_with_epoll.c
+  - src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c
+  - src/core/lib/iomgr/pollset_posix.c
+  - src/core/lib/iomgr/pollset_set_posix.c
+  - src/core/lib/iomgr/pollset_set_windows.c
+  - src/core/lib/iomgr/pollset_windows.c
+  - src/core/lib/iomgr/resolve_address_posix.c
+  - src/core/lib/iomgr/resolve_address_windows.c
+  - src/core/lib/iomgr/sockaddr_utils.c
+  - src/core/lib/iomgr/socket_utils_common_posix.c
+  - src/core/lib/iomgr/socket_utils_linux.c
+  - src/core/lib/iomgr/socket_utils_posix.c
+  - src/core/lib/iomgr/socket_windows.c
+  - src/core/lib/iomgr/tcp_client_posix.c
+  - src/core/lib/iomgr/tcp_client_windows.c
+  - src/core/lib/iomgr/tcp_posix.c
+  - src/core/lib/iomgr/tcp_server_posix.c
+  - src/core/lib/iomgr/tcp_server_windows.c
+  - src/core/lib/iomgr/tcp_windows.c
+  - src/core/lib/iomgr/time_averaged_stats.c
+  - src/core/lib/iomgr/timer.c
+  - src/core/lib/iomgr/timer_heap.c
+  - src/core/lib/iomgr/udp_server.c
+  - src/core/lib/iomgr/unix_sockets_posix.c
+  - src/core/lib/iomgr/unix_sockets_posix_noop.c
+  - src/core/lib/iomgr/wakeup_fd_eventfd.c
+  - src/core/lib/iomgr/wakeup_fd_nospecial.c
+  - src/core/lib/iomgr/wakeup_fd_pipe.c
+  - src/core/lib/iomgr/wakeup_fd_posix.c
+  - src/core/lib/iomgr/workqueue_posix.c
+  - src/core/lib/iomgr/workqueue_windows.c
+  - src/core/lib/json/json.c
+  - src/core/lib/json/json_reader.c
+  - src/core/lib/json/json_string.c
+  - src/core/lib/json/json_writer.c
+  - src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c
+  - src/core/lib/surface/alarm.c
+  - src/core/lib/surface/api_trace.c
+  - src/core/lib/surface/byte_buffer.c
+  - src/core/lib/surface/byte_buffer_reader.c
+  - src/core/lib/surface/call.c
+  - src/core/lib/surface/call_details.c
+  - src/core/lib/surface/call_log_batch.c
+  - src/core/lib/surface/channel.c
+  - src/core/lib/surface/channel_connectivity.c
+  - src/core/lib/surface/channel_init.c
+  - src/core/lib/surface/channel_ping.c
+  - src/core/lib/surface/channel_stack_type.c
+  - src/core/lib/surface/completion_queue.c
+  - src/core/lib/surface/event_string.c
+  - src/core/lib/surface/init.c
+  - src/core/lib/surface/lame_client.c
+  - src/core/lib/surface/metadata_array.c
+  - src/core/lib/surface/server.c
+  - src/core/lib/surface/validate_metadata.c
+  - src/core/lib/surface/version.c
+  - src/core/lib/transport/byte_stream.c
+  - src/core/lib/transport/connectivity_state.c
+  - src/core/lib/transport/metadata.c
+  - src/core/lib/transport/metadata_batch.c
+  - src/core/lib/transport/static_metadata.c
+  - src/core/lib/transport/transport.c
+  - src/core/lib/transport/transport_op_string.c
 - name: grpc_codegen
   public_headers:
   - include/grpc/impl/codegen/byte_buffer.h
@@ -500,42 +468,40 @@
   - include/grpc/impl/codegen/status.h
 - name: grpc_secure
   headers:
-  - src/core/security/auth_filters.h
-  - src/core/security/b64.h
-  - src/core/security/credentials.h
-  - src/core/security/handshake.h
-  - src/core/security/json_token.h
-  - src/core/security/jwt_verifier.h
-  - src/core/security/secure_endpoint.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/ssl_types.h
-  - src/core/tsi/transport_security.h
-  - src/core/tsi/transport_security_interface.h
+  - src/core/lib/security/auth_filters.h
+  - src/core/lib/security/b64.h
+  - src/core/lib/security/credentials.h
+  - src/core/lib/security/handshake.h
+  - src/core/lib/security/json_token.h
+  - src/core/lib/security/jwt_verifier.h
+  - src/core/lib/security/secure_endpoint.h
+  - src/core/lib/security/security_connector.h
+  - src/core/lib/security/security_context.h
+  - src/core/lib/tsi/fake_transport_security.h
+  - src/core/lib/tsi/ssl_transport_security.h
+  - src/core/lib/tsi/ssl_types.h
+  - src/core/lib/tsi/transport_security.h
+  - src/core/lib/tsi/transport_security_interface.h
   src:
-  - src/core/httpcli/httpcli_security_connector.c
-  - src/core/security/b64.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/handshake.c
-  - src/core/security/json_token.c
-  - src/core/security/jwt_verifier.c
-  - src/core/security/secure_endpoint.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/lib/http/httpcli_security_connector.c
+  - src/core/lib/security/b64.c
+  - src/core/lib/security/client_auth_filter.c
+  - src/core/lib/security/credentials.c
+  - src/core/lib/security/credentials_metadata.c
+  - src/core/lib/security/credentials_posix.c
+  - src/core/lib/security/credentials_win32.c
+  - src/core/lib/security/google_default_credentials.c
+  - src/core/lib/security/handshake.c
+  - src/core/lib/security/json_token.c
+  - src/core/lib/security/jwt_verifier.c
+  - src/core/lib/security/secure_endpoint.c
+  - src/core/lib/security/security_connector.c
+  - src/core/lib/security/security_context.c
+  - src/core/lib/security/server_auth_filter.c
+  - src/core/lib/surface/init_secure.c
+  - src/core/lib/tsi/fake_transport_security.c
+  - src/core/lib/tsi/ssl_transport_security.c
+  - src/core/lib/tsi/transport_security.c
 - name: grpc_test_util_base
   headers:
   - test/core/end2end/cq_verifier.h
@@ -544,6 +510,7 @@
   - test/core/util/grpc_profiler.h
   - test/core/util/parse_hexstring.h
   - test/core/util/port.h
+  - test/core/util/port_server_client.h
   - test/core/util/slice_splitter.h
   src:
   - test/core/end2end/cq_verifier.c
@@ -552,8 +519,80 @@
   - test/core/util/grpc_profiler.c
   - test/core/util/parse_hexstring.c
   - test/core/util/port_posix.c
+  - test/core/util/port_server_client.c
   - test/core/util/port_windows.c
   - test/core/util/slice_splitter.c
+- name: grpc_transport_chttp2
+  headers:
+  - src/core/ext/transport/chttp2/transport/alpn.h
+  - src/core/ext/transport/chttp2/transport/bin_encoder.h
+  - src/core/ext/transport/chttp2/transport/chttp2_transport.h
+  - src/core/ext/transport/chttp2/transport/frame.h
+  - src/core/ext/transport/chttp2/transport/frame_data.h
+  - src/core/ext/transport/chttp2/transport/frame_goaway.h
+  - src/core/ext/transport/chttp2/transport/frame_ping.h
+  - src/core/ext/transport/chttp2/transport/frame_rst_stream.h
+  - src/core/ext/transport/chttp2/transport/frame_settings.h
+  - src/core/ext/transport/chttp2/transport/frame_window_update.h
+  - src/core/ext/transport/chttp2/transport/hpack_encoder.h
+  - src/core/ext/transport/chttp2/transport/hpack_parser.h
+  - src/core/ext/transport/chttp2/transport/hpack_table.h
+  - src/core/ext/transport/chttp2/transport/http2_errors.h
+  - src/core/ext/transport/chttp2/transport/huffsyms.h
+  - src/core/ext/transport/chttp2/transport/incoming_metadata.h
+  - src/core/ext/transport/chttp2/transport/internal.h
+  - src/core/ext/transport/chttp2/transport/status_conversion.h
+  - src/core/ext/transport/chttp2/transport/stream_map.h
+  - src/core/ext/transport/chttp2/transport/timeout_encoding.h
+  - src/core/ext/transport/chttp2/transport/varint.h
+  src:
+  - src/core/ext/transport/chttp2/transport/alpn.c
+  - src/core/ext/transport/chttp2/transport/bin_encoder.c
+  - src/core/ext/transport/chttp2/transport/chttp2_transport.c
+  - src/core/ext/transport/chttp2/transport/frame_data.c
+  - src/core/ext/transport/chttp2/transport/frame_goaway.c
+  - src/core/ext/transport/chttp2/transport/frame_ping.c
+  - src/core/ext/transport/chttp2/transport/frame_rst_stream.c
+  - src/core/ext/transport/chttp2/transport/frame_settings.c
+  - src/core/ext/transport/chttp2/transport/frame_window_update.c
+  - src/core/ext/transport/chttp2/transport/hpack_encoder.c
+  - src/core/ext/transport/chttp2/transport/hpack_parser.c
+  - src/core/ext/transport/chttp2/transport/hpack_table.c
+  - src/core/ext/transport/chttp2/transport/huffsyms.c
+  - src/core/ext/transport/chttp2/transport/incoming_metadata.c
+  - src/core/ext/transport/chttp2/transport/parsing.c
+  - src/core/ext/transport/chttp2/transport/status_conversion.c
+  - src/core/ext/transport/chttp2/transport/stream_lists.c
+  - src/core/ext/transport/chttp2/transport/stream_map.c
+  - src/core/ext/transport/chttp2/transport/timeout_encoding.c
+  - src/core/ext/transport/chttp2/transport/varint.c
+  - src/core/ext/transport/chttp2/transport/writing.c
+  uses:
+  - grpc_base
+- name: grpc_transport_chttp2_client_insecure
+  src:
+  - src/core/ext/transport/chttp2/client/insecure/channel_create.c
+  uses:
+  - grpc_transport_chttp2
+  - grpc_base
+- name: grpc_transport_chttp2_client_secure
+  src:
+  - src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
+  uses:
+  - grpc_transport_chttp2
+  - grpc_base
+- name: grpc_transport_chttp2_server_insecure
+  src:
+  - src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
+  uses:
+  - grpc_transport_chttp2
+  - grpc_base
+- name: grpc_transport_chttp2_server_secure
+  src:
+  - src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
+  uses:
+  - grpc_transport_chttp2
+  - grpc_base
 - name: nanopb
   headers:
   - third_party/nanopb/pb.h
@@ -595,9 +634,13 @@
   deps_linkage: static
   dll: true
   filegroups:
-  - grpc_codegen
   - grpc_base
+  - grpc_transport_chttp2_server_secure
+  - grpc_transport_chttp2_client_secure
+  - grpc_transport_chttp2_server_insecure
+  - grpc_transport_chttp2_client_insecure
   - grpc_secure
+  - grpc_codegen
   - census
   - nanopb
   secure: true
@@ -605,6 +648,16 @@
   - grpc.dependencies.openssl
   - grpc.dependencies.zlib
   vs_project_guid: '{29D16885-7228-4C31-81ED-5F9187C7F2A9}'
+- name: grpc_codegen_lib
+  build: protoc
+  language: c
+  headers: []
+  src: []
+  filegroups:
+  - gpr_codegen
+  - grpc_codegen
+  secure: false
+  vs_project_guid: '{A828FD72-44CE-4EA5-8966-6E4624458D58}'
 - name: grpc_dll
   build: private
   language: c
@@ -659,7 +712,7 @@
   build: all
   language: c
   src:
-  - src/core/surface/init_unsecure.c
+  - src/core/lib/surface/init_unsecure.c
   deps:
   - gpr
   baselib: true
@@ -667,6 +720,8 @@
   dll: true
   filegroups:
   - grpc_base
+  - grpc_transport_chttp2_server_insecure
+  - grpc_transport_chttp2_client_insecure
   - grpc_codegen
   - census
   - nanopb
@@ -678,9 +733,9 @@
   public_headers:
   - include/grpc/grpc_zookeeper.h
   headers:
-  - src/core/client_config/resolvers/zookeeper_resolver.h
+  - src/core/lib/client_config/resolvers/zookeeper_resolver.h
   src:
-  - src/core/client_config/resolvers/zookeeper_resolver.c
+  - src/core/lib/client_config/resolvers/zookeeper_resolver.c
   deps:
   - gpr
   - grpc
@@ -719,6 +774,7 @@
   language: c++
   headers:
   - src/cpp/client/secure_credentials.h
+  - src/cpp/common/core_codegen.h
   - src/cpp/common/secure_auth_context.h
   - src/cpp/server/secure_server_credentials.h
   src:
@@ -737,6 +793,17 @@
   - grpc++_codegen
   secure: check
   vs_project_guid: '{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}'
+- name: grpc++_codegen_lib
+  build: all
+  language: c++
+  headers: []
+  src: []
+  filegroups:
+  - gpr_codegen
+  - grpc_codegen
+  - grpc++_codegen
+  secure: false
+  vs_project_guid: '{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}'
 - name: grpc++_test_config
   build: private
   language: c++
@@ -809,10 +876,9 @@
   - src/compiler/objective_c_generator.cc
   - src/compiler/python_generator.cc
   - src/compiler/ruby_generator.cc
-  deps: []
+  deps:
+  - grpc++_codegen_lib
   filegroups:
-  - grpc++_codegen
-  - grpc_codegen
   - gpr_codegen
   secure: false
   vs_project_guid: '{B6E81D84-2ACB-41B8-8781-493A944C7817}'
@@ -1057,6 +1123,27 @@
   - grpc
   - gpr_test_util
   - gpr
+- name: concurrent_connectivity_test
+  build: test
+  language: c
+  src:
+  - test/core/surface/concurrent_connectivity_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+- name: dns_resolver_connectivity_test
+  cpu_cost: 0.1
+  build: test
+  language: c
+  src:
+  - test/core/client_config/resolvers/dns_resolver_connectivity_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: dns_resolver_test
   build: test
   language: c
@@ -1194,6 +1281,14 @@
   deps:
   - gpr_test_util
   - gpr
+- name: gpr_backoff_test
+  build: test
+  language: c
+  src:
+  - test/core/support/backoff_test.c
+  deps:
+  - gpr_test_util
+  - gpr
 - name: gpr_cmdline_test
   build: test
   language: c
@@ -1479,6 +1574,18 @@
   - grpc
   - gpr_test_util
   - gpr
+- name: hpack_parser_fuzzer_test
+  build: fuzzer
+  language: c
+  src:
+  - test/core/transport/chttp2/hpack_parser_fuzzer_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+  corpus_dirs:
+  - test/core/transport/chttp2/hpack_parser_corpus
 - name: hpack_parser_test
   build: test
   language: c
@@ -1499,21 +1606,33 @@
   - grpc
   - gpr_test_util
   - gpr
-- name: httpcli_format_request_test
-  build: test
+- name: http_fuzzer_test
+  build: fuzzer
   language: c
   src:
-  - test/core/httpcli/format_request_test.c
+  - test/core/http/fuzzer.c
   deps:
   - grpc_test_util
   - grpc
   - gpr_test_util
   - gpr
-- name: httpcli_parser_test
+  corpus_dirs:
+  - test/core/http/corpus
+- name: http_parser_test
   build: test
   language: c
   src:
-  - test/core/httpcli/parser_test.c
+  - test/core/http/parser_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+- name: httpcli_format_request_test
+  build: test
+  language: c
+  src:
+  - test/core/http/format_request_test.c
   deps:
   - grpc_test_util
   - grpc
@@ -1524,7 +1643,7 @@
   build: test
   language: c
   src:
-  - test/core/httpcli/httpcli_test.c
+  - test/core/http/httpcli_test.c
   deps:
   - grpc_test_util
   - grpc
@@ -1539,7 +1658,7 @@
   build: test
   language: c
   src:
-  - test/core/httpcli/httpscli_test.c
+  - test/core/http/httpscli_test.c
   deps:
   - grpc_test_util
   - grpc
@@ -1567,6 +1686,18 @@
   - grpc
   - gpr_test_util
   - gpr
+- name: json_fuzzer_test
+  build: fuzzer
+  language: c
+  src:
+  - test/core/json/fuzzer.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+  corpus_dirs:
+  - test/core/json/corpus
 - name: json_rewrite
   build: test
   run: false
@@ -1618,6 +1749,7 @@
   - gpr
 - name: lb_policies_test
   cpu_cost: 0.1
+  flaky: true
   build: test
   language: c
   src:
@@ -1652,6 +1784,7 @@
   - gpr_test_util
   - gpr
 - name: mlog_test
+  flaky: true
   build: test
   language: c
   src:
@@ -1928,6 +2061,18 @@
   - mac
   - linux
   - posix
+- name: uri_fuzzer_test
+  build: fuzzer
+  language: c
+  src:
+  - test/core/client_config/uri_fuzzer_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+  corpus_dirs:
+  - test/core/client_config/uri_corpus
 - name: uri_parser_test
   build: test
   language: c
@@ -2079,6 +2224,20 @@
   - grpc
   - gpr_test_util
   - gpr
+- name: codegen_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - src/proto/grpc/testing/control.proto
+  - src/proto/grpc/testing/messages.proto
+  - src/proto/grpc/testing/payloads.proto
+  - src/proto/grpc/testing/perf_db.proto
+  - src/proto/grpc/testing/services.proto
+  - src/proto/grpc/testing/stats.proto
+  - test/cpp/codegen/codegen_test.cc
+  deps:
+  - grpc++_codegen_lib
 - name: credentials_test
   gtest: true
   build: test
@@ -2379,7 +2538,7 @@
   - linux
   - posix
 - name: qps_openloop_test
-  cpu_cost: 10
+  cpu_cost: 0.5
   build: test
   language: c++
   src:
@@ -2695,8 +2854,8 @@
 configs:
   asan:
     CC: clang
-    CPPFLAGS: -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
-      -DGPR_NO_DIRECT_SYSCALLS
+    CPPFLAGS: -O0 -fsanitize-coverage=edge -fsanitize=address -fno-omit-frame-pointer
+      -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
     CXX: clang++
     LD: clang
     LDFLAGS: -fsanitize=address
@@ -2708,8 +2867,8 @@
     timeout_multiplier: 3
   asan-noleaks:
     CC: clang
-    CPPFLAGS: -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
-      -DGPR_NO_DIRECT_SYSCALLS
+    CPPFLAGS: -O0 -fsanitize-coverage=edge -fsanitize=address -fno-omit-frame-pointer
+      -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
     CXX: clang++
     LD: clang
     LDFLAGS: -fsanitize=address
@@ -2718,12 +2877,55 @@
     test_environ:
       ASAN_OPTIONS: detect_leaks=0:color=always
     timeout_multiplier: 3
+  asan-trace-cmp:
+    CC: clang
+    CPPFLAGS: -O0 -fsanitize-coverage=edge -fsanitize-coverage=trace-cmp -fsanitize=address
+      -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
+    CXX: clang++
+    LD: clang
+    LDFLAGS: -fsanitize=address
+    LDXX: clang++
+    compile_the_world: true
+    test_environ:
+      ASAN_OPTIONS: detect_leaks=1:color=always
+      LSAN_OPTIONS: suppressions=tools/lsan_suppressions.txt:report_objects=1
+    timeout_multiplier: 3
   basicprof:
     CPPFLAGS: -O2 -DGRPC_BASIC_PROFILER -DGRPC_TIMERS_RDTSC
     DEFINES: NDEBUG
   dbg:
     CPPFLAGS: -O0
     DEFINES: _DEBUG DEBUG
+  easan:
+    CC: clang
+    CPPFLAGS: -O0 -fsanitize-coverage=edge -fsanitize=address -fno-omit-frame-pointer
+      -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
+    CXX: clang++
+    DEFINES: _DEBUG DEBUG GRPC_EXECUTION_CONTEXT_SANITIZER
+    LD: clang
+    LDFLAGS: -fsanitize=address
+    LDXX: clang++
+    compile_the_world: true
+    test_environ:
+      ASAN_OPTIONS: detect_leaks=1:color=always
+      LSAN_OPTIONS: suppressions=tools/lsan_suppressions.txt:report_objects=1
+    timeout_multiplier: 3
+  edbg:
+    CPPFLAGS: -O0
+    DEFINES: _DEBUG DEBUG GRPC_EXECUTION_CONTEXT_SANITIZER
+  etsan:
+    CC: clang
+    CPPFLAGS: -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument
+      -DGPR_NO_DIRECT_SYSCALLS
+    CXX: clang++
+    DEFINES: _DEBUG DEBUG GRPC_EXECUTION_CONTEXT_SANITIZER
+    LD: clang
+    LDFLAGS: -fsanitize=thread
+    LDXX: clang++
+    compile_the_world: true
+    test_environ:
+      TSAN_OPTIONS: suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1
+    timeout_multiplier: 5
   gcov:
     CC: gcc
     CPPFLAGS: -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
@@ -2746,9 +2948,9 @@
     valgrind: --tool=memcheck --leak-check=full
   msan:
     CC: clang
-    CPPFLAGS: -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer
-      -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument
-      -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
+    CPPFLAGS: -O0 -fsanitize-coverage=edge -fsanitize=memory -fsanitize-memory-track-origins
+      -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1
+      -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
     CXX: clang++
     DEFINES: NDEBUG
     LD: clang
@@ -2770,10 +2972,10 @@
   tsan:
     CC: clang
     CPPFLAGS: -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument
-      -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
+      -DGPR_NO_DIRECT_SYSCALLS
     CXX: clang++
     LD: clang
-    LDFLAGS: -fsanitize=thread -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
+    LDFLAGS: -fsanitize=thread
     LDXX: clang++
     compile_the_world: true
     test_environ:
@@ -2781,7 +2983,8 @@
     timeout_multiplier: 5
   ubsan:
     CC: clang
-    CPPFLAGS: -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
+    CPPFLAGS: -O1 -fsanitize-coverage=edge -fsanitize=undefined -fno-omit-frame-pointer
+      -Wno-unused-command-line-argument
     CXX: clang++
     DEFINES: NDEBUG
     LD: clang
@@ -2838,7 +3041,7 @@
   - src/node/ext/server_credentials.cc
   - src/node/ext/timeval.cc
 openssl_fallback:
-  base_uri: http://openssl.org/source/
+  base_uri: https://openssl.org/source/old/1.0.2/
   extraction_dir: openssl-1.0.2f
   tarball: openssl-1.0.2f.tar.gz
 php_config_m4:
diff --git a/composer.json b/composer.json
index 9ba45fd..97b1a5c 100644
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,7 @@
   "name": "grpc/grpc",
   "type": "library",
   "description": "gRPC library for PHP",
-  "version": "0.13.0",
+  "version": "0.14.0",
   "keywords": ["rpc"],
   "homepage": "http://grpc.io",
   "license": "BSD-3-Clause",
diff --git a/config.m4 b/config.m4
index 8ab45e6..653b287 100644
--- a/config.m4
+++ b/config.m4
@@ -36,206 +36,211 @@
     src/php/ext/grpc/server.c \
     src/php/ext/grpc/server_credentials.c \
     src/php/ext/grpc/timeval.c \
-    src/core/profiling/basic_timers.c \
-    src/core/profiling/stap_timers.c \
-    src/core/support/alloc.c \
-    src/core/support/avl.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/histogram.c \
-    src/core/support/host_port.c \
-    src/core/support/load_file.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/subprocess_windows.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_precise.c \
-    src/core/support/time_win32.c \
-    src/core/support/tls_pthread.c \
-    src/core/support/tmpfile_posix.c \
-    src/core/support/tmpfile_win32.c \
-    src/core/support/wrap_memcpy.c \
-    src/core/census/grpc_context.c \
-    src/core/census/grpc_filter.c \
-    src/core/channel/channel_args.c \
-    src/core/channel/channel_stack.c \
-    src/core/channel/client_channel.c \
-    src/core/channel/client_uchannel.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/subchannel_call_holder.c \
-    src/core/client_config/client_config.c \
-    src/core/client_config/connector.c \
-    src/core/client_config/default_initial_connect_string.c \
-    src/core/client_config/initial_connect_string.c \
-    src/core/client_config/lb_policies/load_balancer_api.c \
-    src/core/client_config/lb_policies/pick_first.c \
-    src/core/client_config/lb_policies/round_robin.c \
-    src/core/client_config/lb_policy.c \
-    src/core/client_config/lb_policy_factory.c \
-    src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c \
-    src/core/client_config/subchannel.c \
-    src/core/client_config/subchannel_factory.c \
-    src/core/client_config/subchannel_index.c \
-    src/core/client_config/uri_parser.c \
-    src/core/compression/compression_algorithm.c \
-    src/core/compression/message_compress.c \
-    src/core/debug/trace.c \
-    src/core/httpcli/format_request.c \
-    src/core/httpcli/httpcli.c \
-    src/core/httpcli/parser.c \
-    src/core/iomgr/closure.c \
-    src/core/iomgr/endpoint.c \
-    src/core/iomgr/endpoint_pair_posix.c \
-    src/core/iomgr/endpoint_pair_windows.c \
-    src/core/iomgr/exec_ctx.c \
-    src/core/iomgr/executor.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_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/timer.c \
-    src/core/iomgr/timer_heap.c \
-    src/core/iomgr/udp_server.c \
-    src/core/iomgr/wakeup_fd_eventfd.c \
-    src/core/iomgr/wakeup_fd_nospecial.c \
-    src/core/iomgr/wakeup_fd_pipe.c \
-    src/core/iomgr/wakeup_fd_posix.c \
-    src/core/iomgr/workqueue_posix.c \
-    src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c \
-    src/core/surface/alarm.c \
-    src/core/surface/api_trace.c \
-    src/core/surface/byte_buffer.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_connectivity.c \
-    src/core/surface/channel_create.c \
-    src/core/surface/channel_ping.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/validate_metadata.c \
-    src/core/surface/version.c \
-    src/core/transport/byte_stream.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_encoder.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_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/metadata_batch.c \
-    src/core/transport/static_metadata.c \
-    src/core/transport/transport.c \
-    src/core/transport/transport_op_string.c \
-    src/core/httpcli/httpcli_security_connector.c \
-    src/core/security/b64.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/handshake.c \
-    src/core/security/json_token.c \
-    src/core/security/jwt_verifier.c \
-    src/core/security/secure_endpoint.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/context.c \
-    src/core/census/initialize.c \
-    src/core/census/mlog.c \
-    src/core/census/operation.c \
-    src/core/census/placeholders.c \
-    src/core/census/tracing.c \
+    src/core/lib/profiling/basic_timers.c \
+    src/core/lib/profiling/stap_timers.c \
+    src/core/lib/support/alloc.c \
+    src/core/lib/support/avl.c \
+    src/core/lib/support/backoff.c \
+    src/core/lib/support/cmdline.c \
+    src/core/lib/support/cpu_iphone.c \
+    src/core/lib/support/cpu_linux.c \
+    src/core/lib/support/cpu_posix.c \
+    src/core/lib/support/cpu_windows.c \
+    src/core/lib/support/env_linux.c \
+    src/core/lib/support/env_posix.c \
+    src/core/lib/support/env_win32.c \
+    src/core/lib/support/histogram.c \
+    src/core/lib/support/host_port.c \
+    src/core/lib/support/load_file.c \
+    src/core/lib/support/log.c \
+    src/core/lib/support/log_android.c \
+    src/core/lib/support/log_linux.c \
+    src/core/lib/support/log_posix.c \
+    src/core/lib/support/log_win32.c \
+    src/core/lib/support/murmur_hash.c \
+    src/core/lib/support/slice.c \
+    src/core/lib/support/slice_buffer.c \
+    src/core/lib/support/stack_lockfree.c \
+    src/core/lib/support/string.c \
+    src/core/lib/support/string_posix.c \
+    src/core/lib/support/string_win32.c \
+    src/core/lib/support/subprocess_posix.c \
+    src/core/lib/support/subprocess_windows.c \
+    src/core/lib/support/sync.c \
+    src/core/lib/support/sync_posix.c \
+    src/core/lib/support/sync_win32.c \
+    src/core/lib/support/thd.c \
+    src/core/lib/support/thd_posix.c \
+    src/core/lib/support/thd_win32.c \
+    src/core/lib/support/time.c \
+    src/core/lib/support/time_posix.c \
+    src/core/lib/support/time_precise.c \
+    src/core/lib/support/time_win32.c \
+    src/core/lib/support/tls_pthread.c \
+    src/core/lib/support/tmpfile_posix.c \
+    src/core/lib/support/tmpfile_win32.c \
+    src/core/lib/support/wrap_memcpy.c \
+    src/core/ext/transport/chttp2/client/insecure/channel_create.c \
+    src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
+    src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
+    src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c \
+    src/core/ext/transport/chttp2/transport/alpn.c \
+    src/core/ext/transport/chttp2/transport/bin_encoder.c \
+    src/core/ext/transport/chttp2/transport/chttp2_transport.c \
+    src/core/ext/transport/chttp2/transport/frame_data.c \
+    src/core/ext/transport/chttp2/transport/frame_goaway.c \
+    src/core/ext/transport/chttp2/transport/frame_ping.c \
+    src/core/ext/transport/chttp2/transport/frame_rst_stream.c \
+    src/core/ext/transport/chttp2/transport/frame_settings.c \
+    src/core/ext/transport/chttp2/transport/frame_window_update.c \
+    src/core/ext/transport/chttp2/transport/hpack_encoder.c \
+    src/core/ext/transport/chttp2/transport/hpack_parser.c \
+    src/core/ext/transport/chttp2/transport/hpack_table.c \
+    src/core/ext/transport/chttp2/transport/huffsyms.c \
+    src/core/ext/transport/chttp2/transport/incoming_metadata.c \
+    src/core/ext/transport/chttp2/transport/parsing.c \
+    src/core/ext/transport/chttp2/transport/status_conversion.c \
+    src/core/ext/transport/chttp2/transport/stream_lists.c \
+    src/core/ext/transport/chttp2/transport/stream_map.c \
+    src/core/ext/transport/chttp2/transport/timeout_encoding.c \
+    src/core/ext/transport/chttp2/transport/varint.c \
+    src/core/ext/transport/chttp2/transport/writing.c \
+    src/core/lib/census/context.c \
+    src/core/lib/census/grpc_context.c \
+    src/core/lib/census/grpc_filter.c \
+    src/core/lib/census/grpc_plugin.c \
+    src/core/lib/census/initialize.c \
+    src/core/lib/census/mlog.c \
+    src/core/lib/census/operation.c \
+    src/core/lib/census/placeholders.c \
+    src/core/lib/census/tracing.c \
+    src/core/lib/channel/channel_args.c \
+    src/core/lib/channel/channel_stack.c \
+    src/core/lib/channel/channel_stack_builder.c \
+    src/core/lib/channel/client_channel.c \
+    src/core/lib/channel/compress_filter.c \
+    src/core/lib/channel/connected_channel.c \
+    src/core/lib/channel/http_client_filter.c \
+    src/core/lib/channel/http_server_filter.c \
+    src/core/lib/channel/subchannel_call_holder.c \
+    src/core/lib/client_config/client_config.c \
+    src/core/lib/client_config/connector.c \
+    src/core/lib/client_config/default_initial_connect_string.c \
+    src/core/lib/client_config/initial_connect_string.c \
+    src/core/lib/client_config/lb_policies/load_balancer_api.c \
+    src/core/lib/client_config/lb_policies/pick_first.c \
+    src/core/lib/client_config/lb_policies/round_robin.c \
+    src/core/lib/client_config/lb_policy.c \
+    src/core/lib/client_config/lb_policy_factory.c \
+    src/core/lib/client_config/lb_policy_registry.c \
+    src/core/lib/client_config/resolver.c \
+    src/core/lib/client_config/resolver_factory.c \
+    src/core/lib/client_config/resolver_registry.c \
+    src/core/lib/client_config/resolvers/dns_resolver.c \
+    src/core/lib/client_config/resolvers/sockaddr_resolver.c \
+    src/core/lib/client_config/subchannel.c \
+    src/core/lib/client_config/subchannel_factory.c \
+    src/core/lib/client_config/subchannel_index.c \
+    src/core/lib/client_config/uri_parser.c \
+    src/core/lib/compression/compression_algorithm.c \
+    src/core/lib/compression/message_compress.c \
+    src/core/lib/debug/trace.c \
+    src/core/lib/http/format_request.c \
+    src/core/lib/http/httpcli.c \
+    src/core/lib/http/httpcli_security_connector.c \
+    src/core/lib/http/parser.c \
+    src/core/lib/iomgr/closure.c \
+    src/core/lib/iomgr/endpoint.c \
+    src/core/lib/iomgr/endpoint_pair_posix.c \
+    src/core/lib/iomgr/endpoint_pair_windows.c \
+    src/core/lib/iomgr/exec_ctx.c \
+    src/core/lib/iomgr/executor.c \
+    src/core/lib/iomgr/fd_posix.c \
+    src/core/lib/iomgr/iocp_windows.c \
+    src/core/lib/iomgr/iomgr.c \
+    src/core/lib/iomgr/iomgr_posix.c \
+    src/core/lib/iomgr/iomgr_windows.c \
+    src/core/lib/iomgr/pollset_multipoller_with_epoll.c \
+    src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c \
+    src/core/lib/iomgr/pollset_posix.c \
+    src/core/lib/iomgr/pollset_set_posix.c \
+    src/core/lib/iomgr/pollset_set_windows.c \
+    src/core/lib/iomgr/pollset_windows.c \
+    src/core/lib/iomgr/resolve_address_posix.c \
+    src/core/lib/iomgr/resolve_address_windows.c \
+    src/core/lib/iomgr/sockaddr_utils.c \
+    src/core/lib/iomgr/socket_utils_common_posix.c \
+    src/core/lib/iomgr/socket_utils_linux.c \
+    src/core/lib/iomgr/socket_utils_posix.c \
+    src/core/lib/iomgr/socket_windows.c \
+    src/core/lib/iomgr/tcp_client_posix.c \
+    src/core/lib/iomgr/tcp_client_windows.c \
+    src/core/lib/iomgr/tcp_posix.c \
+    src/core/lib/iomgr/tcp_server_posix.c \
+    src/core/lib/iomgr/tcp_server_windows.c \
+    src/core/lib/iomgr/tcp_windows.c \
+    src/core/lib/iomgr/time_averaged_stats.c \
+    src/core/lib/iomgr/timer.c \
+    src/core/lib/iomgr/timer_heap.c \
+    src/core/lib/iomgr/udp_server.c \
+    src/core/lib/iomgr/unix_sockets_posix.c \
+    src/core/lib/iomgr/unix_sockets_posix_noop.c \
+    src/core/lib/iomgr/wakeup_fd_eventfd.c \
+    src/core/lib/iomgr/wakeup_fd_nospecial.c \
+    src/core/lib/iomgr/wakeup_fd_pipe.c \
+    src/core/lib/iomgr/wakeup_fd_posix.c \
+    src/core/lib/iomgr/workqueue_posix.c \
+    src/core/lib/iomgr/workqueue_windows.c \
+    src/core/lib/json/json.c \
+    src/core/lib/json/json_reader.c \
+    src/core/lib/json/json_string.c \
+    src/core/lib/json/json_writer.c \
+    src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c \
+    src/core/lib/security/b64.c \
+    src/core/lib/security/client_auth_filter.c \
+    src/core/lib/security/credentials.c \
+    src/core/lib/security/credentials_metadata.c \
+    src/core/lib/security/credentials_posix.c \
+    src/core/lib/security/credentials_win32.c \
+    src/core/lib/security/google_default_credentials.c \
+    src/core/lib/security/handshake.c \
+    src/core/lib/security/json_token.c \
+    src/core/lib/security/jwt_verifier.c \
+    src/core/lib/security/secure_endpoint.c \
+    src/core/lib/security/security_connector.c \
+    src/core/lib/security/security_context.c \
+    src/core/lib/security/server_auth_filter.c \
+    src/core/lib/surface/alarm.c \
+    src/core/lib/surface/api_trace.c \
+    src/core/lib/surface/byte_buffer.c \
+    src/core/lib/surface/byte_buffer_reader.c \
+    src/core/lib/surface/call.c \
+    src/core/lib/surface/call_details.c \
+    src/core/lib/surface/call_log_batch.c \
+    src/core/lib/surface/channel.c \
+    src/core/lib/surface/channel_connectivity.c \
+    src/core/lib/surface/channel_init.c \
+    src/core/lib/surface/channel_ping.c \
+    src/core/lib/surface/channel_stack_type.c \
+    src/core/lib/surface/completion_queue.c \
+    src/core/lib/surface/event_string.c \
+    src/core/lib/surface/init.c \
+    src/core/lib/surface/init_secure.c \
+    src/core/lib/surface/lame_client.c \
+    src/core/lib/surface/metadata_array.c \
+    src/core/lib/surface/server.c \
+    src/core/lib/surface/validate_metadata.c \
+    src/core/lib/surface/version.c \
+    src/core/lib/transport/byte_stream.c \
+    src/core/lib/transport/connectivity_state.c \
+    src/core/lib/transport/metadata.c \
+    src/core/lib/transport/metadata_batch.c \
+    src/core/lib/transport/static_metadata.c \
+    src/core/lib/transport/transport.c \
+    src/core/lib/transport/transport_op_string.c \
+    src/core/lib/tsi/fake_transport_security.c \
+    src/core/lib/tsi/ssl_transport_security.c \
+    src/core/lib/tsi/transport_security.c \
     third_party/nanopb/pb_common.c \
     third_party/nanopb/pb_decode.c \
     third_party/nanopb/pb_encode.c \
@@ -541,24 +546,28 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/php/ext/grpc)
 
   PHP_ADD_BUILD_DIR($ext_builddir/src/boringssl)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/census)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/channel)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/client_config)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/client_config/lb_policies)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/client_config/resolvers)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/compression)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/debug)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/httpcli)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/iomgr)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/json)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/profiling)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/proto/grpc/lb/v0)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/security)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/support)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/surface)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/transport)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/transport/chttp2)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/core/tsi)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client/insecure)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client/secure)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/insecure)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/secure)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/transport)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/census)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/channel)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/client_config)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/client_config/lb_policies)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/client_config/resolvers)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/compression)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/debug)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/http)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/json)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/profiling)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/proto/grpc/lb/v0)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/support)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/surface)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/transport)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/tsi)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/aes)
   PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/asn1)
diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md
index 3beb1d1..6297b5c 100644
--- a/doc/interop-test-descriptions.md
+++ b/doc/interop-test-descriptions.md
@@ -27,7 +27,7 @@
     * Whether to use a plaintext or encrypted connection
 * --use_test_ca=BOOLEAN
     * Whether to replace platform root CAs with
-      [ca.pem](https://github.com/grpc/grpc/blob/master/src/core/tsi/test_creds/ca.pem)
+      [ca.pem](https://github.com/grpc/grpc/blob/master/src/core/lib/tsi/test_creds/ca.pem)
       as the CA root
 * --default_service_account=ACCOUNT_EMAIL
     * Email of the GCE default service account. Only applicable
@@ -920,7 +920,7 @@
     * Whether to use a plaintext or encrypted connection
 
 Servers must support TLS with ALPN. They should use
-[server1.pem](https://github.com/grpc/grpc/blob/master/src/core/tsi/test_creds/server1.pem)
+[server1.pem](https://github.com/grpc/grpc/blob/master/src/core/lib/tsi/test_creds/server1.pem)
 for their certificate.
 
 ### EmptyCall
diff --git a/examples/cpp/helloworld/README.md b/examples/cpp/helloworld/README.md
index 8e11f7c..04283ea 100644
--- a/examples/cpp/helloworld/README.md
+++ b/examples/cpp/helloworld/README.md
@@ -207,7 +207,7 @@
     helloworld::Greeter::AsyncService service;
     ServerBuilder builder;
     builder.AddListeningPort("0.0.0.0:50051", InsecureServerCredentials());
-    builder.RegisterAsyncService(&service);
+    builder.RegisterService(&service);
     auto cq = builder.AddCompletionQueue();
     auto server = builder.BuildAndStart();
     ```
diff --git a/examples/node/README.md b/examples/node/README.md
index c1ef6b0..2887883 100644
--- a/examples/node/README.md
+++ b/examples/node/README.md
@@ -10,6 +10,11 @@
 -------
 
    ```sh
+   $ # Get the gRPC repository
+   $ export REPO_ROOT=grpc # REPO root can be any directory of your choice
+   $ git clone https://github.com/grpc/grpc.git $REPO_ROOT
+   $ cd $REPO_ROOT
+
    $ cd examples/node
    $ npm install
    ```
diff --git a/examples/node/package.json b/examples/node/package.json
index 00ba428..d135df2 100644
--- a/examples/node/package.json
+++ b/examples/node/package.json
@@ -2,6 +2,9 @@
   "name": "grpc-examples",
   "version": "0.1.0",
   "dependencies": {
-    "grpc": "0.13.0"
+    "async": "^1.5.2",
+    "grpc": "0.13.0",
+    "lodash": "^4.6.1",
+    "minimist": "^1.2.0"
   }
 }
diff --git a/examples/php/composer.json b/examples/php/composer.json
index 9f44f0b..c837bf7 100644
--- a/examples/php/composer.json
+++ b/examples/php/composer.json
@@ -1,17 +1,14 @@
 {
+  "name": "grpc/grpc-demo",
+  "description": "gRPC example for PHP",
+  "minimum-stability": "dev",
   "repositories": [
     {
       "type": "vcs",
       "url": "https://github.com/stanley-cheung/Protobuf-PHP"
     }
   ],
-  "name": "grpc/grpc-demo",
-  "description": "gRPC example for PHP",
-  "minimum-stability": "dev",
   "require": {
-    "php": ">=5.5.0",
-    "datto/protobuf-php": "dev-master",
-    "google/auth": "dev-master",
-    "grpc/grpc": "dev-release-0_11"
+    "grpc/grpc": "dev-release-0_13"
   }
 }
diff --git a/examples/php/greeter_client.php b/examples/php/greeter_client.php
index e5e4c26..3fab14f 100644
--- a/examples/php/greeter_client.php
+++ b/examples/php/greeter_client.php
@@ -1,7 +1,7 @@
 <?php
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,7 +36,9 @@
 require dirname(__FILE__) . '/helloworld.php';
 
 function greet($name) {
-  $client = new helloworld\GreeterClient('localhost:50051', []);
+  $client = new helloworld\GreeterClient('localhost:50051', [
+    'credentials' => Grpc\ChannelCredentials::createInsecure()
+  ]);
   $request = new helloworld\HelloRequest();
   $request->setName($name);
   list($reply, $status) = $client->SayHello($request)->wait();
diff --git a/examples/php/route_guide/route_guide_client.php b/examples/php/route_guide/route_guide_client.php
index 3cd1df7..cc8640c 100644
--- a/examples/php/route_guide/route_guide_client.php
+++ b/examples/php/route_guide/route_guide_client.php
@@ -1,7 +1,7 @@
 <?php
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,7 +37,9 @@
 
 define('COORD_FACTOR', 1e7);
 
-$client = new routeguide\RouteGuideClient('localhost:50051', []);
+$client = new routeguide\RouteGuideClient('localhost:50051', [
+  'credentials' => Grpc\ChannelCredentials::createInsecure()
+]);
 
 function printFeature($feature) {
   $name = $feature->getName();
diff --git a/examples/python/helloworld/greeter_client.py b/examples/python/helloworld/greeter_client.py
index 561b25b..9c18b41 100644
--- a/examples/python/helloworld/greeter_client.py
+++ b/examples/python/helloworld/greeter_client.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,6 +29,8 @@
 
 """The Python implementation of the GRPC helloworld.Greeter client."""
 
+from __future__ import print_function
+
 from grpc.beta import implementations
 
 import helloworld_pb2
@@ -40,7 +42,7 @@
   channel = implementations.insecure_channel('localhost', 50051)
   stub = helloworld_pb2.beta_create_Greeter_stub(channel)
   response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'), _TIMEOUT_SECONDS)
-  print "Greeter client received: " + response.message
+  print("Greeter client received: " + response.message)
 
 
 if __name__ == '__main__':
diff --git a/examples/python/route_guide/route_guide_client.py b/examples/python/route_guide/route_guide_client.py
index b1dfad5..9d6f865 100644
--- a/examples/python/route_guide/route_guide_client.py
+++ b/examples/python/route_guide/route_guide_client.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,6 +29,8 @@
 
 """The Python implementation of the gRPC route guide client."""
 
+from __future__ import print_function
+
 import random
 import time
 
@@ -49,13 +51,13 @@
 def guide_get_one_feature(stub, point):
   feature = stub.GetFeature(point, _TIMEOUT_SECONDS)
   if not feature.location:
-    print "Server returned incomplete feature"
+    print("Server returned incomplete feature")
     return
 
   if feature.name:
-    print "Feature called %s at %s" % (feature.name, feature.location)
+    print("Feature called %s at %s" % (feature.name, feature.location))
   else:
-    print "Found no feature at %s" % feature.location
+    print("Found no feature at %s" % feature.location)
 
 
 def guide_get_feature(stub):
@@ -69,18 +71,18 @@
           latitude=400000000, longitude = -750000000),
       hi=route_guide_pb2.Point(
           latitude = 420000000, longitude = -730000000))
-  print "Looking for features between 40, -75 and 42, -73"
+  print("Looking for features between 40, -75 and 42, -73")
 
   features = stub.ListFeatures(rect, _TIMEOUT_SECONDS)
 
   for feature in features:
-    print "Feature called %s at %s" % (feature.name, feature.location)
+    print("Feature called %s at %s" % (feature.name, feature.location))
 
 
 def generate_route(feature_list):
   for _ in range(0, 10):
     random_feature = feature_list[random.randint(0, len(feature_list) - 1)]
-    print "Visiting point %s" % random_feature.location
+    print("Visiting point %s" % random_feature.location)
     yield random_feature.location
     time.sleep(random.uniform(0.5, 1.5))
 
@@ -90,10 +92,10 @@
 
   route_iter = generate_route(feature_list)
   route_summary = stub.RecordRoute(route_iter, _TIMEOUT_SECONDS)
-  print "Finished trip with %s points " % route_summary.point_count
-  print "Passed %s features " % route_summary.feature_count
-  print "Travelled %s meters " % route_summary.distance
-  print "It took %s seconds " % route_summary.elapsed_time
+  print("Finished trip with %s points " % route_summary.point_count)
+  print("Passed %s features " % route_summary.feature_count)
+  print("Travelled %s meters " % route_summary.distance)
+  print("It took %s seconds " % route_summary.elapsed_time)
 
 
 def generate_messages():
@@ -105,7 +107,7 @@
       make_route_note("Fifth message", 1, 0),
   ]
   for msg in messages:
-    print "Sending %s at %s" % (msg.message, msg.location)
+    print("Sending %s at %s" % (msg.message, msg.location))
     yield msg
     time.sleep(random.uniform(0.5, 1.0))
 
@@ -113,19 +115,19 @@
 def guide_route_chat(stub):
   responses = stub.RouteChat(generate_messages(), _TIMEOUT_SECONDS)
   for response in responses:
-    print "Received message %s at %s" % (response.message, response.location)
+    print("Received message %s at %s" % (response.message, response.location))
 
 
 def run():
   channel = implementations.insecure_channel('localhost', 50051)
   stub = route_guide_pb2.beta_create_RouteGuide_stub(channel)
-  print "-------------- GetFeature --------------"
+  print("-------------- GetFeature --------------")
   guide_get_feature(stub)
-  print "-------------- ListFeatures --------------"
+  print("-------------- ListFeatures --------------")
   guide_list_features(stub)
-  print "-------------- RecordRoute --------------"
+  print("-------------- RecordRoute --------------")
   guide_record_route(stub)
-  print "-------------- RouteChat --------------"
+  print("-------------- RouteChat --------------")
   guide_route_chat(stub)
 
 
diff --git a/examples/ruby/route_guide/route_guide_client.rb b/examples/ruby/route_guide/route_guide_client.rb
index 715a3c0..86dd1fe 100755
--- a/examples/ruby/route_guide/route_guide_client.rb
+++ b/examples/ruby/route_guide/route_guide_client.rb
@@ -38,6 +38,7 @@
 $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
 
 require 'grpc'
+require 'multi_json'
 require 'route_guide_services'
 
 include Routeguide
@@ -115,9 +116,8 @@
   p 'RecordRoute'
   p '-----------'
   points_on_route = 10  # arbitrary
-  deadline = points_on_route  # as delay b/w each is max 1 second
   reqs = RandomRoute.new(features, points_on_route)
-  resp = stub.record_route(reqs.each, deadline)
+  resp = stub.record_route(reqs.each)
   p "summary: #{resp.inspect}"
 end
 
diff --git a/gRPC.podspec b/gRPC.podspec
index f3103ea..08330eb 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -63,17 +63,32 @@
 
   # Core cross-platform gRPC library, written in C.
   s.subspec 'C-Core' do |ss|
-    ss.source_files = 'src/core/profiling/timers.h',
-                      'src/core/support/block_annotate.h',
-                      'src/core/support/env.h',
-                      'src/core/support/load_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/time_precise.h',
-                      'src/core/support/tmpfile.h',
+    ss.source_files = 'src/core/lib/profiling/timers.h',
+                      'src/core/lib/support/backoff.h',
+                      'src/core/lib/support/block_annotate.h',
+                      'src/core/lib/support/env.h',
+                      'src/core/lib/support/load_file.h',
+                      'src/core/lib/support/murmur_hash.h',
+                      'src/core/lib/support/stack_lockfree.h',
+                      'src/core/lib/support/string.h',
+                      'src/core/lib/support/string_win32.h',
+                      'src/core/lib/support/thd_internal.h',
+                      'src/core/lib/support/time_precise.h',
+                      'src/core/lib/support/tmpfile.h',
+                      'include/grpc/impl/codegen/alloc.h',
+                      'include/grpc/impl/codegen/atm.h',
+                      'include/grpc/impl/codegen/atm_gcc_atomic.h',
+                      'include/grpc/impl/codegen/atm_gcc_sync.h',
+                      'include/grpc/impl/codegen/atm_win32.h',
+                      'include/grpc/impl/codegen/log.h',
+                      'include/grpc/impl/codegen/port_platform.h',
+                      'include/grpc/impl/codegen/slice.h',
+                      'include/grpc/impl/codegen/slice_buffer.h',
+                      'include/grpc/impl/codegen/sync.h',
+                      'include/grpc/impl/codegen/sync_generic.h',
+                      'include/grpc/impl/codegen/sync_posix.h',
+                      'include/grpc/impl/codegen/sync_win32.h',
+                      'include/grpc/impl/codegen/time.h',
                       'include/grpc/support/alloc.h',
                       'include/grpc/support/atm.h',
                       'include/grpc/support/atm_gcc_atomic.h',
@@ -102,199 +117,196 @@
                       'include/grpc/support/tls_msvc.h',
                       'include/grpc/support/tls_pthread.h',
                       'include/grpc/support/useful.h',
-                      'include/grpc/impl/codegen/alloc.h',
-                      'include/grpc/impl/codegen/atm.h',
-                      'include/grpc/impl/codegen/atm_gcc_atomic.h',
-                      'include/grpc/impl/codegen/atm_gcc_sync.h',
-                      'include/grpc/impl/codegen/atm_win32.h',
-                      'include/grpc/impl/codegen/log.h',
-                      'include/grpc/impl/codegen/port_platform.h',
-                      'include/grpc/impl/codegen/slice.h',
-                      'include/grpc/impl/codegen/slice_buffer.h',
-                      'include/grpc/impl/codegen/sync.h',
-                      'include/grpc/impl/codegen/sync_generic.h',
-                      'include/grpc/impl/codegen/sync_posix.h',
-                      'include/grpc/impl/codegen/sync_win32.h',
-                      'include/grpc/impl/codegen/time.h',
-                      'src/core/profiling/basic_timers.c',
-                      'src/core/profiling/stap_timers.c',
-                      'src/core/support/alloc.c',
-                      'src/core/support/avl.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/histogram.c',
-                      'src/core/support/host_port.c',
-                      'src/core/support/load_file.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/subprocess_windows.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_precise.c',
-                      'src/core/support/time_win32.c',
-                      'src/core/support/tls_pthread.c',
-                      'src/core/support/tmpfile_posix.c',
-                      'src/core/support/tmpfile_win32.c',
-                      'src/core/support/wrap_memcpy.c',
-                      'src/core/census/grpc_filter.h',
-                      'src/core/channel/channel_args.h',
-                      'src/core/channel/channel_stack.h',
-                      'src/core/channel/client_channel.h',
-                      'src/core/channel/client_uchannel.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/subchannel_call_holder.h',
-                      'src/core/client_config/client_config.h',
-                      'src/core/client_config/connector.h',
-                      'src/core/client_config/initial_connect_string.h',
-                      'src/core/client_config/lb_policies/load_balancer_api.h',
-                      'src/core/client_config/lb_policies/pick_first.h',
-                      'src/core/client_config/lb_policies/round_robin.h',
-                      'src/core/client_config/lb_policy.h',
-                      'src/core/client_config/lb_policy_factory.h',
-                      'src/core/client_config/lb_policy_registry.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/sockaddr_resolver.h',
-                      'src/core/client_config/subchannel.h',
-                      'src/core/client_config/subchannel_factory.h',
-                      'src/core/client_config/subchannel_index.h',
-                      'src/core/client_config/uri_parser.h',
-                      'src/core/compression/algorithm_metadata.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/parser.h',
-                      'src/core/iomgr/closure.h',
-                      'src/core/iomgr/endpoint.h',
-                      'src/core/iomgr/endpoint_pair.h',
-                      'src/core/iomgr/exec_ctx.h',
-                      'src/core/iomgr/executor.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_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/timer.h',
-                      'src/core/iomgr/timer_heap.h',
-                      'src/core/iomgr/udp_server.h',
-                      'src/core/iomgr/wakeup_fd_pipe.h',
-                      'src/core/iomgr/wakeup_fd_posix.h',
-                      'src/core/iomgr/workqueue.h',
-                      'src/core/iomgr/workqueue_posix.h',
-                      'src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.h',
-                      'src/core/statistics/census_interface.h',
-                      'src/core/statistics/census_rpc_stats.h',
-                      'src/core/surface/api_trace.h',
-                      'src/core/surface/call.h',
-                      'src/core/surface/call_test_only.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/byte_stream.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_encoder.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_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/metadata_batch.h',
-                      'src/core/transport/static_metadata.h',
-                      'src/core/transport/transport.h',
-                      'src/core/transport/transport_impl.h',
-                      'src/core/security/auth_filters.h',
-                      'src/core/security/b64.h',
-                      'src/core/security/credentials.h',
-                      'src/core/security/handshake.h',
-                      'src/core/security/json_token.h',
-                      'src/core/security/jwt_verifier.h',
-                      'src/core/security/secure_endpoint.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/ssl_types.h',
-                      'src/core/tsi/transport_security.h',
-                      'src/core/tsi/transport_security_interface.h',
-                      'src/core/census/aggregation.h',
-                      'src/core/census/mlog.h',
-                      'src/core/census/rpc_metric_id.h',
+                      'src/core/lib/profiling/basic_timers.c',
+                      'src/core/lib/profiling/stap_timers.c',
+                      'src/core/lib/support/alloc.c',
+                      'src/core/lib/support/avl.c',
+                      'src/core/lib/support/backoff.c',
+                      'src/core/lib/support/cmdline.c',
+                      'src/core/lib/support/cpu_iphone.c',
+                      'src/core/lib/support/cpu_linux.c',
+                      'src/core/lib/support/cpu_posix.c',
+                      'src/core/lib/support/cpu_windows.c',
+                      'src/core/lib/support/env_linux.c',
+                      'src/core/lib/support/env_posix.c',
+                      'src/core/lib/support/env_win32.c',
+                      'src/core/lib/support/histogram.c',
+                      'src/core/lib/support/host_port.c',
+                      'src/core/lib/support/load_file.c',
+                      'src/core/lib/support/log.c',
+                      'src/core/lib/support/log_android.c',
+                      'src/core/lib/support/log_linux.c',
+                      'src/core/lib/support/log_posix.c',
+                      'src/core/lib/support/log_win32.c',
+                      'src/core/lib/support/murmur_hash.c',
+                      'src/core/lib/support/slice.c',
+                      'src/core/lib/support/slice_buffer.c',
+                      'src/core/lib/support/stack_lockfree.c',
+                      'src/core/lib/support/string.c',
+                      'src/core/lib/support/string_posix.c',
+                      'src/core/lib/support/string_win32.c',
+                      'src/core/lib/support/subprocess_posix.c',
+                      'src/core/lib/support/subprocess_windows.c',
+                      'src/core/lib/support/sync.c',
+                      'src/core/lib/support/sync_posix.c',
+                      'src/core/lib/support/sync_win32.c',
+                      'src/core/lib/support/thd.c',
+                      'src/core/lib/support/thd_posix.c',
+                      'src/core/lib/support/thd_win32.c',
+                      'src/core/lib/support/time.c',
+                      'src/core/lib/support/time_posix.c',
+                      'src/core/lib/support/time_precise.c',
+                      'src/core/lib/support/time_win32.c',
+                      'src/core/lib/support/tls_pthread.c',
+                      'src/core/lib/support/tmpfile_posix.c',
+                      'src/core/lib/support/tmpfile_win32.c',
+                      'src/core/lib/support/wrap_memcpy.c',
+                      'src/core/ext/transport/chttp2/transport/alpn.h',
+                      'src/core/ext/transport/chttp2/transport/bin_encoder.h',
+                      'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
+                      'src/core/ext/transport/chttp2/transport/frame.h',
+                      'src/core/ext/transport/chttp2/transport/frame_data.h',
+                      'src/core/ext/transport/chttp2/transport/frame_goaway.h',
+                      'src/core/ext/transport/chttp2/transport/frame_ping.h',
+                      'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
+                      'src/core/ext/transport/chttp2/transport/frame_settings.h',
+                      'src/core/ext/transport/chttp2/transport/frame_window_update.h',
+                      'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
+                      'src/core/ext/transport/chttp2/transport/hpack_parser.h',
+                      'src/core/ext/transport/chttp2/transport/hpack_table.h',
+                      'src/core/ext/transport/chttp2/transport/http2_errors.h',
+                      'src/core/ext/transport/chttp2/transport/huffsyms.h',
+                      'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
+                      'src/core/ext/transport/chttp2/transport/internal.h',
+                      'src/core/ext/transport/chttp2/transport/status_conversion.h',
+                      'src/core/ext/transport/chttp2/transport/stream_map.h',
+                      'src/core/ext/transport/chttp2/transport/timeout_encoding.h',
+                      'src/core/ext/transport/chttp2/transport/varint.h',
+                      'src/core/lib/census/aggregation.h',
+                      'src/core/lib/census/grpc_filter.h',
+                      'src/core/lib/census/grpc_plugin.h',
+                      'src/core/lib/census/mlog.h',
+                      'src/core/lib/census/rpc_metric_id.h',
+                      'src/core/lib/channel/channel_args.h',
+                      'src/core/lib/channel/channel_stack.h',
+                      'src/core/lib/channel/channel_stack_builder.h',
+                      'src/core/lib/channel/client_channel.h',
+                      'src/core/lib/channel/compress_filter.h',
+                      'src/core/lib/channel/connected_channel.h',
+                      'src/core/lib/channel/context.h',
+                      'src/core/lib/channel/http_client_filter.h',
+                      'src/core/lib/channel/http_server_filter.h',
+                      'src/core/lib/channel/subchannel_call_holder.h',
+                      'src/core/lib/client_config/client_config.h',
+                      'src/core/lib/client_config/connector.h',
+                      'src/core/lib/client_config/initial_connect_string.h',
+                      'src/core/lib/client_config/lb_policies/load_balancer_api.h',
+                      'src/core/lib/client_config/lb_policies/pick_first.h',
+                      'src/core/lib/client_config/lb_policies/round_robin.h',
+                      'src/core/lib/client_config/lb_policy.h',
+                      'src/core/lib/client_config/lb_policy_factory.h',
+                      'src/core/lib/client_config/lb_policy_registry.h',
+                      'src/core/lib/client_config/resolver.h',
+                      'src/core/lib/client_config/resolver_factory.h',
+                      'src/core/lib/client_config/resolver_registry.h',
+                      'src/core/lib/client_config/resolvers/dns_resolver.h',
+                      'src/core/lib/client_config/resolvers/sockaddr_resolver.h',
+                      'src/core/lib/client_config/subchannel.h',
+                      'src/core/lib/client_config/subchannel_factory.h',
+                      'src/core/lib/client_config/subchannel_index.h',
+                      'src/core/lib/client_config/uri_parser.h',
+                      'src/core/lib/compression/algorithm_metadata.h',
+                      'src/core/lib/compression/message_compress.h',
+                      'src/core/lib/debug/trace.h',
+                      'src/core/lib/http/format_request.h',
+                      'src/core/lib/http/httpcli.h',
+                      'src/core/lib/http/parser.h',
+                      'src/core/lib/iomgr/closure.h',
+                      'src/core/lib/iomgr/endpoint.h',
+                      'src/core/lib/iomgr/endpoint_pair.h',
+                      'src/core/lib/iomgr/exec_ctx.h',
+                      'src/core/lib/iomgr/executor.h',
+                      'src/core/lib/iomgr/fd_posix.h',
+                      'src/core/lib/iomgr/iocp_windows.h',
+                      'src/core/lib/iomgr/iomgr.h',
+                      'src/core/lib/iomgr/iomgr_internal.h',
+                      'src/core/lib/iomgr/iomgr_posix.h',
+                      'src/core/lib/iomgr/pollset.h',
+                      'src/core/lib/iomgr/pollset_posix.h',
+                      'src/core/lib/iomgr/pollset_set.h',
+                      'src/core/lib/iomgr/pollset_set_posix.h',
+                      'src/core/lib/iomgr/pollset_set_windows.h',
+                      'src/core/lib/iomgr/pollset_windows.h',
+                      'src/core/lib/iomgr/resolve_address.h',
+                      'src/core/lib/iomgr/sockaddr.h',
+                      'src/core/lib/iomgr/sockaddr_posix.h',
+                      'src/core/lib/iomgr/sockaddr_utils.h',
+                      'src/core/lib/iomgr/sockaddr_win32.h',
+                      'src/core/lib/iomgr/socket_utils_posix.h',
+                      'src/core/lib/iomgr/socket_windows.h',
+                      'src/core/lib/iomgr/tcp_client.h',
+                      'src/core/lib/iomgr/tcp_posix.h',
+                      'src/core/lib/iomgr/tcp_server.h',
+                      'src/core/lib/iomgr/tcp_windows.h',
+                      'src/core/lib/iomgr/time_averaged_stats.h',
+                      'src/core/lib/iomgr/timer.h',
+                      'src/core/lib/iomgr/timer_heap.h',
+                      'src/core/lib/iomgr/udp_server.h',
+                      'src/core/lib/iomgr/unix_sockets_posix.h',
+                      'src/core/lib/iomgr/wakeup_fd_pipe.h',
+                      'src/core/lib/iomgr/wakeup_fd_posix.h',
+                      'src/core/lib/iomgr/workqueue.h',
+                      'src/core/lib/iomgr/workqueue_posix.h',
+                      'src/core/lib/iomgr/workqueue_windows.h',
+                      'src/core/lib/json/json.h',
+                      'src/core/lib/json/json_common.h',
+                      'src/core/lib/json/json_reader.h',
+                      'src/core/lib/json/json_writer.h',
+                      'src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h',
+                      'src/core/lib/security/auth_filters.h',
+                      'src/core/lib/security/b64.h',
+                      'src/core/lib/security/credentials.h',
+                      'src/core/lib/security/handshake.h',
+                      'src/core/lib/security/json_token.h',
+                      'src/core/lib/security/jwt_verifier.h',
+                      'src/core/lib/security/secure_endpoint.h',
+                      'src/core/lib/security/security_connector.h',
+                      'src/core/lib/security/security_context.h',
+                      'src/core/lib/statistics/census_interface.h',
+                      'src/core/lib/statistics/census_rpc_stats.h',
+                      'src/core/lib/surface/api_trace.h',
+                      'src/core/lib/surface/call.h',
+                      'src/core/lib/surface/call_test_only.h',
+                      'src/core/lib/surface/channel.h',
+                      'src/core/lib/surface/channel_init.h',
+                      'src/core/lib/surface/channel_stack_type.h',
+                      'src/core/lib/surface/completion_queue.h',
+                      'src/core/lib/surface/event_string.h',
+                      'src/core/lib/surface/init.h',
+                      'src/core/lib/surface/lame_client.h',
+                      'src/core/lib/surface/server.h',
+                      'src/core/lib/surface/surface_trace.h',
+                      'src/core/lib/transport/byte_stream.h',
+                      'src/core/lib/transport/connectivity_state.h',
+                      'src/core/lib/transport/metadata.h',
+                      'src/core/lib/transport/metadata_batch.h',
+                      'src/core/lib/transport/static_metadata.h',
+                      'src/core/lib/transport/transport.h',
+                      'src/core/lib/transport/transport_impl.h',
+                      'src/core/lib/tsi/fake_transport_security.h',
+                      'src/core/lib/tsi/ssl_transport_security.h',
+                      'src/core/lib/tsi/ssl_types.h',
+                      'src/core/lib/tsi/transport_security.h',
+                      'src/core/lib/tsi/transport_security_interface.h',
                       'third_party/nanopb/pb.h',
                       'third_party/nanopb/pb_common.h',
                       'third_party/nanopb/pb_decode.h',
                       'third_party/nanopb/pb_encode.h',
+                      '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/impl/codegen/byte_buffer.h',
                       'include/grpc/impl/codegen/compression_types.h',
@@ -302,316 +314,321 @@
                       'include/grpc/impl/codegen/grpc_types.h',
                       'include/grpc/impl/codegen/propagation_bits.h',
                       'include/grpc/impl/codegen/status.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/census/grpc_context.c',
-                      'src/core/census/grpc_filter.c',
-                      'src/core/channel/channel_args.c',
-                      'src/core/channel/channel_stack.c',
-                      'src/core/channel/client_channel.c',
-                      'src/core/channel/client_uchannel.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/subchannel_call_holder.c',
-                      'src/core/client_config/client_config.c',
-                      'src/core/client_config/connector.c',
-                      'src/core/client_config/default_initial_connect_string.c',
-                      'src/core/client_config/initial_connect_string.c',
-                      'src/core/client_config/lb_policies/load_balancer_api.c',
-                      'src/core/client_config/lb_policies/pick_first.c',
-                      'src/core/client_config/lb_policies/round_robin.c',
-                      'src/core/client_config/lb_policy.c',
-                      'src/core/client_config/lb_policy_factory.c',
-                      'src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c',
-                      'src/core/client_config/subchannel.c',
-                      'src/core/client_config/subchannel_factory.c',
-                      'src/core/client_config/subchannel_index.c',
-                      'src/core/client_config/uri_parser.c',
-                      'src/core/compression/compression_algorithm.c',
-                      'src/core/compression/message_compress.c',
-                      'src/core/debug/trace.c',
-                      'src/core/httpcli/format_request.c',
-                      'src/core/httpcli/httpcli.c',
-                      'src/core/httpcli/parser.c',
-                      'src/core/iomgr/closure.c',
-                      'src/core/iomgr/endpoint.c',
-                      'src/core/iomgr/endpoint_pair_posix.c',
-                      'src/core/iomgr/endpoint_pair_windows.c',
-                      'src/core/iomgr/exec_ctx.c',
-                      'src/core/iomgr/executor.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_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/timer.c',
-                      'src/core/iomgr/timer_heap.c',
-                      'src/core/iomgr/udp_server.c',
-                      'src/core/iomgr/wakeup_fd_eventfd.c',
-                      'src/core/iomgr/wakeup_fd_nospecial.c',
-                      'src/core/iomgr/wakeup_fd_pipe.c',
-                      'src/core/iomgr/wakeup_fd_posix.c',
-                      'src/core/iomgr/workqueue_posix.c',
-                      'src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c',
-                      'src/core/surface/alarm.c',
-                      'src/core/surface/api_trace.c',
-                      'src/core/surface/byte_buffer.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_connectivity.c',
-                      'src/core/surface/channel_create.c',
-                      'src/core/surface/channel_ping.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/validate_metadata.c',
-                      'src/core/surface/version.c',
-                      'src/core/transport/byte_stream.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_encoder.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_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/metadata_batch.c',
-                      'src/core/transport/static_metadata.c',
-                      'src/core/transport/transport.c',
-                      'src/core/transport/transport_op_string.c',
-                      'src/core/httpcli/httpcli_security_connector.c',
-                      'src/core/security/b64.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/handshake.c',
-                      'src/core/security/json_token.c',
-                      'src/core/security/jwt_verifier.c',
-                      'src/core/security/secure_endpoint.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/context.c',
-                      'src/core/census/initialize.c',
-                      'src/core/census/mlog.c',
-                      'src/core/census/operation.c',
-                      'src/core/census/placeholders.c',
-                      'src/core/census/tracing.c',
+                      'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
+                      'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
+                      'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
+                      'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c',
+                      'src/core/ext/transport/chttp2/transport/alpn.c',
+                      'src/core/ext/transport/chttp2/transport/bin_encoder.c',
+                      'src/core/ext/transport/chttp2/transport/chttp2_transport.c',
+                      'src/core/ext/transport/chttp2/transport/frame_data.c',
+                      'src/core/ext/transport/chttp2/transport/frame_goaway.c',
+                      'src/core/ext/transport/chttp2/transport/frame_ping.c',
+                      'src/core/ext/transport/chttp2/transport/frame_rst_stream.c',
+                      'src/core/ext/transport/chttp2/transport/frame_settings.c',
+                      'src/core/ext/transport/chttp2/transport/frame_window_update.c',
+                      'src/core/ext/transport/chttp2/transport/hpack_encoder.c',
+                      'src/core/ext/transport/chttp2/transport/hpack_parser.c',
+                      'src/core/ext/transport/chttp2/transport/hpack_table.c',
+                      'src/core/ext/transport/chttp2/transport/huffsyms.c',
+                      'src/core/ext/transport/chttp2/transport/incoming_metadata.c',
+                      'src/core/ext/transport/chttp2/transport/parsing.c',
+                      'src/core/ext/transport/chttp2/transport/status_conversion.c',
+                      'src/core/ext/transport/chttp2/transport/stream_lists.c',
+                      'src/core/ext/transport/chttp2/transport/stream_map.c',
+                      'src/core/ext/transport/chttp2/transport/timeout_encoding.c',
+                      'src/core/ext/transport/chttp2/transport/varint.c',
+                      'src/core/ext/transport/chttp2/transport/writing.c',
+                      'src/core/lib/census/context.c',
+                      'src/core/lib/census/grpc_context.c',
+                      'src/core/lib/census/grpc_filter.c',
+                      'src/core/lib/census/grpc_plugin.c',
+                      'src/core/lib/census/initialize.c',
+                      'src/core/lib/census/mlog.c',
+                      'src/core/lib/census/operation.c',
+                      'src/core/lib/census/placeholders.c',
+                      'src/core/lib/census/tracing.c',
+                      'src/core/lib/channel/channel_args.c',
+                      'src/core/lib/channel/channel_stack.c',
+                      'src/core/lib/channel/channel_stack_builder.c',
+                      'src/core/lib/channel/client_channel.c',
+                      'src/core/lib/channel/compress_filter.c',
+                      'src/core/lib/channel/connected_channel.c',
+                      'src/core/lib/channel/http_client_filter.c',
+                      'src/core/lib/channel/http_server_filter.c',
+                      'src/core/lib/channel/subchannel_call_holder.c',
+                      'src/core/lib/client_config/client_config.c',
+                      'src/core/lib/client_config/connector.c',
+                      'src/core/lib/client_config/default_initial_connect_string.c',
+                      'src/core/lib/client_config/initial_connect_string.c',
+                      'src/core/lib/client_config/lb_policies/load_balancer_api.c',
+                      'src/core/lib/client_config/lb_policies/pick_first.c',
+                      'src/core/lib/client_config/lb_policies/round_robin.c',
+                      'src/core/lib/client_config/lb_policy.c',
+                      'src/core/lib/client_config/lb_policy_factory.c',
+                      'src/core/lib/client_config/lb_policy_registry.c',
+                      'src/core/lib/client_config/resolver.c',
+                      'src/core/lib/client_config/resolver_factory.c',
+                      'src/core/lib/client_config/resolver_registry.c',
+                      'src/core/lib/client_config/resolvers/dns_resolver.c',
+                      'src/core/lib/client_config/resolvers/sockaddr_resolver.c',
+                      'src/core/lib/client_config/subchannel.c',
+                      'src/core/lib/client_config/subchannel_factory.c',
+                      'src/core/lib/client_config/subchannel_index.c',
+                      'src/core/lib/client_config/uri_parser.c',
+                      'src/core/lib/compression/compression_algorithm.c',
+                      'src/core/lib/compression/message_compress.c',
+                      'src/core/lib/debug/trace.c',
+                      'src/core/lib/http/format_request.c',
+                      'src/core/lib/http/httpcli.c',
+                      'src/core/lib/http/httpcli_security_connector.c',
+                      'src/core/lib/http/parser.c',
+                      'src/core/lib/iomgr/closure.c',
+                      'src/core/lib/iomgr/endpoint.c',
+                      'src/core/lib/iomgr/endpoint_pair_posix.c',
+                      'src/core/lib/iomgr/endpoint_pair_windows.c',
+                      'src/core/lib/iomgr/exec_ctx.c',
+                      'src/core/lib/iomgr/executor.c',
+                      'src/core/lib/iomgr/fd_posix.c',
+                      'src/core/lib/iomgr/iocp_windows.c',
+                      'src/core/lib/iomgr/iomgr.c',
+                      'src/core/lib/iomgr/iomgr_posix.c',
+                      'src/core/lib/iomgr/iomgr_windows.c',
+                      'src/core/lib/iomgr/pollset_multipoller_with_epoll.c',
+                      'src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c',
+                      'src/core/lib/iomgr/pollset_posix.c',
+                      'src/core/lib/iomgr/pollset_set_posix.c',
+                      'src/core/lib/iomgr/pollset_set_windows.c',
+                      'src/core/lib/iomgr/pollset_windows.c',
+                      'src/core/lib/iomgr/resolve_address_posix.c',
+                      'src/core/lib/iomgr/resolve_address_windows.c',
+                      'src/core/lib/iomgr/sockaddr_utils.c',
+                      'src/core/lib/iomgr/socket_utils_common_posix.c',
+                      'src/core/lib/iomgr/socket_utils_linux.c',
+                      'src/core/lib/iomgr/socket_utils_posix.c',
+                      'src/core/lib/iomgr/socket_windows.c',
+                      'src/core/lib/iomgr/tcp_client_posix.c',
+                      'src/core/lib/iomgr/tcp_client_windows.c',
+                      'src/core/lib/iomgr/tcp_posix.c',
+                      'src/core/lib/iomgr/tcp_server_posix.c',
+                      'src/core/lib/iomgr/tcp_server_windows.c',
+                      'src/core/lib/iomgr/tcp_windows.c',
+                      'src/core/lib/iomgr/time_averaged_stats.c',
+                      'src/core/lib/iomgr/timer.c',
+                      'src/core/lib/iomgr/timer_heap.c',
+                      'src/core/lib/iomgr/udp_server.c',
+                      'src/core/lib/iomgr/unix_sockets_posix.c',
+                      'src/core/lib/iomgr/unix_sockets_posix_noop.c',
+                      'src/core/lib/iomgr/wakeup_fd_eventfd.c',
+                      'src/core/lib/iomgr/wakeup_fd_nospecial.c',
+                      'src/core/lib/iomgr/wakeup_fd_pipe.c',
+                      'src/core/lib/iomgr/wakeup_fd_posix.c',
+                      'src/core/lib/iomgr/workqueue_posix.c',
+                      'src/core/lib/iomgr/workqueue_windows.c',
+                      'src/core/lib/json/json.c',
+                      'src/core/lib/json/json_reader.c',
+                      'src/core/lib/json/json_string.c',
+                      'src/core/lib/json/json_writer.c',
+                      'src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c',
+                      'src/core/lib/security/b64.c',
+                      'src/core/lib/security/client_auth_filter.c',
+                      'src/core/lib/security/credentials.c',
+                      'src/core/lib/security/credentials_metadata.c',
+                      'src/core/lib/security/credentials_posix.c',
+                      'src/core/lib/security/credentials_win32.c',
+                      'src/core/lib/security/google_default_credentials.c',
+                      'src/core/lib/security/handshake.c',
+                      'src/core/lib/security/json_token.c',
+                      'src/core/lib/security/jwt_verifier.c',
+                      'src/core/lib/security/secure_endpoint.c',
+                      'src/core/lib/security/security_connector.c',
+                      'src/core/lib/security/security_context.c',
+                      'src/core/lib/security/server_auth_filter.c',
+                      'src/core/lib/surface/alarm.c',
+                      'src/core/lib/surface/api_trace.c',
+                      'src/core/lib/surface/byte_buffer.c',
+                      'src/core/lib/surface/byte_buffer_reader.c',
+                      'src/core/lib/surface/call.c',
+                      'src/core/lib/surface/call_details.c',
+                      'src/core/lib/surface/call_log_batch.c',
+                      'src/core/lib/surface/channel.c',
+                      'src/core/lib/surface/channel_connectivity.c',
+                      'src/core/lib/surface/channel_init.c',
+                      'src/core/lib/surface/channel_ping.c',
+                      'src/core/lib/surface/channel_stack_type.c',
+                      'src/core/lib/surface/completion_queue.c',
+                      'src/core/lib/surface/event_string.c',
+                      'src/core/lib/surface/init.c',
+                      'src/core/lib/surface/init_secure.c',
+                      'src/core/lib/surface/lame_client.c',
+                      'src/core/lib/surface/metadata_array.c',
+                      'src/core/lib/surface/server.c',
+                      'src/core/lib/surface/validate_metadata.c',
+                      'src/core/lib/surface/version.c',
+                      'src/core/lib/transport/byte_stream.c',
+                      'src/core/lib/transport/connectivity_state.c',
+                      'src/core/lib/transport/metadata.c',
+                      'src/core/lib/transport/metadata_batch.c',
+                      'src/core/lib/transport/static_metadata.c',
+                      'src/core/lib/transport/transport.c',
+                      'src/core/lib/transport/transport_op_string.c',
+                      'src/core/lib/tsi/fake_transport_security.c',
+                      'src/core/lib/tsi/ssl_transport_security.c',
+                      'src/core/lib/tsi/transport_security.c',
                       'third_party/nanopb/pb_common.c',
                       'third_party/nanopb/pb_decode.c',
                       'third_party/nanopb/pb_encode.c'
 
-    ss.private_header_files = 'src/core/profiling/timers.h',
-                              'src/core/support/block_annotate.h',
-                              'src/core/support/env.h',
-                              'src/core/support/load_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/time_precise.h',
-                              'src/core/support/tmpfile.h',
-                              'src/core/census/grpc_filter.h',
-                              'src/core/channel/channel_args.h',
-                              'src/core/channel/channel_stack.h',
-                              'src/core/channel/client_channel.h',
-                              'src/core/channel/client_uchannel.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/subchannel_call_holder.h',
-                              'src/core/client_config/client_config.h',
-                              'src/core/client_config/connector.h',
-                              'src/core/client_config/initial_connect_string.h',
-                              'src/core/client_config/lb_policies/load_balancer_api.h',
-                              'src/core/client_config/lb_policies/pick_first.h',
-                              'src/core/client_config/lb_policies/round_robin.h',
-                              'src/core/client_config/lb_policy.h',
-                              'src/core/client_config/lb_policy_factory.h',
-                              'src/core/client_config/lb_policy_registry.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/sockaddr_resolver.h',
-                              'src/core/client_config/subchannel.h',
-                              'src/core/client_config/subchannel_factory.h',
-                              'src/core/client_config/subchannel_index.h',
-                              'src/core/client_config/uri_parser.h',
-                              'src/core/compression/algorithm_metadata.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/parser.h',
-                              'src/core/iomgr/closure.h',
-                              'src/core/iomgr/endpoint.h',
-                              'src/core/iomgr/endpoint_pair.h',
-                              'src/core/iomgr/exec_ctx.h',
-                              'src/core/iomgr/executor.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_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/timer.h',
-                              'src/core/iomgr/timer_heap.h',
-                              'src/core/iomgr/udp_server.h',
-                              'src/core/iomgr/wakeup_fd_pipe.h',
-                              'src/core/iomgr/wakeup_fd_posix.h',
-                              'src/core/iomgr/workqueue.h',
-                              'src/core/iomgr/workqueue_posix.h',
-                              'src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.h',
-                              'src/core/statistics/census_interface.h',
-                              'src/core/statistics/census_rpc_stats.h',
-                              'src/core/surface/api_trace.h',
-                              'src/core/surface/call.h',
-                              'src/core/surface/call_test_only.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/byte_stream.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_encoder.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_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/metadata_batch.h',
-                              'src/core/transport/static_metadata.h',
-                              'src/core/transport/transport.h',
-                              'src/core/transport/transport_impl.h',
-                              'src/core/security/auth_filters.h',
-                              'src/core/security/b64.h',
-                              'src/core/security/credentials.h',
-                              'src/core/security/handshake.h',
-                              'src/core/security/json_token.h',
-                              'src/core/security/jwt_verifier.h',
-                              'src/core/security/secure_endpoint.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/ssl_types.h',
-                              'src/core/tsi/transport_security.h',
-                              'src/core/tsi/transport_security_interface.h',
-                              'src/core/census/aggregation.h',
-                              'src/core/census/mlog.h',
-                              'src/core/census/rpc_metric_id.h',
+    ss.private_header_files = 'src/core/lib/profiling/timers.h',
+                              'src/core/lib/support/backoff.h',
+                              'src/core/lib/support/block_annotate.h',
+                              'src/core/lib/support/env.h',
+                              'src/core/lib/support/load_file.h',
+                              'src/core/lib/support/murmur_hash.h',
+                              'src/core/lib/support/stack_lockfree.h',
+                              'src/core/lib/support/string.h',
+                              'src/core/lib/support/string_win32.h',
+                              'src/core/lib/support/thd_internal.h',
+                              'src/core/lib/support/time_precise.h',
+                              'src/core/lib/support/tmpfile.h',
+                              'src/core/ext/transport/chttp2/transport/alpn.h',
+                              'src/core/ext/transport/chttp2/transport/bin_encoder.h',
+                              'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
+                              'src/core/ext/transport/chttp2/transport/frame.h',
+                              'src/core/ext/transport/chttp2/transport/frame_data.h',
+                              'src/core/ext/transport/chttp2/transport/frame_goaway.h',
+                              'src/core/ext/transport/chttp2/transport/frame_ping.h',
+                              'src/core/ext/transport/chttp2/transport/frame_rst_stream.h',
+                              'src/core/ext/transport/chttp2/transport/frame_settings.h',
+                              'src/core/ext/transport/chttp2/transport/frame_window_update.h',
+                              'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
+                              'src/core/ext/transport/chttp2/transport/hpack_parser.h',
+                              'src/core/ext/transport/chttp2/transport/hpack_table.h',
+                              'src/core/ext/transport/chttp2/transport/http2_errors.h',
+                              'src/core/ext/transport/chttp2/transport/huffsyms.h',
+                              'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
+                              'src/core/ext/transport/chttp2/transport/internal.h',
+                              'src/core/ext/transport/chttp2/transport/status_conversion.h',
+                              'src/core/ext/transport/chttp2/transport/stream_map.h',
+                              'src/core/ext/transport/chttp2/transport/timeout_encoding.h',
+                              'src/core/ext/transport/chttp2/transport/varint.h',
+                              'src/core/lib/census/aggregation.h',
+                              'src/core/lib/census/grpc_filter.h',
+                              'src/core/lib/census/grpc_plugin.h',
+                              'src/core/lib/census/mlog.h',
+                              'src/core/lib/census/rpc_metric_id.h',
+                              'src/core/lib/channel/channel_args.h',
+                              'src/core/lib/channel/channel_stack.h',
+                              'src/core/lib/channel/channel_stack_builder.h',
+                              'src/core/lib/channel/client_channel.h',
+                              'src/core/lib/channel/compress_filter.h',
+                              'src/core/lib/channel/connected_channel.h',
+                              'src/core/lib/channel/context.h',
+                              'src/core/lib/channel/http_client_filter.h',
+                              'src/core/lib/channel/http_server_filter.h',
+                              'src/core/lib/channel/subchannel_call_holder.h',
+                              'src/core/lib/client_config/client_config.h',
+                              'src/core/lib/client_config/connector.h',
+                              'src/core/lib/client_config/initial_connect_string.h',
+                              'src/core/lib/client_config/lb_policies/load_balancer_api.h',
+                              'src/core/lib/client_config/lb_policies/pick_first.h',
+                              'src/core/lib/client_config/lb_policies/round_robin.h',
+                              'src/core/lib/client_config/lb_policy.h',
+                              'src/core/lib/client_config/lb_policy_factory.h',
+                              'src/core/lib/client_config/lb_policy_registry.h',
+                              'src/core/lib/client_config/resolver.h',
+                              'src/core/lib/client_config/resolver_factory.h',
+                              'src/core/lib/client_config/resolver_registry.h',
+                              'src/core/lib/client_config/resolvers/dns_resolver.h',
+                              'src/core/lib/client_config/resolvers/sockaddr_resolver.h',
+                              'src/core/lib/client_config/subchannel.h',
+                              'src/core/lib/client_config/subchannel_factory.h',
+                              'src/core/lib/client_config/subchannel_index.h',
+                              'src/core/lib/client_config/uri_parser.h',
+                              'src/core/lib/compression/algorithm_metadata.h',
+                              'src/core/lib/compression/message_compress.h',
+                              'src/core/lib/debug/trace.h',
+                              'src/core/lib/http/format_request.h',
+                              'src/core/lib/http/httpcli.h',
+                              'src/core/lib/http/parser.h',
+                              'src/core/lib/iomgr/closure.h',
+                              'src/core/lib/iomgr/endpoint.h',
+                              'src/core/lib/iomgr/endpoint_pair.h',
+                              'src/core/lib/iomgr/exec_ctx.h',
+                              'src/core/lib/iomgr/executor.h',
+                              'src/core/lib/iomgr/fd_posix.h',
+                              'src/core/lib/iomgr/iocp_windows.h',
+                              'src/core/lib/iomgr/iomgr.h',
+                              'src/core/lib/iomgr/iomgr_internal.h',
+                              'src/core/lib/iomgr/iomgr_posix.h',
+                              'src/core/lib/iomgr/pollset.h',
+                              'src/core/lib/iomgr/pollset_posix.h',
+                              'src/core/lib/iomgr/pollset_set.h',
+                              'src/core/lib/iomgr/pollset_set_posix.h',
+                              'src/core/lib/iomgr/pollset_set_windows.h',
+                              'src/core/lib/iomgr/pollset_windows.h',
+                              'src/core/lib/iomgr/resolve_address.h',
+                              'src/core/lib/iomgr/sockaddr.h',
+                              'src/core/lib/iomgr/sockaddr_posix.h',
+                              'src/core/lib/iomgr/sockaddr_utils.h',
+                              'src/core/lib/iomgr/sockaddr_win32.h',
+                              'src/core/lib/iomgr/socket_utils_posix.h',
+                              'src/core/lib/iomgr/socket_windows.h',
+                              'src/core/lib/iomgr/tcp_client.h',
+                              'src/core/lib/iomgr/tcp_posix.h',
+                              'src/core/lib/iomgr/tcp_server.h',
+                              'src/core/lib/iomgr/tcp_windows.h',
+                              'src/core/lib/iomgr/time_averaged_stats.h',
+                              'src/core/lib/iomgr/timer.h',
+                              'src/core/lib/iomgr/timer_heap.h',
+                              'src/core/lib/iomgr/udp_server.h',
+                              'src/core/lib/iomgr/unix_sockets_posix.h',
+                              'src/core/lib/iomgr/wakeup_fd_pipe.h',
+                              'src/core/lib/iomgr/wakeup_fd_posix.h',
+                              'src/core/lib/iomgr/workqueue.h',
+                              'src/core/lib/iomgr/workqueue_posix.h',
+                              'src/core/lib/iomgr/workqueue_windows.h',
+                              'src/core/lib/json/json.h',
+                              'src/core/lib/json/json_common.h',
+                              'src/core/lib/json/json_reader.h',
+                              'src/core/lib/json/json_writer.h',
+                              'src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h',
+                              'src/core/lib/security/auth_filters.h',
+                              'src/core/lib/security/b64.h',
+                              'src/core/lib/security/credentials.h',
+                              'src/core/lib/security/handshake.h',
+                              'src/core/lib/security/json_token.h',
+                              'src/core/lib/security/jwt_verifier.h',
+                              'src/core/lib/security/secure_endpoint.h',
+                              'src/core/lib/security/security_connector.h',
+                              'src/core/lib/security/security_context.h',
+                              'src/core/lib/statistics/census_interface.h',
+                              'src/core/lib/statistics/census_rpc_stats.h',
+                              'src/core/lib/surface/api_trace.h',
+                              'src/core/lib/surface/call.h',
+                              'src/core/lib/surface/call_test_only.h',
+                              'src/core/lib/surface/channel.h',
+                              'src/core/lib/surface/channel_init.h',
+                              'src/core/lib/surface/channel_stack_type.h',
+                              'src/core/lib/surface/completion_queue.h',
+                              'src/core/lib/surface/event_string.h',
+                              'src/core/lib/surface/init.h',
+                              'src/core/lib/surface/lame_client.h',
+                              'src/core/lib/surface/server.h',
+                              'src/core/lib/surface/surface_trace.h',
+                              'src/core/lib/transport/byte_stream.h',
+                              'src/core/lib/transport/connectivity_state.h',
+                              'src/core/lib/transport/metadata.h',
+                              'src/core/lib/transport/metadata_batch.h',
+                              'src/core/lib/transport/static_metadata.h',
+                              'src/core/lib/transport/transport.h',
+                              'src/core/lib/transport/transport_impl.h',
+                              'src/core/lib/tsi/fake_transport_security.h',
+                              'src/core/lib/tsi/ssl_transport_security.h',
+                              'src/core/lib/tsi/ssl_types.h',
+                              'src/core/lib/tsi/transport_security.h',
+                              'src/core/lib/tsi/transport_security_interface.h',
                               'third_party/nanopb/pb.h',
                               'third_party/nanopb/pb_common.h',
                               'third_party/nanopb/pb_decode.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 1b3f15e..c516f52 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -46,6 +46,20 @@
 
   s.extensions = %w(src/ruby/ext/grpc/extconf.rb)
 
+  s.files += %w( include/grpc/impl/codegen/alloc.h )
+  s.files += %w( include/grpc/impl/codegen/atm.h )
+  s.files += %w( include/grpc/impl/codegen/atm_gcc_atomic.h )
+  s.files += %w( include/grpc/impl/codegen/atm_gcc_sync.h )
+  s.files += %w( include/grpc/impl/codegen/atm_win32.h )
+  s.files += %w( include/grpc/impl/codegen/log.h )
+  s.files += %w( include/grpc/impl/codegen/port_platform.h )
+  s.files += %w( include/grpc/impl/codegen/slice.h )
+  s.files += %w( include/grpc/impl/codegen/slice_buffer.h )
+  s.files += %w( include/grpc/impl/codegen/sync.h )
+  s.files += %w( include/grpc/impl/codegen/sync_generic.h )
+  s.files += %w( include/grpc/impl/codegen/sync_posix.h )
+  s.files += %w( include/grpc/impl/codegen/sync_win32.h )
+  s.files += %w( include/grpc/impl/codegen/time.h )
   s.files += %w( include/grpc/support/alloc.h )
   s.files += %w( include/grpc/support/atm.h )
   s.files += %w( include/grpc/support/atm_gcc_atomic.h )
@@ -74,74 +88,67 @@
   s.files += %w( include/grpc/support/tls_msvc.h )
   s.files += %w( include/grpc/support/tls_pthread.h )
   s.files += %w( include/grpc/support/useful.h )
-  s.files += %w( include/grpc/impl/codegen/alloc.h )
-  s.files += %w( include/grpc/impl/codegen/atm.h )
-  s.files += %w( include/grpc/impl/codegen/atm_gcc_atomic.h )
-  s.files += %w( include/grpc/impl/codegen/atm_gcc_sync.h )
-  s.files += %w( include/grpc/impl/codegen/atm_win32.h )
-  s.files += %w( include/grpc/impl/codegen/log.h )
-  s.files += %w( include/grpc/impl/codegen/port_platform.h )
-  s.files += %w( include/grpc/impl/codegen/slice.h )
-  s.files += %w( include/grpc/impl/codegen/slice_buffer.h )
-  s.files += %w( include/grpc/impl/codegen/sync.h )
-  s.files += %w( include/grpc/impl/codegen/sync_generic.h )
-  s.files += %w( include/grpc/impl/codegen/sync_posix.h )
-  s.files += %w( include/grpc/impl/codegen/sync_win32.h )
-  s.files += %w( include/grpc/impl/codegen/time.h )
-  s.files += %w( src/core/profiling/timers.h )
-  s.files += %w( src/core/support/block_annotate.h )
-  s.files += %w( src/core/support/env.h )
-  s.files += %w( src/core/support/load_file.h )
-  s.files += %w( src/core/support/murmur_hash.h )
-  s.files += %w( src/core/support/stack_lockfree.h )
-  s.files += %w( src/core/support/string.h )
-  s.files += %w( src/core/support/string_win32.h )
-  s.files += %w( src/core/support/thd_internal.h )
-  s.files += %w( src/core/support/time_precise.h )
-  s.files += %w( src/core/support/tmpfile.h )
-  s.files += %w( src/core/profiling/basic_timers.c )
-  s.files += %w( src/core/profiling/stap_timers.c )
-  s.files += %w( src/core/support/alloc.c )
-  s.files += %w( src/core/support/avl.c )
-  s.files += %w( src/core/support/cmdline.c )
-  s.files += %w( src/core/support/cpu_iphone.c )
-  s.files += %w( src/core/support/cpu_linux.c )
-  s.files += %w( src/core/support/cpu_posix.c )
-  s.files += %w( src/core/support/cpu_windows.c )
-  s.files += %w( src/core/support/env_linux.c )
-  s.files += %w( src/core/support/env_posix.c )
-  s.files += %w( src/core/support/env_win32.c )
-  s.files += %w( src/core/support/histogram.c )
-  s.files += %w( src/core/support/host_port.c )
-  s.files += %w( src/core/support/load_file.c )
-  s.files += %w( src/core/support/log.c )
-  s.files += %w( src/core/support/log_android.c )
-  s.files += %w( src/core/support/log_linux.c )
-  s.files += %w( src/core/support/log_posix.c )
-  s.files += %w( src/core/support/log_win32.c )
-  s.files += %w( src/core/support/murmur_hash.c )
-  s.files += %w( src/core/support/slice.c )
-  s.files += %w( src/core/support/slice_buffer.c )
-  s.files += %w( src/core/support/stack_lockfree.c )
-  s.files += %w( src/core/support/string.c )
-  s.files += %w( src/core/support/string_posix.c )
-  s.files += %w( src/core/support/string_win32.c )
-  s.files += %w( src/core/support/subprocess_posix.c )
-  s.files += %w( src/core/support/subprocess_windows.c )
-  s.files += %w( src/core/support/sync.c )
-  s.files += %w( src/core/support/sync_posix.c )
-  s.files += %w( src/core/support/sync_win32.c )
-  s.files += %w( src/core/support/thd.c )
-  s.files += %w( src/core/support/thd_posix.c )
-  s.files += %w( src/core/support/thd_win32.c )
-  s.files += %w( src/core/support/time.c )
-  s.files += %w( src/core/support/time_posix.c )
-  s.files += %w( src/core/support/time_precise.c )
-  s.files += %w( src/core/support/time_win32.c )
-  s.files += %w( src/core/support/tls_pthread.c )
-  s.files += %w( src/core/support/tmpfile_posix.c )
-  s.files += %w( src/core/support/tmpfile_win32.c )
-  s.files += %w( src/core/support/wrap_memcpy.c )
+  s.files += %w( src/core/lib/profiling/timers.h )
+  s.files += %w( src/core/lib/support/backoff.h )
+  s.files += %w( src/core/lib/support/block_annotate.h )
+  s.files += %w( src/core/lib/support/env.h )
+  s.files += %w( src/core/lib/support/load_file.h )
+  s.files += %w( src/core/lib/support/murmur_hash.h )
+  s.files += %w( src/core/lib/support/stack_lockfree.h )
+  s.files += %w( src/core/lib/support/string.h )
+  s.files += %w( src/core/lib/support/string_win32.h )
+  s.files += %w( src/core/lib/support/thd_internal.h )
+  s.files += %w( src/core/lib/support/time_precise.h )
+  s.files += %w( src/core/lib/support/tmpfile.h )
+  s.files += %w( src/core/lib/profiling/basic_timers.c )
+  s.files += %w( src/core/lib/profiling/stap_timers.c )
+  s.files += %w( src/core/lib/support/alloc.c )
+  s.files += %w( src/core/lib/support/avl.c )
+  s.files += %w( src/core/lib/support/backoff.c )
+  s.files += %w( src/core/lib/support/cmdline.c )
+  s.files += %w( src/core/lib/support/cpu_iphone.c )
+  s.files += %w( src/core/lib/support/cpu_linux.c )
+  s.files += %w( src/core/lib/support/cpu_posix.c )
+  s.files += %w( src/core/lib/support/cpu_windows.c )
+  s.files += %w( src/core/lib/support/env_linux.c )
+  s.files += %w( src/core/lib/support/env_posix.c )
+  s.files += %w( src/core/lib/support/env_win32.c )
+  s.files += %w( src/core/lib/support/histogram.c )
+  s.files += %w( src/core/lib/support/host_port.c )
+  s.files += %w( src/core/lib/support/load_file.c )
+  s.files += %w( src/core/lib/support/log.c )
+  s.files += %w( src/core/lib/support/log_android.c )
+  s.files += %w( src/core/lib/support/log_linux.c )
+  s.files += %w( src/core/lib/support/log_posix.c )
+  s.files += %w( src/core/lib/support/log_win32.c )
+  s.files += %w( src/core/lib/support/murmur_hash.c )
+  s.files += %w( src/core/lib/support/slice.c )
+  s.files += %w( src/core/lib/support/slice_buffer.c )
+  s.files += %w( src/core/lib/support/stack_lockfree.c )
+  s.files += %w( src/core/lib/support/string.c )
+  s.files += %w( src/core/lib/support/string_posix.c )
+  s.files += %w( src/core/lib/support/string_win32.c )
+  s.files += %w( src/core/lib/support/subprocess_posix.c )
+  s.files += %w( src/core/lib/support/subprocess_windows.c )
+  s.files += %w( src/core/lib/support/sync.c )
+  s.files += %w( src/core/lib/support/sync_posix.c )
+  s.files += %w( src/core/lib/support/sync_win32.c )
+  s.files += %w( src/core/lib/support/thd.c )
+  s.files += %w( src/core/lib/support/thd_posix.c )
+  s.files += %w( src/core/lib/support/thd_win32.c )
+  s.files += %w( src/core/lib/support/time.c )
+  s.files += %w( src/core/lib/support/time_posix.c )
+  s.files += %w( src/core/lib/support/time_precise.c )
+  s.files += %w( src/core/lib/support/time_win32.c )
+  s.files += %w( src/core/lib/support/tls_pthread.c )
+  s.files += %w( src/core/lib/support/tmpfile_posix.c )
+  s.files += %w( src/core/lib/support/tmpfile_win32.c )
+  s.files += %w( src/core/lib/support/wrap_memcpy.c )
+  s.files += %w( include/grpc/byte_buffer.h )
+  s.files += %w( include/grpc/byte_buffer_reader.h )
+  s.files += %w( include/grpc/census.h )
+  s.files += %w( include/grpc/compression.h )
+  s.files += %w( include/grpc/grpc.h )
   s.files += %w( include/grpc/grpc_security.h )
   s.files += %w( include/grpc/impl/codegen/byte_buffer.h )
   s.files += %w( include/grpc/impl/codegen/compression_types.h )
@@ -149,305 +156,309 @@
   s.files += %w( include/grpc/impl/codegen/grpc_types.h )
   s.files += %w( include/grpc/impl/codegen/propagation_bits.h )
   s.files += %w( include/grpc/impl/codegen/status.h )
-  s.files += %w( include/grpc/byte_buffer.h )
-  s.files += %w( include/grpc/byte_buffer_reader.h )
-  s.files += %w( include/grpc/compression.h )
-  s.files += %w( include/grpc/grpc.h )
   s.files += %w( include/grpc/status.h )
-  s.files += %w( include/grpc/census.h )
-  s.files += %w( src/core/census/grpc_filter.h )
-  s.files += %w( src/core/channel/channel_args.h )
-  s.files += %w( src/core/channel/channel_stack.h )
-  s.files += %w( src/core/channel/client_channel.h )
-  s.files += %w( src/core/channel/client_uchannel.h )
-  s.files += %w( src/core/channel/compress_filter.h )
-  s.files += %w( src/core/channel/connected_channel.h )
-  s.files += %w( src/core/channel/context.h )
-  s.files += %w( src/core/channel/http_client_filter.h )
-  s.files += %w( src/core/channel/http_server_filter.h )
-  s.files += %w( src/core/channel/subchannel_call_holder.h )
-  s.files += %w( src/core/client_config/client_config.h )
-  s.files += %w( src/core/client_config/connector.h )
-  s.files += %w( src/core/client_config/initial_connect_string.h )
-  s.files += %w( src/core/client_config/lb_policies/load_balancer_api.h )
-  s.files += %w( src/core/client_config/lb_policies/pick_first.h )
-  s.files += %w( src/core/client_config/lb_policies/round_robin.h )
-  s.files += %w( src/core/client_config/lb_policy.h )
-  s.files += %w( src/core/client_config/lb_policy_factory.h )
-  s.files += %w( src/core/client_config/lb_policy_registry.h )
-  s.files += %w( src/core/client_config/resolver.h )
-  s.files += %w( src/core/client_config/resolver_factory.h )
-  s.files += %w( src/core/client_config/resolver_registry.h )
-  s.files += %w( src/core/client_config/resolvers/dns_resolver.h )
-  s.files += %w( src/core/client_config/resolvers/sockaddr_resolver.h )
-  s.files += %w( src/core/client_config/subchannel.h )
-  s.files += %w( src/core/client_config/subchannel_factory.h )
-  s.files += %w( src/core/client_config/subchannel_index.h )
-  s.files += %w( src/core/client_config/uri_parser.h )
-  s.files += %w( src/core/compression/algorithm_metadata.h )
-  s.files += %w( src/core/compression/message_compress.h )
-  s.files += %w( src/core/debug/trace.h )
-  s.files += %w( src/core/httpcli/format_request.h )
-  s.files += %w( src/core/httpcli/httpcli.h )
-  s.files += %w( src/core/httpcli/parser.h )
-  s.files += %w( src/core/iomgr/closure.h )
-  s.files += %w( src/core/iomgr/endpoint.h )
-  s.files += %w( src/core/iomgr/endpoint_pair.h )
-  s.files += %w( src/core/iomgr/exec_ctx.h )
-  s.files += %w( src/core/iomgr/executor.h )
-  s.files += %w( src/core/iomgr/fd_posix.h )
-  s.files += %w( src/core/iomgr/iocp_windows.h )
-  s.files += %w( src/core/iomgr/iomgr.h )
-  s.files += %w( src/core/iomgr/iomgr_internal.h )
-  s.files += %w( src/core/iomgr/iomgr_posix.h )
-  s.files += %w( src/core/iomgr/pollset.h )
-  s.files += %w( src/core/iomgr/pollset_posix.h )
-  s.files += %w( src/core/iomgr/pollset_set.h )
-  s.files += %w( src/core/iomgr/pollset_set_posix.h )
-  s.files += %w( src/core/iomgr/pollset_set_windows.h )
-  s.files += %w( src/core/iomgr/pollset_windows.h )
-  s.files += %w( src/core/iomgr/resolve_address.h )
-  s.files += %w( src/core/iomgr/sockaddr.h )
-  s.files += %w( src/core/iomgr/sockaddr_posix.h )
-  s.files += %w( src/core/iomgr/sockaddr_utils.h )
-  s.files += %w( src/core/iomgr/sockaddr_win32.h )
-  s.files += %w( src/core/iomgr/socket_utils_posix.h )
-  s.files += %w( src/core/iomgr/socket_windows.h )
-  s.files += %w( src/core/iomgr/tcp_client.h )
-  s.files += %w( src/core/iomgr/tcp_posix.h )
-  s.files += %w( src/core/iomgr/tcp_server.h )
-  s.files += %w( src/core/iomgr/tcp_windows.h )
-  s.files += %w( src/core/iomgr/time_averaged_stats.h )
-  s.files += %w( src/core/iomgr/timer.h )
-  s.files += %w( src/core/iomgr/timer_heap.h )
-  s.files += %w( src/core/iomgr/udp_server.h )
-  s.files += %w( src/core/iomgr/wakeup_fd_pipe.h )
-  s.files += %w( src/core/iomgr/wakeup_fd_posix.h )
-  s.files += %w( src/core/iomgr/workqueue.h )
-  s.files += %w( src/core/iomgr/workqueue_posix.h )
-  s.files += %w( src/core/iomgr/workqueue_windows.h )
-  s.files += %w( src/core/json/json.h )
-  s.files += %w( src/core/json/json_common.h )
-  s.files += %w( src/core/json/json_reader.h )
-  s.files += %w( src/core/json/json_writer.h )
-  s.files += %w( src/core/proto/grpc/lb/v0/load_balancer.pb.h )
-  s.files += %w( src/core/statistics/census_interface.h )
-  s.files += %w( src/core/statistics/census_rpc_stats.h )
-  s.files += %w( src/core/surface/api_trace.h )
-  s.files += %w( src/core/surface/call.h )
-  s.files += %w( src/core/surface/call_test_only.h )
-  s.files += %w( src/core/surface/channel.h )
-  s.files += %w( src/core/surface/completion_queue.h )
-  s.files += %w( src/core/surface/event_string.h )
-  s.files += %w( src/core/surface/init.h )
-  s.files += %w( src/core/surface/server.h )
-  s.files += %w( src/core/surface/surface_trace.h )
-  s.files += %w( src/core/transport/byte_stream.h )
-  s.files += %w( src/core/transport/chttp2/alpn.h )
-  s.files += %w( src/core/transport/chttp2/bin_encoder.h )
-  s.files += %w( src/core/transport/chttp2/frame.h )
-  s.files += %w( src/core/transport/chttp2/frame_data.h )
-  s.files += %w( src/core/transport/chttp2/frame_goaway.h )
-  s.files += %w( src/core/transport/chttp2/frame_ping.h )
-  s.files += %w( src/core/transport/chttp2/frame_rst_stream.h )
-  s.files += %w( src/core/transport/chttp2/frame_settings.h )
-  s.files += %w( src/core/transport/chttp2/frame_window_update.h )
-  s.files += %w( src/core/transport/chttp2/hpack_encoder.h )
-  s.files += %w( src/core/transport/chttp2/hpack_parser.h )
-  s.files += %w( src/core/transport/chttp2/hpack_table.h )
-  s.files += %w( src/core/transport/chttp2/http2_errors.h )
-  s.files += %w( src/core/transport/chttp2/huffsyms.h )
-  s.files += %w( src/core/transport/chttp2/incoming_metadata.h )
-  s.files += %w( src/core/transport/chttp2/internal.h )
-  s.files += %w( src/core/transport/chttp2/status_conversion.h )
-  s.files += %w( src/core/transport/chttp2/stream_map.h )
-  s.files += %w( src/core/transport/chttp2/timeout_encoding.h )
-  s.files += %w( src/core/transport/chttp2/varint.h )
-  s.files += %w( src/core/transport/chttp2_transport.h )
-  s.files += %w( src/core/transport/connectivity_state.h )
-  s.files += %w( src/core/transport/metadata.h )
-  s.files += %w( src/core/transport/metadata_batch.h )
-  s.files += %w( src/core/transport/static_metadata.h )
-  s.files += %w( src/core/transport/transport.h )
-  s.files += %w( src/core/transport/transport_impl.h )
-  s.files += %w( src/core/security/auth_filters.h )
-  s.files += %w( src/core/security/b64.h )
-  s.files += %w( src/core/security/credentials.h )
-  s.files += %w( src/core/security/handshake.h )
-  s.files += %w( src/core/security/json_token.h )
-  s.files += %w( src/core/security/jwt_verifier.h )
-  s.files += %w( src/core/security/secure_endpoint.h )
-  s.files += %w( src/core/security/security_connector.h )
-  s.files += %w( src/core/security/security_context.h )
-  s.files += %w( src/core/tsi/fake_transport_security.h )
-  s.files += %w( src/core/tsi/ssl_transport_security.h )
-  s.files += %w( src/core/tsi/ssl_types.h )
-  s.files += %w( src/core/tsi/transport_security.h )
-  s.files += %w( src/core/tsi/transport_security_interface.h )
-  s.files += %w( src/core/census/aggregation.h )
-  s.files += %w( src/core/census/mlog.h )
-  s.files += %w( src/core/census/rpc_metric_id.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/alpn.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame_data.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame_goaway.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame_ping.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame_rst_stream.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame_settings.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame_window_update.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/hpack_encoder.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/hpack_parser.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/hpack_table.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/http2_errors.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/huffsyms.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/incoming_metadata.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/internal.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/status_conversion.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/stream_map.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/timeout_encoding.h )
+  s.files += %w( src/core/ext/transport/chttp2/transport/varint.h )
+  s.files += %w( src/core/lib/census/aggregation.h )
+  s.files += %w( src/core/lib/census/grpc_filter.h )
+  s.files += %w( src/core/lib/census/grpc_plugin.h )
+  s.files += %w( src/core/lib/census/mlog.h )
+  s.files += %w( src/core/lib/census/rpc_metric_id.h )
+  s.files += %w( src/core/lib/channel/channel_args.h )
+  s.files += %w( src/core/lib/channel/channel_stack.h )
+  s.files += %w( src/core/lib/channel/channel_stack_builder.h )
+  s.files += %w( src/core/lib/channel/client_channel.h )
+  s.files += %w( src/core/lib/channel/compress_filter.h )
+  s.files += %w( src/core/lib/channel/connected_channel.h )
+  s.files += %w( src/core/lib/channel/context.h )
+  s.files += %w( src/core/lib/channel/http_client_filter.h )
+  s.files += %w( src/core/lib/channel/http_server_filter.h )
+  s.files += %w( src/core/lib/channel/subchannel_call_holder.h )
+  s.files += %w( src/core/lib/client_config/client_config.h )
+  s.files += %w( src/core/lib/client_config/connector.h )
+  s.files += %w( src/core/lib/client_config/initial_connect_string.h )
+  s.files += %w( src/core/lib/client_config/lb_policies/load_balancer_api.h )
+  s.files += %w( src/core/lib/client_config/lb_policies/pick_first.h )
+  s.files += %w( src/core/lib/client_config/lb_policies/round_robin.h )
+  s.files += %w( src/core/lib/client_config/lb_policy.h )
+  s.files += %w( src/core/lib/client_config/lb_policy_factory.h )
+  s.files += %w( src/core/lib/client_config/lb_policy_registry.h )
+  s.files += %w( src/core/lib/client_config/resolver.h )
+  s.files += %w( src/core/lib/client_config/resolver_factory.h )
+  s.files += %w( src/core/lib/client_config/resolver_registry.h )
+  s.files += %w( src/core/lib/client_config/resolvers/dns_resolver.h )
+  s.files += %w( src/core/lib/client_config/resolvers/sockaddr_resolver.h )
+  s.files += %w( src/core/lib/client_config/subchannel.h )
+  s.files += %w( src/core/lib/client_config/subchannel_factory.h )
+  s.files += %w( src/core/lib/client_config/subchannel_index.h )
+  s.files += %w( src/core/lib/client_config/uri_parser.h )
+  s.files += %w( src/core/lib/compression/algorithm_metadata.h )
+  s.files += %w( src/core/lib/compression/message_compress.h )
+  s.files += %w( src/core/lib/debug/trace.h )
+  s.files += %w( src/core/lib/http/format_request.h )
+  s.files += %w( src/core/lib/http/httpcli.h )
+  s.files += %w( src/core/lib/http/parser.h )
+  s.files += %w( src/core/lib/iomgr/closure.h )
+  s.files += %w( src/core/lib/iomgr/endpoint.h )
+  s.files += %w( src/core/lib/iomgr/endpoint_pair.h )
+  s.files += %w( src/core/lib/iomgr/exec_ctx.h )
+  s.files += %w( src/core/lib/iomgr/executor.h )
+  s.files += %w( src/core/lib/iomgr/fd_posix.h )
+  s.files += %w( src/core/lib/iomgr/iocp_windows.h )
+  s.files += %w( src/core/lib/iomgr/iomgr.h )
+  s.files += %w( src/core/lib/iomgr/iomgr_internal.h )
+  s.files += %w( src/core/lib/iomgr/iomgr_posix.h )
+  s.files += %w( src/core/lib/iomgr/pollset.h )
+  s.files += %w( src/core/lib/iomgr/pollset_posix.h )
+  s.files += %w( src/core/lib/iomgr/pollset_set.h )
+  s.files += %w( src/core/lib/iomgr/pollset_set_posix.h )
+  s.files += %w( src/core/lib/iomgr/pollset_set_windows.h )
+  s.files += %w( src/core/lib/iomgr/pollset_windows.h )
+  s.files += %w( src/core/lib/iomgr/resolve_address.h )
+  s.files += %w( src/core/lib/iomgr/sockaddr.h )
+  s.files += %w( src/core/lib/iomgr/sockaddr_posix.h )
+  s.files += %w( src/core/lib/iomgr/sockaddr_utils.h )
+  s.files += %w( src/core/lib/iomgr/sockaddr_win32.h )
+  s.files += %w( src/core/lib/iomgr/socket_utils_posix.h )
+  s.files += %w( src/core/lib/iomgr/socket_windows.h )
+  s.files += %w( src/core/lib/iomgr/tcp_client.h )
+  s.files += %w( src/core/lib/iomgr/tcp_posix.h )
+  s.files += %w( src/core/lib/iomgr/tcp_server.h )
+  s.files += %w( src/core/lib/iomgr/tcp_windows.h )
+  s.files += %w( src/core/lib/iomgr/time_averaged_stats.h )
+  s.files += %w( src/core/lib/iomgr/timer.h )
+  s.files += %w( src/core/lib/iomgr/timer_heap.h )
+  s.files += %w( src/core/lib/iomgr/udp_server.h )
+  s.files += %w( src/core/lib/iomgr/unix_sockets_posix.h )
+  s.files += %w( src/core/lib/iomgr/wakeup_fd_pipe.h )
+  s.files += %w( src/core/lib/iomgr/wakeup_fd_posix.h )
+  s.files += %w( src/core/lib/iomgr/workqueue.h )
+  s.files += %w( src/core/lib/iomgr/workqueue_posix.h )
+  s.files += %w( src/core/lib/iomgr/workqueue_windows.h )
+  s.files += %w( src/core/lib/json/json.h )
+  s.files += %w( src/core/lib/json/json_common.h )
+  s.files += %w( src/core/lib/json/json_reader.h )
+  s.files += %w( src/core/lib/json/json_writer.h )
+  s.files += %w( src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h )
+  s.files += %w( src/core/lib/security/auth_filters.h )
+  s.files += %w( src/core/lib/security/b64.h )
+  s.files += %w( src/core/lib/security/credentials.h )
+  s.files += %w( src/core/lib/security/handshake.h )
+  s.files += %w( src/core/lib/security/json_token.h )
+  s.files += %w( src/core/lib/security/jwt_verifier.h )
+  s.files += %w( src/core/lib/security/secure_endpoint.h )
+  s.files += %w( src/core/lib/security/security_connector.h )
+  s.files += %w( src/core/lib/security/security_context.h )
+  s.files += %w( src/core/lib/statistics/census_interface.h )
+  s.files += %w( src/core/lib/statistics/census_rpc_stats.h )
+  s.files += %w( src/core/lib/surface/api_trace.h )
+  s.files += %w( src/core/lib/surface/call.h )
+  s.files += %w( src/core/lib/surface/call_test_only.h )
+  s.files += %w( src/core/lib/surface/channel.h )
+  s.files += %w( src/core/lib/surface/channel_init.h )
+  s.files += %w( src/core/lib/surface/channel_stack_type.h )
+  s.files += %w( src/core/lib/surface/completion_queue.h )
+  s.files += %w( src/core/lib/surface/event_string.h )
+  s.files += %w( src/core/lib/surface/init.h )
+  s.files += %w( src/core/lib/surface/lame_client.h )
+  s.files += %w( src/core/lib/surface/server.h )
+  s.files += %w( src/core/lib/surface/surface_trace.h )
+  s.files += %w( src/core/lib/transport/byte_stream.h )
+  s.files += %w( src/core/lib/transport/connectivity_state.h )
+  s.files += %w( src/core/lib/transport/metadata.h )
+  s.files += %w( src/core/lib/transport/metadata_batch.h )
+  s.files += %w( src/core/lib/transport/static_metadata.h )
+  s.files += %w( src/core/lib/transport/transport.h )
+  s.files += %w( src/core/lib/transport/transport_impl.h )
+  s.files += %w( src/core/lib/tsi/fake_transport_security.h )
+  s.files += %w( src/core/lib/tsi/ssl_transport_security.h )
+  s.files += %w( src/core/lib/tsi/ssl_types.h )
+  s.files += %w( src/core/lib/tsi/transport_security.h )
+  s.files += %w( src/core/lib/tsi/transport_security_interface.h )
   s.files += %w( third_party/nanopb/pb.h )
   s.files += %w( third_party/nanopb/pb_common.h )
   s.files += %w( third_party/nanopb/pb_decode.h )
   s.files += %w( third_party/nanopb/pb_encode.h )
-  s.files += %w( src/core/census/grpc_context.c )
-  s.files += %w( src/core/census/grpc_filter.c )
-  s.files += %w( src/core/channel/channel_args.c )
-  s.files += %w( src/core/channel/channel_stack.c )
-  s.files += %w( src/core/channel/client_channel.c )
-  s.files += %w( src/core/channel/client_uchannel.c )
-  s.files += %w( src/core/channel/compress_filter.c )
-  s.files += %w( src/core/channel/connected_channel.c )
-  s.files += %w( src/core/channel/http_client_filter.c )
-  s.files += %w( src/core/channel/http_server_filter.c )
-  s.files += %w( src/core/channel/subchannel_call_holder.c )
-  s.files += %w( src/core/client_config/client_config.c )
-  s.files += %w( src/core/client_config/connector.c )
-  s.files += %w( src/core/client_config/default_initial_connect_string.c )
-  s.files += %w( src/core/client_config/initial_connect_string.c )
-  s.files += %w( src/core/client_config/lb_policies/load_balancer_api.c )
-  s.files += %w( src/core/client_config/lb_policies/pick_first.c )
-  s.files += %w( src/core/client_config/lb_policies/round_robin.c )
-  s.files += %w( src/core/client_config/lb_policy.c )
-  s.files += %w( src/core/client_config/lb_policy_factory.c )
-  s.files += %w( src/core/client_config/lb_policy_registry.c )
-  s.files += %w( src/core/client_config/resolver.c )
-  s.files += %w( src/core/client_config/resolver_factory.c )
-  s.files += %w( src/core/client_config/resolver_registry.c )
-  s.files += %w( src/core/client_config/resolvers/dns_resolver.c )
-  s.files += %w( src/core/client_config/resolvers/sockaddr_resolver.c )
-  s.files += %w( src/core/client_config/subchannel.c )
-  s.files += %w( src/core/client_config/subchannel_factory.c )
-  s.files += %w( src/core/client_config/subchannel_index.c )
-  s.files += %w( src/core/client_config/uri_parser.c )
-  s.files += %w( src/core/compression/compression_algorithm.c )
-  s.files += %w( src/core/compression/message_compress.c )
-  s.files += %w( src/core/debug/trace.c )
-  s.files += %w( src/core/httpcli/format_request.c )
-  s.files += %w( src/core/httpcli/httpcli.c )
-  s.files += %w( src/core/httpcli/parser.c )
-  s.files += %w( src/core/iomgr/closure.c )
-  s.files += %w( src/core/iomgr/endpoint.c )
-  s.files += %w( src/core/iomgr/endpoint_pair_posix.c )
-  s.files += %w( src/core/iomgr/endpoint_pair_windows.c )
-  s.files += %w( src/core/iomgr/exec_ctx.c )
-  s.files += %w( src/core/iomgr/executor.c )
-  s.files += %w( src/core/iomgr/fd_posix.c )
-  s.files += %w( src/core/iomgr/iocp_windows.c )
-  s.files += %w( src/core/iomgr/iomgr.c )
-  s.files += %w( src/core/iomgr/iomgr_posix.c )
-  s.files += %w( src/core/iomgr/iomgr_windows.c )
-  s.files += %w( src/core/iomgr/pollset_multipoller_with_epoll.c )
-  s.files += %w( src/core/iomgr/pollset_multipoller_with_poll_posix.c )
-  s.files += %w( src/core/iomgr/pollset_posix.c )
-  s.files += %w( src/core/iomgr/pollset_set_posix.c )
-  s.files += %w( src/core/iomgr/pollset_set_windows.c )
-  s.files += %w( src/core/iomgr/pollset_windows.c )
-  s.files += %w( src/core/iomgr/resolve_address_posix.c )
-  s.files += %w( src/core/iomgr/resolve_address_windows.c )
-  s.files += %w( src/core/iomgr/sockaddr_utils.c )
-  s.files += %w( src/core/iomgr/socket_utils_common_posix.c )
-  s.files += %w( src/core/iomgr/socket_utils_linux.c )
-  s.files += %w( src/core/iomgr/socket_utils_posix.c )
-  s.files += %w( src/core/iomgr/socket_windows.c )
-  s.files += %w( src/core/iomgr/tcp_client_posix.c )
-  s.files += %w( src/core/iomgr/tcp_client_windows.c )
-  s.files += %w( src/core/iomgr/tcp_posix.c )
-  s.files += %w( src/core/iomgr/tcp_server_posix.c )
-  s.files += %w( src/core/iomgr/tcp_server_windows.c )
-  s.files += %w( src/core/iomgr/tcp_windows.c )
-  s.files += %w( src/core/iomgr/time_averaged_stats.c )
-  s.files += %w( src/core/iomgr/timer.c )
-  s.files += %w( src/core/iomgr/timer_heap.c )
-  s.files += %w( src/core/iomgr/udp_server.c )
-  s.files += %w( src/core/iomgr/wakeup_fd_eventfd.c )
-  s.files += %w( src/core/iomgr/wakeup_fd_nospecial.c )
-  s.files += %w( src/core/iomgr/wakeup_fd_pipe.c )
-  s.files += %w( src/core/iomgr/wakeup_fd_posix.c )
-  s.files += %w( src/core/iomgr/workqueue_posix.c )
-  s.files += %w( src/core/iomgr/workqueue_windows.c )
-  s.files += %w( src/core/json/json.c )
-  s.files += %w( src/core/json/json_reader.c )
-  s.files += %w( src/core/json/json_string.c )
-  s.files += %w( src/core/json/json_writer.c )
-  s.files += %w( src/core/proto/grpc/lb/v0/load_balancer.pb.c )
-  s.files += %w( src/core/surface/alarm.c )
-  s.files += %w( src/core/surface/api_trace.c )
-  s.files += %w( src/core/surface/byte_buffer.c )
-  s.files += %w( src/core/surface/byte_buffer_reader.c )
-  s.files += %w( src/core/surface/call.c )
-  s.files += %w( src/core/surface/call_details.c )
-  s.files += %w( src/core/surface/call_log_batch.c )
-  s.files += %w( src/core/surface/channel.c )
-  s.files += %w( src/core/surface/channel_connectivity.c )
-  s.files += %w( src/core/surface/channel_create.c )
-  s.files += %w( src/core/surface/channel_ping.c )
-  s.files += %w( src/core/surface/completion_queue.c )
-  s.files += %w( src/core/surface/event_string.c )
-  s.files += %w( src/core/surface/init.c )
-  s.files += %w( src/core/surface/lame_client.c )
-  s.files += %w( src/core/surface/metadata_array.c )
-  s.files += %w( src/core/surface/server.c )
-  s.files += %w( src/core/surface/server_chttp2.c )
-  s.files += %w( src/core/surface/server_create.c )
-  s.files += %w( src/core/surface/validate_metadata.c )
-  s.files += %w( src/core/surface/version.c )
-  s.files += %w( src/core/transport/byte_stream.c )
-  s.files += %w( src/core/transport/chttp2/alpn.c )
-  s.files += %w( src/core/transport/chttp2/bin_encoder.c )
-  s.files += %w( src/core/transport/chttp2/frame_data.c )
-  s.files += %w( src/core/transport/chttp2/frame_goaway.c )
-  s.files += %w( src/core/transport/chttp2/frame_ping.c )
-  s.files += %w( src/core/transport/chttp2/frame_rst_stream.c )
-  s.files += %w( src/core/transport/chttp2/frame_settings.c )
-  s.files += %w( src/core/transport/chttp2/frame_window_update.c )
-  s.files += %w( src/core/transport/chttp2/hpack_encoder.c )
-  s.files += %w( src/core/transport/chttp2/hpack_parser.c )
-  s.files += %w( src/core/transport/chttp2/hpack_table.c )
-  s.files += %w( src/core/transport/chttp2/huffsyms.c )
-  s.files += %w( src/core/transport/chttp2/incoming_metadata.c )
-  s.files += %w( src/core/transport/chttp2/parsing.c )
-  s.files += %w( src/core/transport/chttp2/status_conversion.c )
-  s.files += %w( src/core/transport/chttp2/stream_lists.c )
-  s.files += %w( src/core/transport/chttp2/stream_map.c )
-  s.files += %w( src/core/transport/chttp2/timeout_encoding.c )
-  s.files += %w( src/core/transport/chttp2/varint.c )
-  s.files += %w( src/core/transport/chttp2/writing.c )
-  s.files += %w( src/core/transport/chttp2_transport.c )
-  s.files += %w( src/core/transport/connectivity_state.c )
-  s.files += %w( src/core/transport/metadata.c )
-  s.files += %w( src/core/transport/metadata_batch.c )
-  s.files += %w( src/core/transport/static_metadata.c )
-  s.files += %w( src/core/transport/transport.c )
-  s.files += %w( src/core/transport/transport_op_string.c )
-  s.files += %w( src/core/httpcli/httpcli_security_connector.c )
-  s.files += %w( src/core/security/b64.c )
-  s.files += %w( src/core/security/client_auth_filter.c )
-  s.files += %w( src/core/security/credentials.c )
-  s.files += %w( src/core/security/credentials_metadata.c )
-  s.files += %w( src/core/security/credentials_posix.c )
-  s.files += %w( src/core/security/credentials_win32.c )
-  s.files += %w( src/core/security/google_default_credentials.c )
-  s.files += %w( src/core/security/handshake.c )
-  s.files += %w( src/core/security/json_token.c )
-  s.files += %w( src/core/security/jwt_verifier.c )
-  s.files += %w( src/core/security/secure_endpoint.c )
-  s.files += %w( src/core/security/security_connector.c )
-  s.files += %w( src/core/security/security_context.c )
-  s.files += %w( src/core/security/server_auth_filter.c )
-  s.files += %w( src/core/security/server_secure_chttp2.c )
-  s.files += %w( src/core/surface/init_secure.c )
-  s.files += %w( src/core/surface/secure_channel_create.c )
-  s.files += %w( src/core/tsi/fake_transport_security.c )
-  s.files += %w( src/core/tsi/ssl_transport_security.c )
-  s.files += %w( src/core/tsi/transport_security.c )
-  s.files += %w( src/core/census/context.c )
-  s.files += %w( src/core/census/initialize.c )
-  s.files += %w( src/core/census/mlog.c )
-  s.files += %w( src/core/census/operation.c )
-  s.files += %w( src/core/census/placeholders.c )
-  s.files += %w( src/core/census/tracing.c )
+  s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create.c )
+  s.files += %w( src/core/ext/transport/chttp2/client/secure/secure_channel_create.c )
+  s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2.c )
+  s.files += %w( src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/alpn.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame_data.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame_goaway.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame_ping.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame_rst_stream.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame_settings.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/frame_window_update.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/hpack_encoder.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/hpack_parser.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/hpack_table.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/huffsyms.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/incoming_metadata.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/parsing.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/status_conversion.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/stream_lists.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/stream_map.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/timeout_encoding.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/varint.c )
+  s.files += %w( src/core/ext/transport/chttp2/transport/writing.c )
+  s.files += %w( src/core/lib/census/context.c )
+  s.files += %w( src/core/lib/census/grpc_context.c )
+  s.files += %w( src/core/lib/census/grpc_filter.c )
+  s.files += %w( src/core/lib/census/grpc_plugin.c )
+  s.files += %w( src/core/lib/census/initialize.c )
+  s.files += %w( src/core/lib/census/mlog.c )
+  s.files += %w( src/core/lib/census/operation.c )
+  s.files += %w( src/core/lib/census/placeholders.c )
+  s.files += %w( src/core/lib/census/tracing.c )
+  s.files += %w( src/core/lib/channel/channel_args.c )
+  s.files += %w( src/core/lib/channel/channel_stack.c )
+  s.files += %w( src/core/lib/channel/channel_stack_builder.c )
+  s.files += %w( src/core/lib/channel/client_channel.c )
+  s.files += %w( src/core/lib/channel/compress_filter.c )
+  s.files += %w( src/core/lib/channel/connected_channel.c )
+  s.files += %w( src/core/lib/channel/http_client_filter.c )
+  s.files += %w( src/core/lib/channel/http_server_filter.c )
+  s.files += %w( src/core/lib/channel/subchannel_call_holder.c )
+  s.files += %w( src/core/lib/client_config/client_config.c )
+  s.files += %w( src/core/lib/client_config/connector.c )
+  s.files += %w( src/core/lib/client_config/default_initial_connect_string.c )
+  s.files += %w( src/core/lib/client_config/initial_connect_string.c )
+  s.files += %w( src/core/lib/client_config/lb_policies/load_balancer_api.c )
+  s.files += %w( src/core/lib/client_config/lb_policies/pick_first.c )
+  s.files += %w( src/core/lib/client_config/lb_policies/round_robin.c )
+  s.files += %w( src/core/lib/client_config/lb_policy.c )
+  s.files += %w( src/core/lib/client_config/lb_policy_factory.c )
+  s.files += %w( src/core/lib/client_config/lb_policy_registry.c )
+  s.files += %w( src/core/lib/client_config/resolver.c )
+  s.files += %w( src/core/lib/client_config/resolver_factory.c )
+  s.files += %w( src/core/lib/client_config/resolver_registry.c )
+  s.files += %w( src/core/lib/client_config/resolvers/dns_resolver.c )
+  s.files += %w( src/core/lib/client_config/resolvers/sockaddr_resolver.c )
+  s.files += %w( src/core/lib/client_config/subchannel.c )
+  s.files += %w( src/core/lib/client_config/subchannel_factory.c )
+  s.files += %w( src/core/lib/client_config/subchannel_index.c )
+  s.files += %w( src/core/lib/client_config/uri_parser.c )
+  s.files += %w( src/core/lib/compression/compression_algorithm.c )
+  s.files += %w( src/core/lib/compression/message_compress.c )
+  s.files += %w( src/core/lib/debug/trace.c )
+  s.files += %w( src/core/lib/http/format_request.c )
+  s.files += %w( src/core/lib/http/httpcli.c )
+  s.files += %w( src/core/lib/http/httpcli_security_connector.c )
+  s.files += %w( src/core/lib/http/parser.c )
+  s.files += %w( src/core/lib/iomgr/closure.c )
+  s.files += %w( src/core/lib/iomgr/endpoint.c )
+  s.files += %w( src/core/lib/iomgr/endpoint_pair_posix.c )
+  s.files += %w( src/core/lib/iomgr/endpoint_pair_windows.c )
+  s.files += %w( src/core/lib/iomgr/exec_ctx.c )
+  s.files += %w( src/core/lib/iomgr/executor.c )
+  s.files += %w( src/core/lib/iomgr/fd_posix.c )
+  s.files += %w( src/core/lib/iomgr/iocp_windows.c )
+  s.files += %w( src/core/lib/iomgr/iomgr.c )
+  s.files += %w( src/core/lib/iomgr/iomgr_posix.c )
+  s.files += %w( src/core/lib/iomgr/iomgr_windows.c )
+  s.files += %w( src/core/lib/iomgr/pollset_multipoller_with_epoll.c )
+  s.files += %w( src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c )
+  s.files += %w( src/core/lib/iomgr/pollset_posix.c )
+  s.files += %w( src/core/lib/iomgr/pollset_set_posix.c )
+  s.files += %w( src/core/lib/iomgr/pollset_set_windows.c )
+  s.files += %w( src/core/lib/iomgr/pollset_windows.c )
+  s.files += %w( src/core/lib/iomgr/resolve_address_posix.c )
+  s.files += %w( src/core/lib/iomgr/resolve_address_windows.c )
+  s.files += %w( src/core/lib/iomgr/sockaddr_utils.c )
+  s.files += %w( src/core/lib/iomgr/socket_utils_common_posix.c )
+  s.files += %w( src/core/lib/iomgr/socket_utils_linux.c )
+  s.files += %w( src/core/lib/iomgr/socket_utils_posix.c )
+  s.files += %w( src/core/lib/iomgr/socket_windows.c )
+  s.files += %w( src/core/lib/iomgr/tcp_client_posix.c )
+  s.files += %w( src/core/lib/iomgr/tcp_client_windows.c )
+  s.files += %w( src/core/lib/iomgr/tcp_posix.c )
+  s.files += %w( src/core/lib/iomgr/tcp_server_posix.c )
+  s.files += %w( src/core/lib/iomgr/tcp_server_windows.c )
+  s.files += %w( src/core/lib/iomgr/tcp_windows.c )
+  s.files += %w( src/core/lib/iomgr/time_averaged_stats.c )
+  s.files += %w( src/core/lib/iomgr/timer.c )
+  s.files += %w( src/core/lib/iomgr/timer_heap.c )
+  s.files += %w( src/core/lib/iomgr/udp_server.c )
+  s.files += %w( src/core/lib/iomgr/unix_sockets_posix.c )
+  s.files += %w( src/core/lib/iomgr/unix_sockets_posix_noop.c )
+  s.files += %w( src/core/lib/iomgr/wakeup_fd_eventfd.c )
+  s.files += %w( src/core/lib/iomgr/wakeup_fd_nospecial.c )
+  s.files += %w( src/core/lib/iomgr/wakeup_fd_pipe.c )
+  s.files += %w( src/core/lib/iomgr/wakeup_fd_posix.c )
+  s.files += %w( src/core/lib/iomgr/workqueue_posix.c )
+  s.files += %w( src/core/lib/iomgr/workqueue_windows.c )
+  s.files += %w( src/core/lib/json/json.c )
+  s.files += %w( src/core/lib/json/json_reader.c )
+  s.files += %w( src/core/lib/json/json_string.c )
+  s.files += %w( src/core/lib/json/json_writer.c )
+  s.files += %w( src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c )
+  s.files += %w( src/core/lib/security/b64.c )
+  s.files += %w( src/core/lib/security/client_auth_filter.c )
+  s.files += %w( src/core/lib/security/credentials.c )
+  s.files += %w( src/core/lib/security/credentials_metadata.c )
+  s.files += %w( src/core/lib/security/credentials_posix.c )
+  s.files += %w( src/core/lib/security/credentials_win32.c )
+  s.files += %w( src/core/lib/security/google_default_credentials.c )
+  s.files += %w( src/core/lib/security/handshake.c )
+  s.files += %w( src/core/lib/security/json_token.c )
+  s.files += %w( src/core/lib/security/jwt_verifier.c )
+  s.files += %w( src/core/lib/security/secure_endpoint.c )
+  s.files += %w( src/core/lib/security/security_connector.c )
+  s.files += %w( src/core/lib/security/security_context.c )
+  s.files += %w( src/core/lib/security/server_auth_filter.c )
+  s.files += %w( src/core/lib/surface/alarm.c )
+  s.files += %w( src/core/lib/surface/api_trace.c )
+  s.files += %w( src/core/lib/surface/byte_buffer.c )
+  s.files += %w( src/core/lib/surface/byte_buffer_reader.c )
+  s.files += %w( src/core/lib/surface/call.c )
+  s.files += %w( src/core/lib/surface/call_details.c )
+  s.files += %w( src/core/lib/surface/call_log_batch.c )
+  s.files += %w( src/core/lib/surface/channel.c )
+  s.files += %w( src/core/lib/surface/channel_connectivity.c )
+  s.files += %w( src/core/lib/surface/channel_init.c )
+  s.files += %w( src/core/lib/surface/channel_ping.c )
+  s.files += %w( src/core/lib/surface/channel_stack_type.c )
+  s.files += %w( src/core/lib/surface/completion_queue.c )
+  s.files += %w( src/core/lib/surface/event_string.c )
+  s.files += %w( src/core/lib/surface/init.c )
+  s.files += %w( src/core/lib/surface/init_secure.c )
+  s.files += %w( src/core/lib/surface/lame_client.c )
+  s.files += %w( src/core/lib/surface/metadata_array.c )
+  s.files += %w( src/core/lib/surface/server.c )
+  s.files += %w( src/core/lib/surface/validate_metadata.c )
+  s.files += %w( src/core/lib/surface/version.c )
+  s.files += %w( src/core/lib/transport/byte_stream.c )
+  s.files += %w( src/core/lib/transport/connectivity_state.c )
+  s.files += %w( src/core/lib/transport/metadata.c )
+  s.files += %w( src/core/lib/transport/metadata_batch.c )
+  s.files += %w( src/core/lib/transport/static_metadata.c )
+  s.files += %w( src/core/lib/transport/transport.c )
+  s.files += %w( src/core/lib/transport/transport_op_string.c )
+  s.files += %w( src/core/lib/tsi/fake_transport_security.c )
+  s.files += %w( src/core/lib/tsi/ssl_transport_security.c )
+  s.files += %w( src/core/lib/tsi/transport_security.c )
   s.files += %w( third_party/nanopb/pb_common.c )
   s.files += %w( third_party/nanopb/pb_decode.c )
   s.files += %w( third_party/nanopb/pb_encode.c )
diff --git a/include/grpc++/alarm.h b/include/grpc++/alarm.h
index 3b8104d..764837a 100644
--- a/include/grpc++/alarm.h
+++ b/include/grpc++/alarm.h
@@ -50,7 +50,7 @@
 class CompletionQueue;
 
 /// A thin wrapper around \a grpc_alarm (see / \a / src/core/surface/alarm.h).
-class Alarm : private GrpcLibrary {
+class Alarm : private GrpcLibraryCodegen {
  public:
   /// Create a completion queue alarm instance associated to \a cq.
   ///
diff --git a/include/grpc++/channel.h b/include/grpc++/channel.h
index 80547f7..679d473 100644
--- a/include/grpc++/channel.h
+++ b/include/grpc++/channel.h
@@ -49,7 +49,7 @@
 class Channel GRPC_FINAL : public ChannelInterface,
                            public CallHook,
                            public std::enable_shared_from_this<Channel>,
-                           private GrpcLibrary {
+                           private GrpcLibraryCodegen {
  public:
   ~Channel();
 
diff --git a/include/grpc++/generic/async_generic_service.h b/include/grpc++/generic/async_generic_service.h
index 9ae8391..b87b17e 100644
--- a/include/grpc++/generic/async_generic_service.h
+++ b/include/grpc++/generic/async_generic_service.h
@@ -34,8 +34,8 @@
 #ifndef GRPCXX_GENERIC_ASYNC_GENERIC_SERVICE_H
 #define GRPCXX_GENERIC_ASYNC_GENERIC_SERVICE_H
 
-#include <grpc++/support/byte_buffer.h>
 #include <grpc++/support/async_stream.h>
+#include <grpc++/support/byte_buffer.h>
 
 struct grpc_server;
 
diff --git a/include/grpc++/impl/codegen/async_stream.h b/include/grpc++/impl/codegen/async_stream.h
index b041048..cac345e 100644
--- a/include/grpc++/impl/codegen/async_stream.h
+++ b/include/grpc++/impl/codegen/async_stream.h
@@ -34,10 +34,11 @@
 #ifndef GRPCXX_IMPL_CODEGEN_ASYNC_STREAM_H
 #define GRPCXX_IMPL_CODEGEN_ASYNC_STREAM_H
 
-#include <grpc++/impl/codegen/channel_interface.h>
 #include <grpc++/impl/codegen/call.h>
-#include <grpc++/impl/codegen/service_type.h>
+#include <grpc++/impl/codegen/channel_interface.h>
+#include <grpc++/impl/codegen/core_codegen_interface.h>
 #include <grpc++/impl/codegen/server_context.h>
+#include <grpc++/impl/codegen/service_type.h>
 #include <grpc++/impl/codegen/status.h>
 
 namespace grpc {
@@ -109,13 +110,13 @@
     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());
+    GPR_CODEGEN_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_);
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
 
     meta_ops_.set_output_tag(tag);
     meta_ops_.RecvInitialMetadata(context_);
@@ -177,7 +178,7 @@
   }
 
   void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!context_->initial_metadata_received_);
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
 
     meta_ops_.set_output_tag(tag);
     meta_ops_.RecvInitialMetadata(context_);
@@ -187,7 +188,7 @@
   void Write(const W& msg, void* tag) GRPC_OVERRIDE {
     write_ops_.set_output_tag(tag);
     // TODO(ctiller): don't assert
-    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
     call_.PerformOps(&write_ops_);
   }
 
@@ -214,7 +215,8 @@
   CallOpSet<CallOpSendMessage> write_ops_;
   CallOpSet<CallOpClientSendClose> writes_done_ops_;
   CallOpSet<CallOpRecvInitialMetadata, CallOpGenericRecvMessage,
-            CallOpClientRecvStatus> finish_ops_;
+            CallOpClientRecvStatus>
+      finish_ops_;
 };
 
 /// Client-side interface for asynchronous bi-directional streaming.
@@ -243,7 +245,7 @@
   }
 
   void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!context_->initial_metadata_received_);
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
 
     meta_ops_.set_output_tag(tag);
     meta_ops_.RecvInitialMetadata(context_);
@@ -262,7 +264,7 @@
   void Write(const W& msg, void* tag) GRPC_OVERRIDE {
     write_ops_.set_output_tag(tag);
     // TODO(ctiller): don't assert
-    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
     call_.PerformOps(&write_ops_);
   }
 
@@ -300,7 +302,7 @@
       : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
 
   void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 
     meta_ops_.set_output_tag(tag);
     meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
@@ -331,7 +333,7 @@
   }
 
   void FinishWithError(const Status& status, void* tag) {
-    GPR_ASSERT(!status.ok());
+    GPR_CODEGEN_ASSERT(!status.ok());
     finish_ops_.set_output_tag(tag);
     if (!ctx_->sent_initial_metadata_) {
       finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
@@ -349,7 +351,8 @@
   CallOpSet<CallOpSendInitialMetadata> meta_ops_;
   CallOpSet<CallOpRecvMessage<R>> read_ops_;
   CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-            CallOpServerSendStatus> finish_ops_;
+            CallOpServerSendStatus>
+      finish_ops_;
 };
 
 template <class W>
@@ -360,7 +363,7 @@
       : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
 
   void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 
     meta_ops_.set_output_tag(tag);
     meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
@@ -375,7 +378,7 @@
       ctx_->sent_initial_metadata_ = true;
     }
     // TODO(ctiller): don't assert
-    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
     call_.PerformOps(&write_ops_);
   }
 
@@ -409,7 +412,7 @@
       : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
 
   void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 
     meta_ops_.set_output_tag(tag);
     meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
@@ -430,7 +433,7 @@
       ctx_->sent_initial_metadata_ = true;
     }
     // TODO(ctiller): don't assert
-    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
     call_.PerformOps(&write_ops_);
   }
 
diff --git a/include/grpc++/impl/codegen/async_unary_call.h b/include/grpc++/impl/codegen/async_unary_call.h
index f3c75dc..1526deb 100644
--- a/include/grpc++/impl/codegen/async_unary_call.h
+++ b/include/grpc++/impl/codegen/async_unary_call.h
@@ -45,6 +45,7 @@
 namespace grpc {
 
 class CompletionQueue;
+extern CoreCodegenInterface* g_core_codegen_interface;
 
 template <class R>
 class ClientAsyncResponseReaderInterface {
@@ -68,13 +69,13 @@
     collection_->init_buf_.SetCollection(collection_);
     collection_->init_buf_.SendInitialMetadata(context->send_initial_metadata_);
     // TODO(ctiller): don't assert
-    GPR_ASSERT(collection_->init_buf_.SendMessage(request).ok());
+    GPR_CODEGEN_ASSERT(collection_->init_buf_.SendMessage(request).ok());
     collection_->init_buf_.ClientSendClose();
     call_.PerformOps(&collection_->init_buf_);
   }
 
   void ReadInitialMetadata(void* tag) {
-    GPR_ASSERT(!context_->initial_metadata_received_);
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
 
     collection_->meta_buf_.SetCollection(collection_);
     collection_->meta_buf_.set_output_tag(tag);
@@ -100,10 +101,12 @@
   class CallOpSetCollection : public CallOpSetCollectionInterface {
    public:
     SneakyCallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-                    CallOpClientSendClose> init_buf_;
+                    CallOpClientSendClose>
+        init_buf_;
     CallOpSet<CallOpRecvInitialMetadata> meta_buf_;
     CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>,
-              CallOpClientRecvStatus> finish_buf_;
+              CallOpClientRecvStatus>
+        finish_buf_;
   };
   std::shared_ptr<CallOpSetCollection> collection_;
 };
@@ -116,7 +119,7 @@
       : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
 
   void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 
     meta_buf_.set_output_tag(tag);
     meta_buf_.SendInitialMetadata(ctx_->initial_metadata_);
@@ -141,7 +144,7 @@
   }
 
   void FinishWithError(const Status& status, void* tag) {
-    GPR_ASSERT(!status.ok());
+    GPR_CODEGEN_ASSERT(!status.ok());
     finish_buf_.set_output_tag(tag);
     if (!ctx_->sent_initial_metadata_) {
       finish_buf_.SendInitialMetadata(ctx_->initial_metadata_);
@@ -158,7 +161,8 @@
   ServerContext* ctx_;
   CallOpSet<CallOpSendInitialMetadata> meta_buf_;
   CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-            CallOpServerSendStatus> finish_buf_;
+            CallOpServerSendStatus>
+      finish_buf_;
 };
 
 }  // namespace grpc
diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h
index 5e450b0..50f5a75 100644
--- a/include/grpc++/impl/codegen/call.h
+++ b/include/grpc++/impl/codegen/call.h
@@ -34,19 +34,21 @@
 #ifndef GRPCXX_IMPL_CODEGEN_CALL_H
 #define GRPCXX_IMPL_CODEGEN_CALL_H
 
-#include <functional>
-#include <memory>
-#include <map>
 #include <cstring>
+#include <functional>
+#include <map>
+#include <memory>
 
+#include <grpc++/impl/codegen/call_hook.h>
+#include <grpc++/impl/codegen/client_context.h>
+#include <grpc++/impl/codegen/completion_queue_tag.h>
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/core_codegen_interface.h>
+#include <grpc++/impl/codegen/serialization_traits.h>
+#include <grpc++/impl/codegen/status.h>
+#include <grpc++/impl/codegen/string_ref.h>
 #include <grpc/impl/codegen/alloc.h>
 #include <grpc/impl/codegen/grpc_types.h>
-#include <grpc++/impl/codegen/client_context.h>
-#include <grpc++/impl/codegen/call_hook.h>
-#include <grpc++/impl/codegen/completion_queue_tag.h>
-#include <grpc++/impl/codegen/serialization_traits.h>
-#include <grpc++/impl/codegen/config.h>
-#include <grpc++/impl/codegen/status.h>
 
 struct grpc_byte_buffer;
 
@@ -56,12 +58,39 @@
 class Call;
 class CallHook;
 class CompletionQueue;
+extern CoreCodegenInterface* g_core_codegen_interface;
 
-void FillMetadataMap(
+inline void FillMetadataMap(
     grpc_metadata_array* arr,
-    std::multimap<grpc::string_ref, grpc::string_ref>* metadata);
-grpc_metadata* FillMetadataArray(
-    const std::multimap<grpc::string, grpc::string>& metadata);
+    std::multimap<grpc::string_ref, grpc::string_ref>* metadata) {
+  for (size_t i = 0; i < arr->count; i++) {
+    // TODO(yangg) handle duplicates?
+    metadata->insert(std::pair<grpc::string_ref, grpc::string_ref>(
+        arr->metadata[i].key, grpc::string_ref(arr->metadata[i].value,
+                                               arr->metadata[i].value_length)));
+  }
+  g_core_codegen_interface->grpc_metadata_array_destroy(arr);
+  g_core_codegen_interface->grpc_metadata_array_init(arr);
+}
+
+// TODO(yangg) if the map is changed before we send, the pointers will be a
+// mess. Make sure it does not happen.
+inline grpc_metadata* FillMetadataArray(
+    const std::multimap<grpc::string, grpc::string>& metadata) {
+  if (metadata.empty()) {
+    return nullptr;
+  }
+  grpc_metadata* metadata_array =
+      (grpc_metadata*)(g_core_codegen_interface->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;
+}
 
 /// Per-message write options.
 class WriteOptions {
@@ -170,7 +199,7 @@
   }
   void FinishOp(bool* status, int max_message_size) {
     if (!send_) return;
-    gpr_free(initial_metadata_);
+    g_core_codegen_interface->gpr_free(initial_metadata_);
     send_ = false;
   }
 
@@ -204,7 +233,7 @@
     write_options_.Clear();
   }
   void FinishOp(bool* status, int max_message_size) {
-    if (own_buf_) grpc_byte_buffer_destroy(send_buf_);
+    if (own_buf_) g_core_codegen_interface->grpc_byte_buffer_destroy(send_buf_);
     send_buf_ = nullptr;
   }
 
@@ -251,10 +280,11 @@
       if (*status) {
         got_message = true;
         *status = SerializationTraits<R>::Deserialize(recv_buf_, message_,
-                                                      max_message_size).ok();
+                                                      max_message_size)
+                      .ok();
       } else {
         got_message = false;
-        grpc_byte_buffer_destroy(recv_buf_);
+        g_core_codegen_interface->grpc_byte_buffer_destroy(recv_buf_);
       }
     } else {
       got_message = false;
@@ -321,7 +351,7 @@
         *status = deserialize_->Deserialize(recv_buf_, max_message_size).ok();
       } else {
         got_message = false;
-        grpc_byte_buffer_destroy(recv_buf_);
+        g_core_codegen_interface->grpc_byte_buffer_destroy(recv_buf_);
       }
     } else {
       got_message = false;
@@ -386,7 +416,7 @@
 
   void FinishOp(bool* status, int max_message_size) {
     if (!send_status_available_) return;
-    gpr_free(trailing_metadata_);
+    g_core_codegen_interface->gpr_free(trailing_metadata_);
     send_status_available_ = false;
   }
 
@@ -462,7 +492,7 @@
     *recv_status_ = Status(
         static_cast<StatusCode>(status_code_),
         status_details_ ? grpc::string(status_details_) : grpc::string());
-    gpr_free(status_details_);
+    g_core_codegen_interface->gpr_free(status_details_);
     recv_status_ = nullptr;
   }
 
@@ -576,11 +606,22 @@
 class Call GRPC_FINAL {
  public:
   /* call is owned by the caller */
-  Call(grpc_call* call, CallHook* call_hook_, CompletionQueue* cq);
-  Call(grpc_call* call, CallHook* call_hook_, CompletionQueue* cq,
-       int max_message_size);
+  Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq)
+      : call_hook_(call_hook), cq_(cq), call_(call), max_message_size_(-1) {}
 
-  void PerformOps(CallOpSetInterface* ops);
+  Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq,
+       int max_message_size)
+      : call_hook_(call_hook),
+        cq_(cq),
+        call_(call),
+        max_message_size_(max_message_size) {}
+
+  void PerformOps(CallOpSetInterface* ops) {
+    if (max_message_size_ > 0) {
+      ops->set_max_message_size(max_message_size_);
+    }
+    call_hook_->PerformOpsOnCall(ops, this);
+  }
 
   grpc_call* call() { return call_; }
   CompletionQueue* cq() { return cq_; }
diff --git a/include/grpc++/impl/codegen/client_context.h b/include/grpc++/impl/codegen/client_context.h
index db2afe9..271d464 100644
--- a/include/grpc++/impl/codegen/client_context.h
+++ b/include/grpc++/impl/codegen/client_context.h
@@ -54,6 +54,7 @@
 #include <string>
 
 #include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/core_codegen_interface.h>
 #include <grpc++/impl/codegen/security/auth_context.h>
 #include <grpc++/impl/codegen/status.h>
 #include <grpc++/impl/codegen/string_ref.h>
@@ -192,7 +193,7 @@
   /// \return A multimap of initial metadata key-value pairs from the server.
   const std::multimap<grpc::string_ref, grpc::string_ref>&
   GetServerInitialMetadata() {
-    GPR_ASSERT(initial_metadata_received_);
+    GPR_CODEGEN_ASSERT(initial_metadata_received_);
     return recv_initial_metadata_;
   }
 
diff --git a/include/grpc++/impl/codegen/client_unary_call.h b/include/grpc++/impl/codegen/client_unary_call.h
index 0134dec..6c35a95 100644
--- a/include/grpc++/impl/codegen/client_unary_call.h
+++ b/include/grpc++/impl/codegen/client_unary_call.h
@@ -37,6 +37,7 @@
 #include <grpc++/impl/codegen/call.h>
 #include <grpc++/impl/codegen/channel_interface.h>
 #include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/core_codegen_interface.h>
 #include <grpc++/impl/codegen/status.h>
 
 namespace grpc {
@@ -55,7 +56,8 @@
   Call call(channel->CreateCall(method, context, &cq));
   CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
             CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,
-            CallOpClientSendClose, CallOpClientRecvStatus> ops;
+            CallOpClientSendClose, CallOpClientRecvStatus>
+      ops;
   Status status = ops.SendMessage(request);
   if (!status.ok()) {
     return status;
@@ -66,7 +68,7 @@
   ops.ClientSendClose();
   ops.ClientRecvStatus(context, &status);
   call.PerformOps(&ops);
-  GPR_ASSERT((cq.Pluck(&ops) && ops.got_message) || !status.ok());
+  GPR_CODEGEN_ASSERT((cq.Pluck(&ops) && ops.got_message) || !status.ok());
   return status;
 }
 
diff --git a/include/grpc++/impl/codegen/completion_queue.h b/include/grpc++/impl/codegen/completion_queue.h
index 102831e..42ec287 100644
--- a/include/grpc++/impl/codegen/completion_queue.h
+++ b/include/grpc++/impl/codegen/completion_queue.h
@@ -36,9 +36,12 @@
 #ifndef GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_H
 #define GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_H
 
+#include <grpc++/impl/codegen/completion_queue_tag.h>
+#include <grpc++/impl/codegen/core_codegen_interface.h>
 #include <grpc++/impl/codegen/grpc_library.h>
 #include <grpc++/impl/codegen/status.h>
 #include <grpc++/impl/codegen/time.h>
+#include <grpc/impl/codegen/time.h>
 
 struct grpc_completion_queue;
 
@@ -76,13 +79,17 @@
 class ServerBuilder;
 class ServerContext;
 
+extern CoreCodegenInterface* g_core_codegen_interface;
+
 /// A thin wrapper around \a grpc_completion_queue (see / \a
 /// src/core/surface/completion_queue.h).
-class CompletionQueue : private GrpcLibrary {
+class CompletionQueue : private GrpcLibraryCodegen {
  public:
   /// Default constructor. Implicitly creates a \a grpc_completion_queue
   /// instance.
-  CompletionQueue();
+  CompletionQueue() {
+    cq_ = g_core_codegen_interface->grpc_completion_queue_create(nullptr);
+  }
 
   /// Wrap \a take, taking ownership of the instance.
   ///
@@ -90,7 +97,9 @@
   explicit CompletionQueue(grpc_completion_queue* take);
 
   /// Destructor. Destroys the owned wrapped completion queue / instance.
-  ~CompletionQueue();
+  ~CompletionQueue() {
+    g_core_codegen_interface->grpc_completion_queue_destroy(cq_);
+  }
 
   /// Tri-state return for AsyncNext: SHUTDOWN, GOT_EVENT, TIMEOUT.
   enum NextStatus {
@@ -124,8 +133,8 @@
   ///
   /// \return true if read a regular event, false if the queue is shutting down.
   bool Next(void** tag, bool* ok) {
-    return (AsyncNextInternal(tag, ok, gpr_inf_future(GPR_CLOCK_REALTIME)) !=
-            SHUTDOWN);
+    return (AsyncNextInternal(tag, ok, g_core_codegen_interface->gpr_inf_future(
+                                           GPR_CLOCK_REALTIME)) != SHUTDOWN);
   }
 
   /// Request the shutdown of the queue.
@@ -181,10 +190,31 @@
 
   /// Wraps \a grpc_completion_queue_pluck.
   /// \warning Must not be mixed with calls to \a Next.
-  bool Pluck(CompletionQueueTag* tag);
+  bool Pluck(CompletionQueueTag* tag) {
+    auto deadline =
+        g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME);
+    auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
+        cq_, tag, deadline, nullptr);
+    bool ok = ev.success != 0;
+    void* ignored = tag;
+    GPR_CODEGEN_ASSERT(tag->FinalizeResult(&ignored, &ok));
+    GPR_CODEGEN_ASSERT(ignored == tag);
+    // Ignore mutations by FinalizeResult: Pluck returns the C API status
+    return ev.success != 0;
+  }
 
   /// Performs a single polling pluck on \a tag.
-  void TryPluck(CompletionQueueTag* tag);
+  /// \warning Must not be mixed with calls to \a Next.
+  void TryPluck(CompletionQueueTag* tag) {
+    auto deadline = gpr_time_0(GPR_CLOCK_REALTIME);
+    auto ev = g_core_codegen_interface->grpc_completion_queue_pluck(
+        cq_, tag, deadline, nullptr);
+    if (ev.type == GRPC_QUEUE_TIMEOUT) return;
+    bool ok = ev.success != 0;
+    void* ignored = tag;
+    // the tag must be swallowed if using TryPluck
+    GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok));
+  }
 
   grpc_completion_queue* cq_;  // owned
 };
diff --git a/include/grpc++/impl/codegen/completion_queue_tag.h b/include/grpc++/impl/codegen/completion_queue_tag.h
index 8be2ac3..e904f73 100644
--- a/include/grpc++/impl/codegen/completion_queue_tag.h
+++ b/include/grpc++/impl/codegen/completion_queue_tag.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPCXX_COMPLETION_QUEUE_TAG_H
-#define GRPCXX_COMPLETION_QUEUE_TAG_H
+#ifndef GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_TAG_H
+#define GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_TAG_H
 
 namespace grpc {
 
@@ -49,4 +49,4 @@
 
 }  // namespace grpc
 
-#endif  // GRPCXX_COMPLETION_QUEUE_TAG_H
+#endif  // GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_TAG_H
diff --git a/include/grpc++/impl/codegen/core_codegen_interface.h b/include/grpc++/impl/codegen/core_codegen_interface.h
new file mode 100644
index 0000000..a23031f
--- /dev/null
+++ b/include/grpc++/impl/codegen/core_codegen_interface.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
+#define GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
+
+#include <grpc++/impl/codegen/config_protobuf.h>
+#include <grpc++/impl/codegen/status.h>
+#include <grpc/impl/codegen/grpc_types.h>
+
+namespace grpc {
+
+/// Interface between the codegen library and the minimal subset of core
+/// features required by the generated code.
+///
+/// All undocumented methods are simply forwarding the call to their namesakes.
+/// Please refer to their corresponding documentation for details.
+///
+/// \warning This interface should be considered internal and private.
+class CoreCodegenInterface {
+ public:
+  // 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.
+  virtual Status SerializeProto(const grpc::protobuf::Message& msg,
+                                grpc_byte_buffer** buffer) = 0;
+
+  // The caller keeps ownership of buffer and msg.
+  virtual Status DeserializeProto(grpc_byte_buffer* buffer,
+                                  grpc::protobuf::Message* msg,
+                                  int max_message_size) = 0;
+
+  /// Upon a failed assertion, log the error.
+  virtual void assert_fail(const char* failed_assertion) = 0;
+
+  virtual grpc_completion_queue* grpc_completion_queue_create(
+      void* reserved) = 0;
+  virtual void grpc_completion_queue_destroy(grpc_completion_queue* cq) = 0;
+  virtual grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq,
+                                                 void* tag,
+                                                 gpr_timespec deadline,
+                                                 void* reserved) = 0;
+
+  virtual void* gpr_malloc(size_t size) = 0;
+  virtual void gpr_free(void* p) = 0;
+
+  virtual void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) = 0;
+  virtual void grpc_metadata_array_init(grpc_metadata_array* array) = 0;
+  virtual void grpc_metadata_array_destroy(grpc_metadata_array* array) = 0;
+
+  virtual gpr_timespec gpr_inf_future(gpr_clock_type type) = 0;
+};
+
+extern CoreCodegenInterface* g_core_codegen_interface;
+
+/// Codegen specific version of \a GPR_ASSERT.
+#define GPR_CODEGEN_ASSERT(x)                          \
+  do {                                                 \
+    if (!(x)) {                                        \
+      grpc::g_core_codegen_interface->assert_fail(#x); \
+    }                                                  \
+  } while (0)
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_INTERFACE_H
diff --git a/include/grpc++/impl/codegen/grpc_library.h b/include/grpc++/impl/codegen/grpc_library.h
index eb7152a..3cdc6f3 100644
--- a/include/grpc++/impl/codegen/grpc_library.h
+++ b/include/grpc++/impl/codegen/grpc_library.h
@@ -34,6 +34,7 @@
 #ifndef GRPCXX_IMPL_CODEGEN_GRPC_LIBRARY_H
 #define GRPCXX_IMPL_CODEGEN_GRPC_LIBRARY_H
 
+#include <grpc++/impl/codegen/core_codegen_interface.h>
 #include <grpc/impl/codegen/log.h>
 
 namespace grpc {
@@ -44,24 +45,27 @@
   virtual void shutdown() = 0;
 };
 
+/// Initialized by \a grpc::GrpcLibraryInitializer from
+/// <grpc++/impl/grpc_library.h>
 extern GrpcLibraryInterface* g_glip;
 
-class GrpcLibrary {
+/// Classes that require gRPC to be initialized should inherit from this class.
+class GrpcLibraryCodegen {
  public:
-  GrpcLibrary() {
-    GPR_ASSERT(g_glip &&
-               "gRPC library not initialized. See "
-               "grpc::internal::GrpcLibraryInitializer.");
+  GrpcLibraryCodegen() {
+    GPR_CODEGEN_ASSERT(g_glip &&
+                       "gRPC library not initialized. See "
+                       "grpc::internal::GrpcLibraryInitializer.");
     g_glip->init();
   }
-  virtual ~GrpcLibrary() {
-    GPR_ASSERT(g_glip &&
-               "gRPC library not initialized. See "
-               "grpc::internal::GrpcLibraryInitializer.");
+  virtual ~GrpcLibraryCodegen() {
+    GPR_CODEGEN_ASSERT(g_glip &&
+                       "gRPC library not initialized. See "
+                       "grpc::internal::GrpcLibraryInitializer.");
     g_glip->shutdown();
   }
 };
 
 }  // namespace grpc
 
-#endif  // GRPCXX_IMPL_GRPC_LIBRARY_H
+#endif  // GRPCXX_IMPL_CODEGEN_GRPC_LIBRARY_H
diff --git a/include/grpc++/impl/codegen/impl/async_stream.h b/include/grpc++/impl/codegen/impl/async_stream.h
new file mode 100644
index 0000000..95c8447
--- /dev/null
+++ b/include/grpc++/impl/codegen/impl/async_stream.h
@@ -0,0 +1,465 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_IMPL_ASYNC_STREAM_H
+#define GRPCXX_IMPL_CODEGEN_IMPL_ASYNC_STREAM_H
+
+#include <grpc++/impl/codegen/call.h>
+#include <grpc++/impl/codegen/channel_interface.h>
+#include <grpc++/impl/codegen/core_codegen_interface.h>
+#include <grpc++/impl/codegen/server_context.h>
+#include <grpc++/impl/codegen/service_type.h>
+#include <grpc++/impl/codegen/status.h>
+
+namespace grpc {
+
+class CompletionQueue;
+
+/// Common interface for all client side asynchronous streaming.
+class ClientAsyncStreamingInterface {
+ public:
+  virtual ~ClientAsyncStreamingInterface() {}
+
+  /// Request notification of the reading of the initial metadata. Completion
+  /// will be notified by \a tag on the associated completion queue.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  virtual void ReadInitialMetadata(void* tag) = 0;
+
+  /// Request notification completion.
+  ///
+  /// \param[out] status To be updated with the operation status.
+  /// \param[in] tag Tag identifying this request.
+  virtual void Finish(Status* status, void* tag) = 0;
+};
+
+/// An interface that yields a sequence of messages of type \a R.
+template <class R>
+class AsyncReaderInterface {
+ public:
+  virtual ~AsyncReaderInterface() {}
+
+  /// Read a message of type \a R into \a msg. Completion will be notified by \a
+  /// tag on the associated completion queue.
+  ///
+  /// \param[out] msg Where to eventually store the read message.
+  /// \param[in] tag The tag identifying the operation.
+  virtual void Read(R* msg, void* tag) = 0;
+};
+
+/// An interface that can be fed a sequence of messages of type \a W.
+template <class W>
+class AsyncWriterInterface {
+ public:
+  virtual ~AsyncWriterInterface() {}
+
+  /// Request the writing of \a msg with identifying tag \a tag.
+  ///
+  /// Only one write may be outstanding at any given time. This means that
+  /// after calling Write, one must wait to receive \a tag from the completion
+  /// queue BEFORE calling Write again.
+  ///
+  /// \param[in] msg The message to be written.
+  /// \param[in] tag The tag identifying the operation.
+  virtual void Write(const W& msg, void* tag) = 0;
+};
+
+template <class R>
+class ClientAsyncReaderInterface : public ClientAsyncStreamingInterface,
+                                   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 W& request, void* tag)
+      : context_(context), call_(channel->CreateCall(method, context, cq)) {
+    init_ops_.set_output_tag(tag);
+    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(init_ops_.SendMessage(request).ok());
+    init_ops_.ClientSendClose();
+    call_.PerformOps(&init_ops_);
+  }
+
+  void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.RecvInitialMetadata(context_);
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Read(R* msg, void* tag) GRPC_OVERRIDE {
+    read_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      read_ops_.RecvInitialMetadata(context_);
+    }
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
+  }
+
+  void Finish(Status* status, void* tag) GRPC_OVERRIDE {
+    finish_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      finish_ops_.RecvInitialMetadata(context_);
+    }
+    finish_ops_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  ClientContext* context_;
+  Call call_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose>
+      init_ops_;
+  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> read_ops_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_;
+};
+
+/// Common interface for client side asynchronous writing.
+template <class W>
+class ClientAsyncWriterInterface : public ClientAsyncStreamingInterface,
+                                   public AsyncWriterInterface<W> {
+ public:
+  /// Signal the client is done with the writes.
+  ///
+  /// \param[in] tag The tag identifying the operation.
+  virtual void WritesDone(void* tag) = 0;
+};
+
+template <class W>
+class ClientAsyncWriter GRPC_FINAL : public ClientAsyncWriterInterface<W> {
+ public:
+  template <class R>
+  ClientAsyncWriter(ChannelInterface* channel, CompletionQueue* cq,
+                    const RpcMethod& method, ClientContext* context,
+                    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_CODEGEN_ASSERT(!context_->initial_metadata_received_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.RecvInitialMetadata(context_);
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
+    write_ops_.set_output_tag(tag);
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void WritesDone(void* tag) GRPC_OVERRIDE {
+    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_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      finish_ops_.RecvInitialMetadata(context_);
+    }
+    finish_ops_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  ClientContext* context_;
+  Call call_;
+  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 asynchronous bi-directional streaming.
+template <class W, class R>
+class ClientAsyncReaderWriterInterface : public ClientAsyncStreamingInterface,
+                                         public AsyncWriterInterface<W>,
+                                         public AsyncReaderInterface<R> {
+ public:
+  /// Signal the client is done with the writes.
+  ///
+  /// \param[in] tag The tag identifying the operation.
+  virtual void WritesDone(void* tag) = 0;
+};
+
+template <class W, class R>
+class ClientAsyncReaderWriter GRPC_FINAL
+    : public ClientAsyncReaderWriterInterface<W, R> {
+ public:
+  ClientAsyncReaderWriter(ChannelInterface* channel, CompletionQueue* cq,
+                          const RpcMethod& method, ClientContext* context,
+                          void* tag)
+      : context_(context), call_(channel->CreateCall(method, context, cq)) {
+    init_ops_.set_output_tag(tag);
+    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
+    call_.PerformOps(&init_ops_);
+  }
+
+  void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.RecvInitialMetadata(context_);
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Read(R* msg, void* tag) GRPC_OVERRIDE {
+    read_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      read_ops_.RecvInitialMetadata(context_);
+    }
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
+  }
+
+  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
+    write_ops_.set_output_tag(tag);
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void WritesDone(void* tag) GRPC_OVERRIDE {
+    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_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      finish_ops_.RecvInitialMetadata(context_);
+    }
+    finish_ops_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  ClientContext* context_;
+  Call call_;
+  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>
+class ServerAsyncReader GRPC_FINAL : public ServerAsyncStreamingInterface,
+                                     public AsyncReaderInterface<R> {
+ public:
+  explicit ServerAsyncReader(ServerContext* ctx)
+      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+    ctx_->sent_initial_metadata_ = true;
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Read(R* msg, void* tag) GRPC_OVERRIDE {
+    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_ops_.set_output_tag(tag);
+    if (!ctx_->sent_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_ops_.ServerSendStatus(ctx_->trailing_metadata_,
+                                   finish_ops_.SendMessage(msg));
+    } else {
+      finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    }
+    call_.PerformOps(&finish_ops_);
+  }
+
+  void FinishWithError(const Status& status, void* tag) {
+    GPR_CODEGEN_ASSERT(!status.ok());
+    finish_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
+
+  Call call_;
+  ServerContext* ctx_;
+  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+  CallOpSet<CallOpRecvMessage<R>> read_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+            CallOpServerSendStatus>
+      finish_ops_;
+};
+
+template <class W>
+class ServerAsyncWriter GRPC_FINAL : public ServerAsyncStreamingInterface,
+                                     public AsyncWriterInterface<W> {
+ public:
+  explicit ServerAsyncWriter(ServerContext* ctx)
+      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+    ctx_->sent_initial_metadata_ = true;
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
+    write_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      write_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void Finish(const Status& status, void* tag) {
+    finish_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
+
+  Call call_;
+  ServerContext* ctx_;
+  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_;
+};
+
+/// Server-side interface for asynchronous bi-directional streaming.
+template <class W, class R>
+class ServerAsyncReaderWriter GRPC_FINAL : public ServerAsyncStreamingInterface,
+                                           public AsyncWriterInterface<W>,
+                                           public AsyncReaderInterface<R> {
+ public:
+  explicit ServerAsyncReaderWriter(ServerContext* ctx)
+      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+    ctx_->sent_initial_metadata_ = true;
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Read(R* msg, void* tag) GRPC_OVERRIDE {
+    read_ops_.set_output_tag(tag);
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
+  }
+
+  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
+    write_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      write_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    // TODO(ctiller): don't assert
+    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void Finish(const Status& status, void* tag) {
+    finish_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  friend class ::grpc::Server;
+
+  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
+
+  Call call_;
+  ServerContext* ctx_;
+  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+  CallOpSet<CallOpRecvMessage<R>> read_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_IMPL_ASYNC_STREAM_H
diff --git a/include/grpc++/impl/codegen/impl/status_code_enum.h b/include/grpc++/impl/codegen/impl/status_code_enum.h
new file mode 100644
index 0000000..f8caec0
--- /dev/null
+++ b/include/grpc++/impl/codegen/impl/status_code_enum.h
@@ -0,0 +1,152 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_IMPL_STATUS_CODE_ENUM_H
+#define GRPCXX_IMPL_CODEGEN_IMPL_STATUS_CODE_ENUM_H
+
+namespace grpc {
+
+enum StatusCode {
+  /// Not an error; returned on success.
+  OK = 0,
+
+  /// The operation was cancelled (typically by the caller).
+  CANCELLED = 1,
+
+  /// Unknown error. An example of where this error may be returned is if a
+  /// Status value received from another address space belongs to an error-space
+  /// that is not known in this address space. Also errors raised by APIs that
+  /// do not return enough error information may be converted to this error.
+  UNKNOWN = 2,
+
+  /// Client specified an invalid argument. Note that this differs from
+  /// FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are
+  /// problematic regardless of the state of the system (e.g., a malformed file
+  /// name).
+  INVALID_ARGUMENT = 3,
+
+  /// Deadline expired before operation could complete. For operations that
+  /// change the state of the system, this error may be returned even if the
+  /// operation has completed successfully. For example, a successful response
+  /// from a server could have been delayed long enough for the deadline to
+  /// expire.
+  DEADLINE_EXCEEDED = 4,
+
+  /// Some requested entity (e.g., file or directory) was not found.
+  NOT_FOUND = 5,
+
+  /// Some entity that we attempted to create (e.g., file or directory) already
+  /// exists.
+  ALREADY_EXISTS = 6,
+
+  /// The caller does not have permission to execute the specified operation.
+  /// PERMISSION_DENIED must not be used for rejections caused by exhausting
+  /// some resource (use RESOURCE_EXHAUSTED instead for those errors).
+  /// PERMISSION_DENIED must not be used if the caller can not be identified
+  /// (use UNAUTHENTICATED instead for those errors).
+  PERMISSION_DENIED = 7,
+
+  /// The request does not have valid authentication credentials for the
+  /// operation.
+  UNAUTHENTICATED = 16,
+
+  /// Some resource has been exhausted, perhaps a per-user quota, or perhaps the
+  /// entire file system is out of space.
+  RESOURCE_EXHAUSTED = 8,
+
+  /// Operation was rejected because the system is not in a state required for
+  /// the operation's execution. For example, directory to be deleted may be
+  /// non-empty, an rmdir operation is applied to a non-directory, etc.
+  ///
+  /// A litmus test that may help a service implementor in deciding
+  /// between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
+  ///  (a) Use UNAVAILABLE if the client can retry just the failing call.
+  ///  (b) Use ABORTED if the client should retry at a higher-level
+  ///      (e.g., restarting a read-modify-write sequence).
+  ///  (c) Use FAILED_PRECONDITION if the client should not retry until
+  ///      the system state has been explicitly fixed. E.g., if an "rmdir"
+  ///      fails because the directory is non-empty, FAILED_PRECONDITION
+  ///      should be returned since the client should not retry unless
+  ///      they have first fixed up the directory by deleting files from it.
+  ///  (d) Use FAILED_PRECONDITION if the client performs conditional
+  ///      REST Get/Update/Delete on a resource and the resource on the
+  ///      server does not match the condition. E.g., conflicting
+  ///      read-modify-write on the same resource.
+  FAILED_PRECONDITION = 9,
+
+  /// The operation was aborted, typically due to a concurrency issue like
+  /// sequencer check failures, transaction aborts, etc.
+  ///
+  /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
+  /// and UNAVAILABLE.
+  ABORTED = 10,
+
+  /// Operation was attempted past the valid range. E.g., seeking or reading
+  /// past end of file.
+  ///
+  /// Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed
+  /// if the system state changes. For example, a 32-bit file system will
+  /// generate INVALID_ARGUMENT if asked to read at an offset that is not in the
+  /// range [0,2^32-1], but it will generate OUT_OF_RANGE if asked to read from
+  /// an offset past the current file size.
+  ///
+  /// There is a fair bit of overlap between FAILED_PRECONDITION and
+  /// OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific error)
+  /// when it applies so that callers who are iterating through a space can
+  /// easily look for an OUT_OF_RANGE error to detect when they are done.
+  OUT_OF_RANGE = 11,
+
+  /// Operation is not implemented or not supported/enabled in this service.
+  UNIMPLEMENTED = 12,
+
+  /// Internal errors. Means some invariants expected by underlying System has
+  /// been broken. If you see one of these errors, Something is very broken.
+  INTERNAL = 13,
+
+  /// The service is currently unavailable. This is a most likely a transient
+  /// condition and may be corrected by retrying with a backoff.
+  ///
+  /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
+  /// and UNAVAILABLE.
+  UNAVAILABLE = 14,
+
+  /// Unrecoverable data loss or corruption.
+  DATA_LOSS = 15,
+
+  /// Force users to include a default branch:
+  DO_NOT_USE = -1
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_IMPL_STATUS_CODE_ENUM_H
diff --git a/include/grpc++/impl/codegen/impl/sync.h b/include/grpc++/impl/codegen/impl/sync.h
new file mode 100644
index 0000000..68fd0c4
--- /dev/null
+++ b/include/grpc++/impl/codegen/impl/sync.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_IMPL_SYNC_H
+#define GRPCXX_IMPL_CODEGEN_IMPL_SYNC_H
+
+#include <grpc++/impl/codegen/config.h>
+
+#ifdef GRPC_CXX0X_NO_THREAD
+#include <grpc++/impl/codegen/sync_no_cxx11.h>
+#else
+#include <grpc++/impl/codegen/sync_cxx11.h>
+#endif
+
+#endif  // GRPCXX_IMPL_CODEGEN_IMPL_SYNC_H
diff --git a/include/grpc++/impl/codegen/method_handler_impl.h b/include/grpc++/impl/codegen/method_handler_impl.h
index 1bf9bf0..0ab2ae4 100644
--- a/include/grpc++/impl/codegen/method_handler_impl.h
+++ b/include/grpc++/impl/codegen/method_handler_impl.h
@@ -34,6 +34,7 @@
 #ifndef GRPCXX_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
 #define GRPCXX_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
 
+#include <grpc++/impl/codegen/core_codegen_interface.h>
 #include <grpc++/impl/codegen/rpc_service_method.h>
 #include <grpc++/impl/codegen/sync_stream.h>
 
@@ -58,9 +59,10 @@
       status = func_(service_, param.server_context, &req, &rsp);
     }
 
-    GPR_ASSERT(!param.server_context->sent_initial_metadata_);
+    GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_);
     CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-              CallOpServerSendStatus> ops;
+              CallOpServerSendStatus>
+        ops;
     ops.SendInitialMetadata(param.server_context->initial_metadata_);
     if (status.ok()) {
       status = ops.SendMessage(rsp);
@@ -73,7 +75,8 @@
  private:
   // Application provided rpc handler function.
   std::function<Status(ServiceType*, ServerContext*, const RequestType*,
-                       ResponseType*)> func_;
+                       ResponseType*)>
+      func_;
   // The class the above handler function lives in.
   ServiceType* service_;
 };
@@ -93,9 +96,10 @@
     ResponseType rsp;
     Status status = func_(service_, param.server_context, &reader, &rsp);
 
-    GPR_ASSERT(!param.server_context->sent_initial_metadata_);
+    GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_);
     CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-              CallOpServerSendStatus> ops;
+              CallOpServerSendStatus>
+        ops;
     ops.SendInitialMetadata(param.server_context->initial_metadata_);
     if (status.ok()) {
       status = ops.SendMessage(rsp);
@@ -107,7 +111,8 @@
 
  private:
   std::function<Status(ServiceType*, ServerContext*, ServerReader<RequestType>*,
-                       ResponseType*)> func_;
+                       ResponseType*)>
+      func_;
   ServiceType* service_;
 };
 
@@ -142,7 +147,8 @@
 
  private:
   std::function<Status(ServiceType*, ServerContext*, const RequestType*,
-                       ServerWriter<ResponseType>*)> func_;
+                       ServerWriter<ResponseType>*)>
+      func_;
   ServiceType* service_;
 };
 
@@ -173,7 +179,8 @@
 
  private:
   std::function<Status(ServiceType*, ServerContext*,
-                       ServerReaderWriter<ResponseType, RequestType>*)> func_;
+                       ServerReaderWriter<ResponseType, RequestType>*)>
+      func_;
   ServiceType* service_;
 };
 
diff --git a/include/grpc++/impl/codegen/proto_utils.h b/include/grpc++/impl/codegen/proto_utils.h
index ce17710..f77f8ee 100644
--- a/include/grpc++/impl/codegen/proto_utils.h
+++ b/include/grpc++/impl/codegen/proto_utils.h
@@ -36,22 +36,16 @@
 
 #include <type_traits>
 
-#include <grpc/impl/codegen/byte_buffer.h>
-#include <grpc++/impl/codegen/serialization_traits.h>
 #include <grpc++/impl/codegen/config_protobuf.h>
+#include <grpc++/impl/codegen/core_codegen_interface.h>
+#include <grpc++/impl/codegen/serialization_traits.h>
 #include <grpc++/impl/codegen/status.h>
+#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc/impl/codegen/log.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.
-Status SerializeProto(const grpc::protobuf::Message& msg,
-                      grpc_byte_buffer** buffer);
-
-// The caller keeps ownership of buffer and msg.
-Status DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg,
-                        int max_message_size);
+extern CoreCodegenInterface* g_core_codegen_interface;
 
 template <class T>
 class SerializationTraits<T, typename std::enable_if<std::is_base_of<
@@ -60,14 +54,13 @@
   static Status Serialize(const grpc::protobuf::Message& msg,
                           grpc_byte_buffer** buffer, bool* own_buffer) {
     *own_buffer = true;
-    return SerializeProto(msg, buffer);
+    return g_core_codegen_interface->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;
+    return g_core_codegen_interface->DeserializeProto(buffer, msg,
+                                                      max_message_size);
   }
 };
 
diff --git a/include/grpc++/impl/codegen/rpc_service_method.h b/include/grpc++/impl/codegen/rpc_service_method.h
index 6256301..8b1f026 100644
--- a/include/grpc++/impl/codegen/rpc_service_method.h
+++ b/include/grpc++/impl/codegen/rpc_service_method.h
@@ -40,10 +40,10 @@
 #include <memory>
 #include <vector>
 
-#include <grpc/impl/codegen/byte_buffer.h>
 #include <grpc++/impl/codegen/config.h>
 #include <grpc++/impl/codegen/rpc_method.h>
 #include <grpc++/impl/codegen/status.h>
+#include <grpc/impl/codegen/byte_buffer.h>
 
 namespace grpc {
 class ServerContext;
diff --git a/include/grpc++/impl/codegen/server_context.h b/include/grpc++/impl/codegen/server_context.h
index ad08b82..f8326bc 100644
--- a/include/grpc++/impl/codegen/server_context.h
+++ b/include/grpc++/impl/codegen/server_context.h
@@ -37,12 +37,12 @@
 #include <map>
 #include <memory>
 
-#include <grpc/impl/codegen/compression_types.h>
-#include <grpc/impl/codegen/time.h>
-#include <grpc++/impl/codegen/security/auth_context.h>
 #include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/security/auth_context.h>
 #include <grpc++/impl/codegen/string_ref.h>
 #include <grpc++/impl/codegen/time.h>
+#include <grpc/impl/codegen/compression_types.h>
+#include <grpc/impl/codegen/time.h>
 
 struct gpr_timespec;
 struct grpc_metadata;
@@ -103,6 +103,9 @@
   void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
   void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
 
+  // IsCancelled is always safe to call when using sync API
+  // When using async API, it is only safe to call IsCancelled after
+  // the AsyncNotifyWhenDone tag has been delivered
   bool IsCancelled() const;
 
   // Cancel the Call from the server. This is a best-effort API and depending on
diff --git a/include/grpc++/impl/codegen/server_interface.h b/include/grpc++/impl/codegen/server_interface.h
index f934619..908d124 100644
--- a/include/grpc++/impl/codegen/server_interface.h
+++ b/include/grpc++/impl/codegen/server_interface.h
@@ -34,10 +34,11 @@
 #ifndef GRPCXX_IMPL_CODEGEN_SERVER_INTERFACE_H
 #define GRPCXX_IMPL_CODEGEN_SERVER_INTERFACE_H
 
-#include <grpc/impl/codegen/grpc_types.h>
 #include <grpc++/impl/codegen/call_hook.h>
 #include <grpc++/impl/codegen/completion_queue_tag.h>
+#include <grpc++/impl/codegen/core_codegen_interface.h>
 #include <grpc++/impl/codegen/rpc_service_method.h>
+#include <grpc/impl/codegen/grpc_types.h>
 
 namespace grpc {
 
@@ -191,10 +192,11 @@
     bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
       bool serialization_status =
           *status && payload_ &&
-          SerializationTraits<Message>::Deserialize(
-              payload_, request_, server_->max_message_size()).ok();
+          SerializationTraits<Message>::Deserialize(payload_, request_,
+                                                    server_->max_message_size())
+              .ok();
       bool ret = RegisteredAsyncRequest::FinalizeResult(tag, status);
-      *status = serialization_status&&* status;
+      *status = serialization_status && *status;
       return ret;
     }
 
@@ -223,7 +225,7 @@
                         CompletionQueue* call_cq,
                         ServerCompletionQueue* notification_cq, void* tag,
                         Message* message) {
-    GPR_ASSERT(method);
+    GPR_CODEGEN_ASSERT(method);
     new PayloadAsyncRequest<Message>(method->server_tag(), this, context,
                                      stream, call_cq, notification_cq, tag,
                                      message);
@@ -233,7 +235,7 @@
                         ServerAsyncStreamingInterface* stream,
                         CompletionQueue* call_cq,
                         ServerCompletionQueue* notification_cq, void* tag) {
-    GPR_ASSERT(method);
+    GPR_CODEGEN_ASSERT(method);
     new NoPayloadAsyncRequest(method->server_tag(), this, context, stream,
                               call_cq, notification_cq, tag);
   }
diff --git a/include/grpc++/impl/codegen/service_type.h b/include/grpc++/impl/codegen/service_type.h
index deb91a4..faf1893 100644
--- a/include/grpc++/impl/codegen/service_type.h
+++ b/include/grpc++/impl/codegen/service_type.h
@@ -35,6 +35,7 @@
 #define GRPCXX_IMPL_CODEGEN_SERVICE_TYPE_H
 
 #include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/core_codegen_interface.h>
 #include <grpc++/impl/codegen/rpc_service_method.h>
 #include <grpc++/impl/codegen/serialization_traits.h>
 #include <grpc++/impl/codegen/server_interface.h>
@@ -131,21 +132,18 @@
   void AddMethod(RpcServiceMethod* method) { methods_.emplace_back(method); }
 
   void MarkMethodAsync(int index) {
-    if (methods_[index].get() == nullptr) {
-      gpr_log(GPR_ERROR,
-              "Cannot mark the method as 'async' because it has already been "
-              "marked as 'generic'.");
-      return;
-    }
+    GPR_CODEGEN_ASSERT(
+        methods_[index].get() != nullptr &&
+        "Cannot mark the method as 'async' because it has already been "
+        "marked as 'generic'.");
     methods_[index]->ResetHandler();
   }
 
   void MarkMethodGeneric(int index) {
-    if (methods_[index]->handler() == nullptr) {
-      gpr_log(GPR_ERROR,
-              "Cannot mark the method as 'generic' because it has already been "
-              "marked as 'async'.");
-    }
+    GPR_CODEGEN_ASSERT(
+        methods_[index]->handler() != nullptr &&
+        "Cannot mark the method as 'generic' because it has already been "
+        "marked as 'async'.");
     methods_[index].reset();
   }
 
diff --git a/include/grpc++/impl/codegen/string_ref.h b/include/grpc++/impl/codegen/string_ref.h
index e3af37e..4af2000 100644
--- a/include/grpc++/impl/codegen/string_ref.h
+++ b/include/grpc++/impl/codegen/string_ref.h
@@ -34,8 +34,12 @@
 #ifndef GRPCXX_IMPL_CODEGEN_STRING_REF_H
 #define GRPCXX_IMPL_CODEGEN_STRING_REF_H
 
-#include <iterator>
+#include <string.h>
+
+#include <algorithm>
 #include <iosfwd>
+#include <iostream>
+#include <iterator>
 
 #include <grpc++/impl/codegen/config.h>
 
@@ -62,8 +66,13 @@
   string_ref() : data_(nullptr), length_(0) {}
   string_ref(const string_ref& other)
       : data_(other.data_), length_(other.length_) {}
-  string_ref& operator=(const string_ref& rhs);
-  string_ref(const char* s);
+  string_ref& operator=(const string_ref& rhs) {
+    data_ = rhs.data_;
+    length_ = rhs.length_;
+    return *this;
+  }
+
+  string_ref(const char* s) : data_(s), length_(strlen(s)) {}
   string_ref(const char* s, size_t l) : data_(s), length_(l) {}
   string_ref(const grpc::string& s) : data_(s.data()), length_(s.length()) {}
 
@@ -95,13 +104,40 @@
   const char* data() const { return data_; }
 
   // string operations
-  int compare(string_ref x) const;
-  bool starts_with(string_ref x) const;
-  bool ends_with(string_ref x) const;
-  size_t find(string_ref s) const;
-  size_t find(char c) const;
+  int compare(string_ref x) const {
+    size_t min_size = length_ < x.length_ ? length_ : x.length_;
+    int r = memcmp(data_, x.data_, min_size);
+    if (r < 0) return -1;
+    if (r > 0) return 1;
+    if (length_ < x.length_) return -1;
+    if (length_ > x.length_) return 1;
+    return 0;
+  }
 
-  string_ref substr(size_t pos, size_t n = npos) const;
+  bool starts_with(string_ref x) const {
+    return length_ >= x.length_ && (memcmp(data_, x.data_, x.length_) == 0);
+  }
+
+  bool ends_with(string_ref x) const {
+    return length_ >= x.length_ &&
+           (memcmp(data_ + (length_ - x.length_), x.data_, x.length_) == 0);
+  }
+
+  size_t find(string_ref s) const {
+    auto it = std::search(cbegin(), cend(), s.cbegin(), s.cend());
+    return it == cend() ? npos : std::distance(cbegin(), it);
+  }
+
+  size_t find(char c) const {
+    auto it = std::find(cbegin(), cend(), c);
+    return it == cend() ? npos : std::distance(cbegin(), it);
+  }
+
+  string_ref substr(size_t pos, size_t n = npos) const {
+    if (pos > length_) pos = length_;
+    if (n > (length_ - pos)) n = length_ - pos;
+    return string_ref(data_ + pos, n);
+  }
 
  private:
   const char* data_;
@@ -109,14 +145,16 @@
 };
 
 // Comparison operators
-bool operator==(string_ref x, string_ref y);
-bool operator!=(string_ref x, string_ref y);
-bool operator<(string_ref x, string_ref y);
-bool operator>(string_ref x, string_ref y);
-bool operator<=(string_ref x, string_ref y);
-bool operator>=(string_ref x, string_ref y);
+inline bool operator==(string_ref x, string_ref y) { return x.compare(y) == 0; }
+inline bool operator!=(string_ref x, string_ref y) { return x.compare(y) != 0; }
+inline bool operator<(string_ref x, string_ref y) { return x.compare(y) < 0; }
+inline bool operator<=(string_ref x, string_ref y) { return x.compare(y) <= 0; }
+inline bool operator>(string_ref x, string_ref y) { return x.compare(y) > 0; }
+inline bool operator>=(string_ref x, string_ref y) { return x.compare(y) >= 0; }
 
-std::ostream& operator<<(std::ostream& stream, const string_ref& string);
+inline std::ostream& operator<<(std::ostream& out, const string_ref& string) {
+  return out << grpc::string(string.begin(), string.end());
+}
 
 }  // namespace grpc
 
diff --git a/include/grpc++/impl/codegen/sync_stream.h b/include/grpc++/impl/codegen/sync_stream.h
index 9ae48bd..0eabc5f 100644
--- a/include/grpc++/impl/codegen/sync_stream.h
+++ b/include/grpc++/impl/codegen/sync_stream.h
@@ -38,6 +38,7 @@
 #include <grpc++/impl/codegen/channel_interface.h>
 #include <grpc++/impl/codegen/client_context.h>
 #include <grpc++/impl/codegen/completion_queue.h>
+#include <grpc++/impl/codegen/core_codegen_interface.h>
 #include <grpc++/impl/codegen/server_context.h>
 #include <grpc++/impl/codegen/service_type.h>
 #include <grpc++/impl/codegen/status.h>
@@ -122,17 +123,18 @@
                ClientContext* context, const W& request)
       : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
     CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-              CallOpClientSendClose> ops;
+              CallOpClientSendClose>
+        ops;
     ops.SendInitialMetadata(context->send_initial_metadata_);
     // TODO(ctiller): don't assert
-    GPR_ASSERT(ops.SendMessage(request).ok());
+    GPR_CODEGEN_ASSERT(ops.SendMessage(request).ok());
     ops.ClientSendClose();
     call_.PerformOps(&ops);
     cq_.Pluck(&ops);
   }
 
   void WaitForInitialMetadata() GRPC_OVERRIDE {
-    GPR_ASSERT(!context_->initial_metadata_received_);
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
 
     CallOpSet<CallOpRecvInitialMetadata> ops;
     ops.RecvInitialMetadata(context_);
@@ -155,7 +157,7 @@
     Status status;
     ops.ClientRecvStatus(context_, &status);
     call_.PerformOps(&ops);
-    GPR_ASSERT(cq_.Pluck(&ops));
+    GPR_CODEGEN_ASSERT(cq_.Pluck(&ops));
     return status;
   }
 
@@ -194,7 +196,7 @@
   }
 
   void WaitForInitialMetadata() {
-    GPR_ASSERT(!context_->initial_metadata_received_);
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
 
     CallOpSet<CallOpRecvInitialMetadata> ops;
     ops.RecvInitialMetadata(context_);
@@ -227,14 +229,15 @@
     }
     finish_ops_.ClientRecvStatus(context_, &status);
     call_.PerformOps(&finish_ops_);
-    GPR_ASSERT(cq_.Pluck(&finish_ops_));
+    GPR_CODEGEN_ASSERT(cq_.Pluck(&finish_ops_));
     return status;
   }
 
  private:
   ClientContext* context_;
   CallOpSet<CallOpRecvInitialMetadata, CallOpGenericRecvMessage,
-            CallOpClientRecvStatus> finish_ops_;
+            CallOpClientRecvStatus>
+      finish_ops_;
   CompletionQueue cq_;
   Call call_;
 };
@@ -271,7 +274,7 @@
   }
 
   void WaitForInitialMetadata() GRPC_OVERRIDE {
-    GPR_ASSERT(!context_->initial_metadata_received_);
+    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
 
     CallOpSet<CallOpRecvInitialMetadata> ops;
     ops.RecvInitialMetadata(context_);
@@ -312,7 +315,7 @@
     Status status;
     ops.ClientRecvStatus(context_, &status);
     call_.PerformOps(&ops);
-    GPR_ASSERT(cq_.Pluck(&ops));
+    GPR_CODEGEN_ASSERT(cq_.Pluck(&ops));
     return status;
   }
 
@@ -328,7 +331,7 @@
   ServerReader(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
 
   void SendInitialMetadata() {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 
     CallOpSet<CallOpSendInitialMetadata> ops;
     ops.SendInitialMetadata(ctx_->initial_metadata_);
@@ -355,7 +358,7 @@
   ServerWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
 
   void SendInitialMetadata() {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 
     CallOpSet<CallOpSendInitialMetadata> ops;
     ops.SendInitialMetadata(ctx_->initial_metadata_);
@@ -391,7 +394,7 @@
   ServerReaderWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
 
   void SendInitialMetadata() {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 
     CallOpSet<CallOpSendInitialMetadata> ops;
     ops.SendInitialMetadata(ctx_->initial_metadata_);
diff --git a/include/grpc++/impl/grpc_library.h b/include/grpc++/impl/grpc_library.h
index e8a075f..ecb5a4d 100644
--- a/include/grpc++/impl/grpc_library.h
+++ b/include/grpc++/impl/grpc_library.h
@@ -40,21 +40,31 @@
 #include <grpc++/impl/codegen/grpc_library.h>
 #include <grpc/grpc.h>
 
+#include "src/cpp/common/core_codegen.h"
+
 namespace grpc {
 
 namespace internal {
 class GrpcLibrary GRPC_FINAL : public GrpcLibraryInterface {
  public:
   void init() GRPC_OVERRIDE { grpc_init(); }
-
   void shutdown() GRPC_OVERRIDE { grpc_shutdown(); }
 };
 
 static GrpcLibrary g_gli;
+static CoreCodegen g_core_codegen;
 
+/// Instantiating this class ensures the proper initialization of gRPC.
 class GrpcLibraryInitializer GRPC_FINAL {
  public:
-  GrpcLibraryInitializer() { grpc::g_glip = &g_gli; }
+  GrpcLibraryInitializer() {
+    if (grpc::g_glip == nullptr) {
+      grpc::g_glip = &g_gli;
+    }
+    if (grpc::g_core_codegen_interface == nullptr) {
+      grpc::g_core_codegen_interface = &g_core_codegen;
+    }
+  }
 
   /// A no-op method to force the linker to reference this class, which will
   /// take care of initializing and shutting down the gRPC runtime.
diff --git a/include/grpc++/impl/proto_utils.h b/include/grpc++/impl/proto_utils.h
index 9124001..36acabb 100644
--- a/include/grpc++/impl/proto_utils.h
+++ b/include/grpc++/impl/proto_utils.h
@@ -31,9 +31,9 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CPP_PROTO_PROTO_UTILS_H
-#define GRPC_INTERNAL_CPP_PROTO_PROTO_UTILS_H
+#ifndef GRPCXX_IMPL_PROTO_UTILS_H
+#define GRPCXX_IMPL_PROTO_UTILS_H
 
 #include <grpc++/impl/codegen/proto_utils.h>
 
-#endif  // GRPC_INTERNAL_CPP_PROTO_PROTO_UTILS_H
+#endif  // GRPCXX_IMPL_PROTO_UTILS_H
diff --git a/include/grpc++/security/auth_context.h b/include/grpc++/security/auth_context.h
index bca8fa7..548f9a2 100644
--- a/include/grpc++/security/auth_context.h
+++ b/include/grpc++/security/auth_context.h
@@ -31,9 +31,9 @@
  *
  */
 
-#ifndef GRPCXX_SUPPORT_AUTH_CONTEXT_H
-#define GRPCXX_SUPPORT_AUTH_CONTEXT_H
+#ifndef GRPCXX_SECURITY_AUTH_CONTEXT_H
+#define GRPCXX_SECURITY_AUTH_CONTEXT_H
 
 #include <grpc++/impl/codegen/security/auth_context.h>
 
-#endif  // GRPCXX_SUPPORT_AUTH_CONTEXT_H
+#endif  // GRPCXX_SECURITY_AUTH_CONTEXT_H
diff --git a/include/grpc++/security/auth_metadata_processor.h b/include/grpc++/security/auth_metadata_processor.h
index 25011f3..b39451f 100644
--- a/include/grpc++/security/auth_metadata_processor.h
+++ b/include/grpc++/security/auth_metadata_processor.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPCXX_AUTH_METADATA_PROCESSOR_H_
-#define GRPCXX_AUTH_METADATA_PROCESSOR_H_
+#ifndef GRPCXX_SECURITY_AUTH_METADATA_PROCESSOR_H
+#define GRPCXX_SECURITY_AUTH_METADATA_PROCESSOR_H
 
 #include <map>
 
@@ -70,4 +70,4 @@
 
 }  // namespace grpc
 
-#endif  // GRPCXX_AUTH_METADATA_PROCESSOR_H_
+#endif  // GRPCXX_SECURITY_AUTH_METADATA_PROCESSOR_H
diff --git a/include/grpc++/security/credentials.h b/include/grpc++/security/credentials.h
index e0806c0..bedfc9c 100644
--- a/include/grpc++/security/credentials.h
+++ b/include/grpc++/security/credentials.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPCXX_CREDENTIALS_H
-#define GRPCXX_CREDENTIALS_H
+#ifndef GRPCXX_SECURITY_CREDENTIALS_H
+#define GRPCXX_SECURITY_CREDENTIALS_H
 
 #include <map>
 #include <memory>
@@ -57,7 +57,7 @@
 /// for all the calls on that channel.
 ///
 /// \see http://www.grpc.io/docs/guides/auth.html
-class ChannelCredentials : private GrpcLibrary {
+class ChannelCredentials : private GrpcLibraryCodegen {
  public:
   ChannelCredentials();
   ~ChannelCredentials();
@@ -83,7 +83,7 @@
 /// authenticate with a server for a given call on a channel.
 ///
 /// \see http://www.grpc.io/docs/guides/auth.html
-class CallCredentials : private GrpcLibrary {
+class CallCredentials : private GrpcLibraryCodegen {
  public:
   CallCredentials();
   ~CallCredentials();
@@ -229,4 +229,4 @@
 
 }  // namespace grpc
 
-#endif  // GRPCXX_CREDENTIALS_H
+#endif  // GRPCXX_SECURITY_CREDENTIALS_H
diff --git a/include/grpc++/security/server_credentials.h b/include/grpc++/security/server_credentials.h
index e933825..addb11c 100644
--- a/include/grpc++/security/server_credentials.h
+++ b/include/grpc++/security/server_credentials.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPCXX_SERVER_CREDENTIALS_H
-#define GRPCXX_SERVER_CREDENTIALS_H
+#ifndef GRPCXX_SECURITY_SERVER_CREDENTIALS_H
+#define GRPCXX_SECURITY_SERVER_CREDENTIALS_H
 
 #include <memory>
 #include <vector>
@@ -89,4 +89,4 @@
 
 }  // namespace grpc
 
-#endif  // GRPCXX_SERVER_CREDENTIALS_H
+#endif  // GRPCXX_SECURITY_SERVER_CREDENTIALS_H
diff --git a/include/grpc++/server.h b/include/grpc++/server.h
index c177805..9eb8c28 100644
--- a/include/grpc++/server.h
+++ b/include/grpc++/server.h
@@ -62,7 +62,7 @@
 /// Models a gRPC server.
 ///
 /// Servers are configured and started via \a grpc::ServerBuilder.
-class Server GRPC_FINAL : public ServerInterface, private GrpcLibrary {
+class Server GRPC_FINAL : public ServerInterface, private GrpcLibraryCodegen {
  public:
   ~Server();
 
diff --git a/include/grpc++/support/byte_buffer.h b/include/grpc++/support/byte_buffer.h
index 82591a8..3825518 100644
--- a/include/grpc++/support/byte_buffer.h
+++ b/include/grpc++/support/byte_buffer.h
@@ -34,13 +34,13 @@
 #ifndef GRPCXX_SUPPORT_BYTE_BUFFER_H
 #define GRPCXX_SUPPORT_BYTE_BUFFER_H
 
-#include <grpc/grpc.h>
-#include <grpc/byte_buffer.h>
-#include <grpc/support/log.h>
 #include <grpc++/impl/serialization_traits.h>
 #include <grpc++/support/config.h>
 #include <grpc++/support/slice.h>
 #include <grpc++/support/status.h>
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
 
 #include <vector>
 
@@ -99,8 +99,8 @@
   }
   static Status Serialize(const ByteBuffer& source, grpc_byte_buffer** buffer,
                           bool* own_buffer) {
-    *buffer = source.buffer();
-    *own_buffer = false;
+    *buffer = grpc_byte_buffer_copy(source.buffer());
+    *own_buffer = true;
     return Status::OK;
   }
 };
diff --git a/include/grpc++/support/channel_arguments.h b/include/grpc++/support/channel_arguments.h
index a9ede35..8c2f7c7 100644
--- a/include/grpc++/support/channel_arguments.h
+++ b/include/grpc++/support/channel_arguments.h
@@ -34,12 +34,12 @@
 #ifndef GRPCXX_SUPPORT_CHANNEL_ARGUMENTS_H
 #define GRPCXX_SUPPORT_CHANNEL_ARGUMENTS_H
 
-#include <vector>
 #include <list>
+#include <vector>
 
+#include <grpc++/support/config.h>
 #include <grpc/compression.h>
 #include <grpc/grpc.h>
-#include <grpc++/support/config.h>
 
 namespace grpc {
 namespace testing {
diff --git a/include/grpc++/support/slice.h b/include/grpc++/support/slice.h
index 724691a..6251a8b 100644
--- a/include/grpc++/support/slice.h
+++ b/include/grpc++/support/slice.h
@@ -34,8 +34,8 @@
 #ifndef GRPCXX_SUPPORT_SLICE_H
 #define GRPCXX_SUPPORT_SLICE_H
 
-#include <grpc/support/slice.h>
 #include <grpc++/support/config.h>
+#include <grpc/support/slice.h>
 
 namespace grpc {
 
diff --git a/include/grpc/byte_buffer_reader.h b/include/grpc/byte_buffer_reader.h
index b0e63a6..600bd38 100644
--- a/include/grpc/byte_buffer_reader.h
+++ b/include/grpc/byte_buffer_reader.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,8 +34,8 @@
 #ifndef GRPC_BYTE_BUFFER_READER_H
 #define GRPC_BYTE_BUFFER_READER_H
 
-#include <grpc/grpc.h>
 #include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/grpc/census.h b/include/grpc/census.h
index 442a754..4ccf4af 100644
--- a/include/grpc/census.h
+++ b/include/grpc/census.h
@@ -35,8 +35,8 @@
  * they can (ultimately) be used in many different RPC systems (with differing
  * implementations). */
 
-#ifndef CENSUS_CENSUS_H
-#define CENSUS_CENSUS_H
+#ifndef GRPC_CENSUS_H
+#define GRPC_CENSUS_H
 
 #include <grpc/grpc.h>
 
@@ -537,4 +537,4 @@
 }
 #endif
 
-#endif /* CENSUS_CENSUS_H */
+#endif /* GRPC_CENSUS_H */
diff --git a/include/grpc/compression.h b/include/grpc/compression.h
index acc168a..39023de 100644
--- a/include/grpc/compression.h
+++ b/include/grpc/compression.h
@@ -36,8 +36,8 @@
 
 #include <stdlib.h>
 
-#include <grpc/impl/codegen/port_platform.h>
 #include <grpc/impl/codegen/compression_types.h>
+#include <grpc/impl/codegen/port_platform.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -55,11 +55,12 @@
 GRPCAPI int grpc_compression_algorithm_name(
     grpc_compression_algorithm algorithm, char **name);
 
-/** Returns the compression algorithm corresponding to \a level.
+/** Returns the compression algorithm corresponding to \a level for the
+ * compression algorithms encoded in the \a accepted_encodings bitset.
  *
  * It abort()s for unknown levels . */
-GRPCAPI grpc_compression_algorithm
-grpc_compression_algorithm_for_level(grpc_compression_level level);
+GRPCAPI grpc_compression_algorithm grpc_compression_algorithm_for_level(
+    grpc_compression_level level, uint32_t accepted_encodings);
 
 GRPCAPI void grpc_compression_options_init(grpc_compression_options *opts);
 
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 5113645..fe0cf28 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -36,13 +36,13 @@
 
 #include <grpc/status.h>
 
-#include <stddef.h>
 #include <grpc/byte_buffer.h>
+#include <grpc/impl/codegen/connectivity_state.h>
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/impl/codegen/propagation_bits.h>
 #include <grpc/support/slice.h>
 #include <grpc/support/time.h>
-#include <grpc/impl/codegen/connectivity_state.h>
-#include <grpc/impl/codegen/propagation_bits.h>
-#include <grpc/impl/codegen/grpc_types.h>
+#include <stddef.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -154,9 +154,8 @@
 GRPCAPI void grpc_alarm_destroy(grpc_alarm *alarm);
 
 /** Check the connectivity state of a channel. */
-GRPCAPI grpc_connectivity_state
-grpc_channel_check_connectivity_state(grpc_channel *channel,
-                                      int try_to_connect);
+GRPCAPI grpc_connectivity_state grpc_channel_check_connectivity_state(
+    grpc_channel *channel, int try_to_connect);
 
 /** Watch for a change in connectivity state.
     Once the channel connectivity state is different from last_observed_state,
@@ -267,9 +266,10 @@
     and description passed in.
     Importantly, this function does not send status nor description to the
     remote endpoint. */
-GRPCAPI grpc_call_error
-grpc_call_cancel_with_status(grpc_call *call, grpc_status_code status,
-                             const char *description, void *reserved);
+GRPCAPI grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
+                                                     grpc_status_code status,
+                                                     const char *description,
+                                                     void *reserved);
 
 /** Destroy a call.
     THREAD SAFETY: grpc_call_destroy is thread-compatible */
@@ -283,13 +283,11 @@
     to \a cq_bound_to_call.
     Note that \a cq_for_notification must have been registered to the server via
     \a grpc_server_register_completion_queue. */
-GRPCAPI 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);
+GRPCAPI 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
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index ef7205d..f2d04e5 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -48,6 +48,7 @@
 
 #define GRPC_X509_CN_PROPERTY_NAME "x509_common_name"
 #define GRPC_X509_SAN_PROPERTY_NAME "x509_subject_alternative_name"
+#define GRPC_X509_PEM_CERT_PROPERTY_NAME "x509_pem_cert"
 
 typedef struct grpc_auth_context grpc_auth_context;
 
@@ -79,9 +80,8 @@
 
 /* Finds a property in the context. May return an empty iterator (first _next
    will return NULL) if no property with this name was found in the context. */
-GRPCAPI grpc_auth_property_iterator
-grpc_auth_context_find_properties_by_name(const grpc_auth_context *ctx,
-                                          const char *name);
+GRPCAPI grpc_auth_property_iterator grpc_auth_context_find_properties_by_name(
+    const grpc_auth_context *ctx, const char *name);
 
 /* Gets the name of the property that indicates the peer identity. Will return
    NULL if the peer is not authenticated. */
@@ -362,8 +362,8 @@
 
 /* Sets a credentials to a call. Can only be called on the client side before
    grpc_call_start_batch. */
-GRPCAPI grpc_call_error
-grpc_call_set_credentials(grpc_call *call, grpc_call_credentials *creds);
+GRPCAPI grpc_call_error grpc_call_set_credentials(grpc_call *call,
+                                                  grpc_call_credentials *creds);
 
 /* --- Auth Metadata Processing --- */
 
diff --git a/include/grpc/impl/codegen/log.h b/include/grpc/impl/codegen/log.h
index d6e18e9..afd8c5d 100644
--- a/include/grpc/impl/codegen/log.h
+++ b/include/grpc/impl/codegen/log.h
@@ -34,8 +34,8 @@
 #ifndef GRPC_IMPL_CODEGEN_LOG_H
 #define GRPC_IMPL_CODEGEN_LOG_H
 
-#include <stdlib.h> /* for abort() */
 #include <stdarg.h>
+#include <stdlib.h> /* for abort() */
 
 #include <grpc/impl/codegen/port_platform.h>
 
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index 9256904..607511e 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -133,6 +133,9 @@
 #define GPR_POSIX_TIME 1
 #define GPR_GETPID_IN_UNISTD_H 1
 #define GPR_HAVE_MSG_NOSIGNAL 1
+#define GPR_HAVE_UNIX_SOCKET 1
+#define GPR_HAVE_IP_PKTINFO 1
+#define GPR_HAVE_IPV6_RECVPKTINFO 1
 #elif defined(__linux__)
 #define GPR_POSIX_CRASH_HANDLER 1
 #define GPR_PLATFORM_STRING "linux"
@@ -154,6 +157,9 @@
 #define GPR_POSIX_WAKEUP_FD 1
 #define GPR_POSIX_SOCKET 1
 #define GPR_POSIX_SOCKETADDR 1
+#define GPR_HAVE_UNIX_SOCKET 1
+#define GPR_HAVE_IP_PKTINFO 1
+#define GPR_HAVE_IPV6_RECVPKTINFO 1
 #ifdef __GLIBC_PREREQ
 #if __GLIBC_PREREQ(2, 9)
 #define GPR_LINUX_EVENTFD 1
@@ -214,6 +220,8 @@
 #define GPR_POSIX_TIME 1
 #define GPR_GETPID_IN_UNISTD_H 1
 #define GPR_HAVE_SO_NOSIGPIPE 1
+#define GPR_HAVE_UNIX_SOCKET 1
+#define GPR_HAVE_IP_PKTINFO 1
 #ifdef _LP64
 #define GPR_ARCH_64 1
 #else /* _LP64 */
@@ -242,13 +250,49 @@
 #define GPR_POSIX_TIME 1
 #define GPR_GETPID_IN_UNISTD_H 1
 #define GPR_HAVE_SO_NOSIGPIPE 1
+#define GPR_HAVE_UNIX_SOCKET 1
+#define GPR_HAVE_IP_PKTINFO 1
+#define GPR_HAVE_IPV6_RECVPKTINFO 1
+#ifdef _LP64
+#define GPR_ARCH_64 1
+#else /* _LP64 */
+#define GPR_ARCH_32 1
+#endif /* _LP64 */
+#elif defined(__native_client__)
+#define GPR_PLATFORM_STRING "nacl"
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE
+#endif
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#define GPR_CPU_POSIX 1
+#define GPR_GCC_ATOMIC 1
+#define GPR_GCC_TLS 1
+#define GPR_POSIX_LOG 1
+#define GPR_POSIX_MULTIPOLL_WITH_POLL 1
+#define GPR_POSIX_WAKEUP_FD 1
+#define GPR_POSIX_NO_SPECIAL_WAKEUP_FD 1
+#define GPR_POSIX_SOCKET 1
+#define GPR_POSIX_SOCKETADDR 1
+#define GPR_POSIX_SOCKETUTILS 1
+#define GPR_POSIX_ENV 1
+#define GPR_POSIX_FILE 1
+#define GPR_POSIX_STRING 1
+#define GPR_POSIX_SUBPROCESS 1
+#define GPR_POSIX_SYNC 1
+#define GPR_POSIX_TIME 1
+#define GPR_GETPID_IN_UNISTD_H 1
 #ifdef _LP64
 #define GPR_ARCH_64 1
 #else /* _LP64 */
 #define GPR_ARCH_32 1
 #endif /* _LP64 */
 #else
-#error Could not auto-detect platform
+#error "Could not auto-detect platform"
 #endif
 #endif /* GPR_NO_AUTODETECT_PLATFORM */
 
diff --git a/include/grpc/impl/codegen/propagation_bits.h b/include/grpc/impl/codegen/propagation_bits.h
index cdd6997..4b64558 100644
--- a/include/grpc/impl/codegen/propagation_bits.h
+++ b/include/grpc/impl/codegen/propagation_bits.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPC_IMPL_CODEGEN_H
-#define GRPC_IMPL_CODEGEN_H
+#ifndef GRPC_IMPL_CODEGEN_PROPAGATION_BITS_H
+#define GRPC_IMPL_CODEGEN_PROPAGATION_BITS_H
 
 #include <grpc/impl/codegen/port_platform.h>
 
@@ -64,4 +64,4 @@
 }
 #endif
 
-#endif /* GRPC_IMPL_CODEGEN_H */
+#endif /* GRPC_IMPL_CODEGEN_PROPAGATION_BITS_H */
diff --git a/include/grpc/impl/codegen/slice.h b/include/grpc/impl/codegen/slice.h
index a62fdd0..03c59e7 100644
--- a/include/grpc/impl/codegen/slice.h
+++ b/include/grpc/impl/codegen/slice.h
@@ -122,8 +122,8 @@
 
 /* Equivalent to gpr_slice_new, but with a two argument destroy function that
    also takes the slice length. */
-GPRAPI gpr_slice
-gpr_slice_new_with_len(void *p, size_t len, void (*destroy)(void *, size_t));
+GPRAPI gpr_slice gpr_slice_new_with_len(void *p, size_t len,
+                                        void (*destroy)(void *, size_t));
 
 /* Equivalent to gpr_slice_new(malloc(len), len, free), but saves one malloc()
    call.
diff --git a/include/grpc/impl/codegen/slice_buffer.h b/include/grpc/impl/codegen/slice_buffer.h
index 4fe909e..7191878 100644
--- a/include/grpc/impl/codegen/slice_buffer.h
+++ b/include/grpc/impl/codegen/slice_buffer.h
@@ -73,8 +73,8 @@
    slice at the returned index in sb->slices)
    The implementation MAY decide to concatenate data at the end of a small
    slice added in this fashion. */
-GPRAPI size_t
-gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice slice);
+GPRAPI size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb,
+                                           gpr_slice slice);
 GPRAPI void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *slices,
                                   size_t n);
 /* add a very small (less than 8 bytes) amount of data to the end of a slice
diff --git a/include/grpc/impl/codegen/time.h b/include/grpc/impl/codegen/time.h
index c22bedf..b4f4509 100644
--- a/include/grpc/impl/codegen/time.h
+++ b/include/grpc/impl/codegen/time.h
@@ -88,8 +88,8 @@
 GPRAPI gpr_timespec gpr_now(gpr_clock_type clock);
 
 /* Convert a timespec from one clock to another */
-GPRAPI gpr_timespec
-gpr_convert_clock_type(gpr_timespec t, gpr_clock_type target_clock);
+GPRAPI gpr_timespec gpr_convert_clock_type(gpr_timespec t,
+                                           gpr_clock_type target_clock);
 
 /* Return -ve, 0, or +ve according to whether a < b, a == b, or a > b
    respectively.  */
diff --git a/include/grpc/support/atm_gcc_atomic.h b/include/grpc/support/atm_gcc_atomic.h
index 7e1f7fd..2fc8f60 100644
--- a/include/grpc/support/atm_gcc_atomic.h
+++ b/include/grpc/support/atm_gcc_atomic.h
@@ -31,9 +31,9 @@
  *
  */
 
-#ifndef GRPC_IMPL_CODEGEN_ATM_GCC_ATOMIC_H
-#define GRPC_IMPL_CODEGEN_ATM_GCC_ATOMIC_H
+#ifndef GRPC_SUPPORT_ATM_GCC_ATOMIC_H
+#define GRPC_SUPPORT_ATM_GCC_ATOMIC_H
 
 #include <grpc/impl/codegen/atm_gcc_atomic.h>
 
-#endif /* GRPC_IMPL_CODEGEN_ATM_GCC_ATOMIC_H */
+#endif /* GRPC_SUPPORT_ATM_GCC_ATOMIC_H */
diff --git a/include/grpc/support/subprocess.h b/include/grpc/support/subprocess.h
index 6a49460..e013b70 100644
--- a/include/grpc/support/subprocess.h
+++ b/include/grpc/support/subprocess.h
@@ -56,4 +56,4 @@
 }  // extern "C"
 #endif
 
-#endif
+#endif /* GRPC_SUPPORT_SUBPROCESS_H */
diff --git a/include/grpc/support/tls.h b/include/grpc/support/tls.h
index 43addc7..0ff19bb 100644
--- a/include/grpc/support/tls.h
+++ b/include/grpc/support/tls.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -74,4 +74,4 @@
 #include <grpc/support/tls_pthread.h>
 #endif
 
-#endif
+#endif /* GRPC_SUPPORT_TLS_H */
diff --git a/include/grpc/support/tls_gcc.h b/include/grpc/support/tls_gcc.h
index a697ad0..21269e4 100644
--- a/include/grpc/support/tls_gcc.h
+++ b/include/grpc/support/tls_gcc.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,9 +34,51 @@
 #ifndef GRPC_SUPPORT_TLS_GCC_H
 #define GRPC_SUPPORT_TLS_GCC_H
 
+#include <stdbool.h>
+
+#include <grpc/support/log.h>
+
 /* Thread local storage based on gcc compiler primitives.
    #include tls.h to use this - and see that file for documentation */
 
+#ifndef NDEBUG
+
+struct gpr_gcc_thread_local {
+  intptr_t value;
+  bool *inited;
+};
+
+#define GPR_TLS_DECL(name)           \
+  static bool name##_inited = false; \
+  static __thread struct gpr_gcc_thread_local name = {0, &(name##_inited)}
+
+#define gpr_tls_init(tls)                  \
+  do {                                     \
+    GPR_ASSERT(*((tls)->inited) == false); \
+    *((tls)->inited) = true;               \
+  } while (0)
+
+/* It is allowed to call gpr_tls_init after gpr_tls_destroy is called. */
+#define gpr_tls_destroy(tls)      \
+  do {                            \
+    GPR_ASSERT(*((tls)->inited)); \
+    *((tls)->inited) = false;     \
+  } while (0)
+
+#define gpr_tls_set(tls, new_value) \
+  do {                              \
+    GPR_ASSERT(*((tls)->inited));   \
+    (tls)->value = (new_value);     \
+  } while (0)
+
+#define gpr_tls_get(tls)          \
+  ({                              \
+    GPR_ASSERT(*((tls)->inited)); \
+    (tls)->value;                 \
+  })
+
+#else /* NDEBUG */
+
 struct gpr_gcc_thread_local {
   intptr_t value;
 };
@@ -53,4 +95,6 @@
 #define gpr_tls_set(tls, new_value) (((tls)->value) = (new_value))
 #define gpr_tls_get(tls) ((tls)->value)
 
-#endif
+#endif /* NDEBUG */
+
+#endif /* GRPC_SUPPORT_TLS_GCC_H */
diff --git a/include/grpc/support/tls_msvc.h b/include/grpc/support/tls_msvc.h
index 987a514..751ec35 100644
--- a/include/grpc/support/tls_msvc.h
+++ b/include/grpc/support/tls_msvc.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_TLS_GCC_H
-#define GRPC_SUPPORT_TLS_GCC_H
+#ifndef GRPC_SUPPORT_TLS_MSVC_H
+#define GRPC_SUPPORT_TLS_MSVC_H
 
 /* Thread local storage based on ms visual c compiler primitives.
    #include tls.h to use this - and see that file for documentation */
@@ -53,4 +53,4 @@
 #define gpr_tls_set(tls, new_value) (((tls)->value) = (new_value))
 #define gpr_tls_get(tls) ((tls)->value)
 
-#endif
+#endif /* GRPC_SUPPORT_TLS_MSVC_H */
diff --git a/include/grpc/support/tls_pthread.h b/include/grpc/support/tls_pthread.h
index 699ee6b..93ba782 100644
--- a/include/grpc/support/tls_pthread.h
+++ b/include/grpc/support/tls_pthread.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -57,4 +57,4 @@
 }
 #endif
 
-#endif
+#endif /* GRPC_SUPPORT_TLS_PTHREAD_H */
diff --git a/package.json b/package.json
index 2df2a7f..4da7c70 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc",
-  "version": "0.13.1-pre1",
+  "version": "0.14.0-dev",
   "author": "Google Inc.",
   "description": "gRPC Library for Node",
   "homepage": "http://www.grpc.io/",
@@ -27,6 +27,7 @@
   },
   "bundledDependencies": ["node-pre-gyp"],
   "dependencies": {
+    "arguejs": "^0.2.3",
     "lodash": "^3.9.3",
     "nan": "^2.0.0",
     "protobufjs": "^4.0.0"
@@ -86,6 +87,11 @@
     "src/node/src/grpc_extension.js",
     "src/node/src/metadata.js",
     "src/node/src/server.js",
+    "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/impl/codegen/byte_buffer.h",
     "include/grpc/impl/codegen/compression_types.h",
@@ -93,305 +99,309 @@
     "include/grpc/impl/codegen/grpc_types.h",
     "include/grpc/impl/codegen/propagation_bits.h",
     "include/grpc/impl/codegen/status.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/census/grpc_filter.h",
-    "src/core/channel/channel_args.h",
-    "src/core/channel/channel_stack.h",
-    "src/core/channel/client_channel.h",
-    "src/core/channel/client_uchannel.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/subchannel_call_holder.h",
-    "src/core/client_config/client_config.h",
-    "src/core/client_config/connector.h",
-    "src/core/client_config/initial_connect_string.h",
-    "src/core/client_config/lb_policies/load_balancer_api.h",
-    "src/core/client_config/lb_policies/pick_first.h",
-    "src/core/client_config/lb_policies/round_robin.h",
-    "src/core/client_config/lb_policy.h",
-    "src/core/client_config/lb_policy_factory.h",
-    "src/core/client_config/lb_policy_registry.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/sockaddr_resolver.h",
-    "src/core/client_config/subchannel.h",
-    "src/core/client_config/subchannel_factory.h",
-    "src/core/client_config/subchannel_index.h",
-    "src/core/client_config/uri_parser.h",
-    "src/core/compression/algorithm_metadata.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/parser.h",
-    "src/core/iomgr/closure.h",
-    "src/core/iomgr/endpoint.h",
-    "src/core/iomgr/endpoint_pair.h",
-    "src/core/iomgr/exec_ctx.h",
-    "src/core/iomgr/executor.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_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/timer.h",
-    "src/core/iomgr/timer_heap.h",
-    "src/core/iomgr/udp_server.h",
-    "src/core/iomgr/wakeup_fd_pipe.h",
-    "src/core/iomgr/wakeup_fd_posix.h",
-    "src/core/iomgr/workqueue.h",
-    "src/core/iomgr/workqueue_posix.h",
-    "src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.h",
-    "src/core/statistics/census_interface.h",
-    "src/core/statistics/census_rpc_stats.h",
-    "src/core/surface/api_trace.h",
-    "src/core/surface/call.h",
-    "src/core/surface/call_test_only.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/byte_stream.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_encoder.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_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/metadata_batch.h",
-    "src/core/transport/static_metadata.h",
-    "src/core/transport/transport.h",
-    "src/core/transport/transport_impl.h",
-    "src/core/security/auth_filters.h",
-    "src/core/security/b64.h",
-    "src/core/security/credentials.h",
-    "src/core/security/handshake.h",
-    "src/core/security/json_token.h",
-    "src/core/security/jwt_verifier.h",
-    "src/core/security/secure_endpoint.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/ssl_types.h",
-    "src/core/tsi/transport_security.h",
-    "src/core/tsi/transport_security_interface.h",
-    "src/core/census/aggregation.h",
-    "src/core/census/mlog.h",
-    "src/core/census/rpc_metric_id.h",
+    "src/core/ext/transport/chttp2/transport/alpn.h",
+    "src/core/ext/transport/chttp2/transport/bin_encoder.h",
+    "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
+    "src/core/ext/transport/chttp2/transport/frame.h",
+    "src/core/ext/transport/chttp2/transport/frame_data.h",
+    "src/core/ext/transport/chttp2/transport/frame_goaway.h",
+    "src/core/ext/transport/chttp2/transport/frame_ping.h",
+    "src/core/ext/transport/chttp2/transport/frame_rst_stream.h",
+    "src/core/ext/transport/chttp2/transport/frame_settings.h",
+    "src/core/ext/transport/chttp2/transport/frame_window_update.h",
+    "src/core/ext/transport/chttp2/transport/hpack_encoder.h",
+    "src/core/ext/transport/chttp2/transport/hpack_parser.h",
+    "src/core/ext/transport/chttp2/transport/hpack_table.h",
+    "src/core/ext/transport/chttp2/transport/http2_errors.h",
+    "src/core/ext/transport/chttp2/transport/huffsyms.h",
+    "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
+    "src/core/ext/transport/chttp2/transport/internal.h",
+    "src/core/ext/transport/chttp2/transport/status_conversion.h",
+    "src/core/ext/transport/chttp2/transport/stream_map.h",
+    "src/core/ext/transport/chttp2/transport/timeout_encoding.h",
+    "src/core/ext/transport/chttp2/transport/varint.h",
+    "src/core/lib/census/aggregation.h",
+    "src/core/lib/census/grpc_filter.h",
+    "src/core/lib/census/grpc_plugin.h",
+    "src/core/lib/census/mlog.h",
+    "src/core/lib/census/rpc_metric_id.h",
+    "src/core/lib/channel/channel_args.h",
+    "src/core/lib/channel/channel_stack.h",
+    "src/core/lib/channel/channel_stack_builder.h",
+    "src/core/lib/channel/client_channel.h",
+    "src/core/lib/channel/compress_filter.h",
+    "src/core/lib/channel/connected_channel.h",
+    "src/core/lib/channel/context.h",
+    "src/core/lib/channel/http_client_filter.h",
+    "src/core/lib/channel/http_server_filter.h",
+    "src/core/lib/channel/subchannel_call_holder.h",
+    "src/core/lib/client_config/client_config.h",
+    "src/core/lib/client_config/connector.h",
+    "src/core/lib/client_config/initial_connect_string.h",
+    "src/core/lib/client_config/lb_policies/load_balancer_api.h",
+    "src/core/lib/client_config/lb_policies/pick_first.h",
+    "src/core/lib/client_config/lb_policies/round_robin.h",
+    "src/core/lib/client_config/lb_policy.h",
+    "src/core/lib/client_config/lb_policy_factory.h",
+    "src/core/lib/client_config/lb_policy_registry.h",
+    "src/core/lib/client_config/resolver.h",
+    "src/core/lib/client_config/resolver_factory.h",
+    "src/core/lib/client_config/resolver_registry.h",
+    "src/core/lib/client_config/resolvers/dns_resolver.h",
+    "src/core/lib/client_config/resolvers/sockaddr_resolver.h",
+    "src/core/lib/client_config/subchannel.h",
+    "src/core/lib/client_config/subchannel_factory.h",
+    "src/core/lib/client_config/subchannel_index.h",
+    "src/core/lib/client_config/uri_parser.h",
+    "src/core/lib/compression/algorithm_metadata.h",
+    "src/core/lib/compression/message_compress.h",
+    "src/core/lib/debug/trace.h",
+    "src/core/lib/http/format_request.h",
+    "src/core/lib/http/httpcli.h",
+    "src/core/lib/http/parser.h",
+    "src/core/lib/iomgr/closure.h",
+    "src/core/lib/iomgr/endpoint.h",
+    "src/core/lib/iomgr/endpoint_pair.h",
+    "src/core/lib/iomgr/exec_ctx.h",
+    "src/core/lib/iomgr/executor.h",
+    "src/core/lib/iomgr/fd_posix.h",
+    "src/core/lib/iomgr/iocp_windows.h",
+    "src/core/lib/iomgr/iomgr.h",
+    "src/core/lib/iomgr/iomgr_internal.h",
+    "src/core/lib/iomgr/iomgr_posix.h",
+    "src/core/lib/iomgr/pollset.h",
+    "src/core/lib/iomgr/pollset_posix.h",
+    "src/core/lib/iomgr/pollset_set.h",
+    "src/core/lib/iomgr/pollset_set_posix.h",
+    "src/core/lib/iomgr/pollset_set_windows.h",
+    "src/core/lib/iomgr/pollset_windows.h",
+    "src/core/lib/iomgr/resolve_address.h",
+    "src/core/lib/iomgr/sockaddr.h",
+    "src/core/lib/iomgr/sockaddr_posix.h",
+    "src/core/lib/iomgr/sockaddr_utils.h",
+    "src/core/lib/iomgr/sockaddr_win32.h",
+    "src/core/lib/iomgr/socket_utils_posix.h",
+    "src/core/lib/iomgr/socket_windows.h",
+    "src/core/lib/iomgr/tcp_client.h",
+    "src/core/lib/iomgr/tcp_posix.h",
+    "src/core/lib/iomgr/tcp_server.h",
+    "src/core/lib/iomgr/tcp_windows.h",
+    "src/core/lib/iomgr/time_averaged_stats.h",
+    "src/core/lib/iomgr/timer.h",
+    "src/core/lib/iomgr/timer_heap.h",
+    "src/core/lib/iomgr/udp_server.h",
+    "src/core/lib/iomgr/unix_sockets_posix.h",
+    "src/core/lib/iomgr/wakeup_fd_pipe.h",
+    "src/core/lib/iomgr/wakeup_fd_posix.h",
+    "src/core/lib/iomgr/workqueue.h",
+    "src/core/lib/iomgr/workqueue_posix.h",
+    "src/core/lib/iomgr/workqueue_windows.h",
+    "src/core/lib/json/json.h",
+    "src/core/lib/json/json_common.h",
+    "src/core/lib/json/json_reader.h",
+    "src/core/lib/json/json_writer.h",
+    "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h",
+    "src/core/lib/security/auth_filters.h",
+    "src/core/lib/security/b64.h",
+    "src/core/lib/security/credentials.h",
+    "src/core/lib/security/handshake.h",
+    "src/core/lib/security/json_token.h",
+    "src/core/lib/security/jwt_verifier.h",
+    "src/core/lib/security/secure_endpoint.h",
+    "src/core/lib/security/security_connector.h",
+    "src/core/lib/security/security_context.h",
+    "src/core/lib/statistics/census_interface.h",
+    "src/core/lib/statistics/census_rpc_stats.h",
+    "src/core/lib/surface/api_trace.h",
+    "src/core/lib/surface/call.h",
+    "src/core/lib/surface/call_test_only.h",
+    "src/core/lib/surface/channel.h",
+    "src/core/lib/surface/channel_init.h",
+    "src/core/lib/surface/channel_stack_type.h",
+    "src/core/lib/surface/completion_queue.h",
+    "src/core/lib/surface/event_string.h",
+    "src/core/lib/surface/init.h",
+    "src/core/lib/surface/lame_client.h",
+    "src/core/lib/surface/server.h",
+    "src/core/lib/surface/surface_trace.h",
+    "src/core/lib/transport/byte_stream.h",
+    "src/core/lib/transport/connectivity_state.h",
+    "src/core/lib/transport/metadata.h",
+    "src/core/lib/transport/metadata_batch.h",
+    "src/core/lib/transport/static_metadata.h",
+    "src/core/lib/transport/transport.h",
+    "src/core/lib/transport/transport_impl.h",
+    "src/core/lib/tsi/fake_transport_security.h",
+    "src/core/lib/tsi/ssl_transport_security.h",
+    "src/core/lib/tsi/ssl_types.h",
+    "src/core/lib/tsi/transport_security.h",
+    "src/core/lib/tsi/transport_security_interface.h",
     "third_party/nanopb/pb.h",
     "third_party/nanopb/pb_common.h",
     "third_party/nanopb/pb_decode.h",
     "third_party/nanopb/pb_encode.h",
-    "src/core/census/grpc_context.c",
-    "src/core/census/grpc_filter.c",
-    "src/core/channel/channel_args.c",
-    "src/core/channel/channel_stack.c",
-    "src/core/channel/client_channel.c",
-    "src/core/channel/client_uchannel.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/subchannel_call_holder.c",
-    "src/core/client_config/client_config.c",
-    "src/core/client_config/connector.c",
-    "src/core/client_config/default_initial_connect_string.c",
-    "src/core/client_config/initial_connect_string.c",
-    "src/core/client_config/lb_policies/load_balancer_api.c",
-    "src/core/client_config/lb_policies/pick_first.c",
-    "src/core/client_config/lb_policies/round_robin.c",
-    "src/core/client_config/lb_policy.c",
-    "src/core/client_config/lb_policy_factory.c",
-    "src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c",
-    "src/core/client_config/subchannel.c",
-    "src/core/client_config/subchannel_factory.c",
-    "src/core/client_config/subchannel_index.c",
-    "src/core/client_config/uri_parser.c",
-    "src/core/compression/compression_algorithm.c",
-    "src/core/compression/message_compress.c",
-    "src/core/debug/trace.c",
-    "src/core/httpcli/format_request.c",
-    "src/core/httpcli/httpcli.c",
-    "src/core/httpcli/parser.c",
-    "src/core/iomgr/closure.c",
-    "src/core/iomgr/endpoint.c",
-    "src/core/iomgr/endpoint_pair_posix.c",
-    "src/core/iomgr/endpoint_pair_windows.c",
-    "src/core/iomgr/exec_ctx.c",
-    "src/core/iomgr/executor.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_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/timer.c",
-    "src/core/iomgr/timer_heap.c",
-    "src/core/iomgr/udp_server.c",
-    "src/core/iomgr/wakeup_fd_eventfd.c",
-    "src/core/iomgr/wakeup_fd_nospecial.c",
-    "src/core/iomgr/wakeup_fd_pipe.c",
-    "src/core/iomgr/wakeup_fd_posix.c",
-    "src/core/iomgr/workqueue_posix.c",
-    "src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c",
-    "src/core/surface/alarm.c",
-    "src/core/surface/api_trace.c",
-    "src/core/surface/byte_buffer.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_connectivity.c",
-    "src/core/surface/channel_create.c",
-    "src/core/surface/channel_ping.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/validate_metadata.c",
-    "src/core/surface/version.c",
-    "src/core/transport/byte_stream.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_encoder.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_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/metadata_batch.c",
-    "src/core/transport/static_metadata.c",
-    "src/core/transport/transport.c",
-    "src/core/transport/transport_op_string.c",
-    "src/core/httpcli/httpcli_security_connector.c",
-    "src/core/security/b64.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/handshake.c",
-    "src/core/security/json_token.c",
-    "src/core/security/jwt_verifier.c",
-    "src/core/security/secure_endpoint.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/context.c",
-    "src/core/census/initialize.c",
-    "src/core/census/mlog.c",
-    "src/core/census/operation.c",
-    "src/core/census/placeholders.c",
-    "src/core/census/tracing.c",
+    "src/core/ext/transport/chttp2/client/insecure/channel_create.c",
+    "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c",
+    "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
+    "src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c",
+    "src/core/ext/transport/chttp2/transport/alpn.c",
+    "src/core/ext/transport/chttp2/transport/bin_encoder.c",
+    "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
+    "src/core/ext/transport/chttp2/transport/frame_data.c",
+    "src/core/ext/transport/chttp2/transport/frame_goaway.c",
+    "src/core/ext/transport/chttp2/transport/frame_ping.c",
+    "src/core/ext/transport/chttp2/transport/frame_rst_stream.c",
+    "src/core/ext/transport/chttp2/transport/frame_settings.c",
+    "src/core/ext/transport/chttp2/transport/frame_window_update.c",
+    "src/core/ext/transport/chttp2/transport/hpack_encoder.c",
+    "src/core/ext/transport/chttp2/transport/hpack_parser.c",
+    "src/core/ext/transport/chttp2/transport/hpack_table.c",
+    "src/core/ext/transport/chttp2/transport/huffsyms.c",
+    "src/core/ext/transport/chttp2/transport/incoming_metadata.c",
+    "src/core/ext/transport/chttp2/transport/parsing.c",
+    "src/core/ext/transport/chttp2/transport/status_conversion.c",
+    "src/core/ext/transport/chttp2/transport/stream_lists.c",
+    "src/core/ext/transport/chttp2/transport/stream_map.c",
+    "src/core/ext/transport/chttp2/transport/timeout_encoding.c",
+    "src/core/ext/transport/chttp2/transport/varint.c",
+    "src/core/ext/transport/chttp2/transport/writing.c",
+    "src/core/lib/census/context.c",
+    "src/core/lib/census/grpc_context.c",
+    "src/core/lib/census/grpc_filter.c",
+    "src/core/lib/census/grpc_plugin.c",
+    "src/core/lib/census/initialize.c",
+    "src/core/lib/census/mlog.c",
+    "src/core/lib/census/operation.c",
+    "src/core/lib/census/placeholders.c",
+    "src/core/lib/census/tracing.c",
+    "src/core/lib/channel/channel_args.c",
+    "src/core/lib/channel/channel_stack.c",
+    "src/core/lib/channel/channel_stack_builder.c",
+    "src/core/lib/channel/client_channel.c",
+    "src/core/lib/channel/compress_filter.c",
+    "src/core/lib/channel/connected_channel.c",
+    "src/core/lib/channel/http_client_filter.c",
+    "src/core/lib/channel/http_server_filter.c",
+    "src/core/lib/channel/subchannel_call_holder.c",
+    "src/core/lib/client_config/client_config.c",
+    "src/core/lib/client_config/connector.c",
+    "src/core/lib/client_config/default_initial_connect_string.c",
+    "src/core/lib/client_config/initial_connect_string.c",
+    "src/core/lib/client_config/lb_policies/load_balancer_api.c",
+    "src/core/lib/client_config/lb_policies/pick_first.c",
+    "src/core/lib/client_config/lb_policies/round_robin.c",
+    "src/core/lib/client_config/lb_policy.c",
+    "src/core/lib/client_config/lb_policy_factory.c",
+    "src/core/lib/client_config/lb_policy_registry.c",
+    "src/core/lib/client_config/resolver.c",
+    "src/core/lib/client_config/resolver_factory.c",
+    "src/core/lib/client_config/resolver_registry.c",
+    "src/core/lib/client_config/resolvers/dns_resolver.c",
+    "src/core/lib/client_config/resolvers/sockaddr_resolver.c",
+    "src/core/lib/client_config/subchannel.c",
+    "src/core/lib/client_config/subchannel_factory.c",
+    "src/core/lib/client_config/subchannel_index.c",
+    "src/core/lib/client_config/uri_parser.c",
+    "src/core/lib/compression/compression_algorithm.c",
+    "src/core/lib/compression/message_compress.c",
+    "src/core/lib/debug/trace.c",
+    "src/core/lib/http/format_request.c",
+    "src/core/lib/http/httpcli.c",
+    "src/core/lib/http/httpcli_security_connector.c",
+    "src/core/lib/http/parser.c",
+    "src/core/lib/iomgr/closure.c",
+    "src/core/lib/iomgr/endpoint.c",
+    "src/core/lib/iomgr/endpoint_pair_posix.c",
+    "src/core/lib/iomgr/endpoint_pair_windows.c",
+    "src/core/lib/iomgr/exec_ctx.c",
+    "src/core/lib/iomgr/executor.c",
+    "src/core/lib/iomgr/fd_posix.c",
+    "src/core/lib/iomgr/iocp_windows.c",
+    "src/core/lib/iomgr/iomgr.c",
+    "src/core/lib/iomgr/iomgr_posix.c",
+    "src/core/lib/iomgr/iomgr_windows.c",
+    "src/core/lib/iomgr/pollset_multipoller_with_epoll.c",
+    "src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c",
+    "src/core/lib/iomgr/pollset_posix.c",
+    "src/core/lib/iomgr/pollset_set_posix.c",
+    "src/core/lib/iomgr/pollset_set_windows.c",
+    "src/core/lib/iomgr/pollset_windows.c",
+    "src/core/lib/iomgr/resolve_address_posix.c",
+    "src/core/lib/iomgr/resolve_address_windows.c",
+    "src/core/lib/iomgr/sockaddr_utils.c",
+    "src/core/lib/iomgr/socket_utils_common_posix.c",
+    "src/core/lib/iomgr/socket_utils_linux.c",
+    "src/core/lib/iomgr/socket_utils_posix.c",
+    "src/core/lib/iomgr/socket_windows.c",
+    "src/core/lib/iomgr/tcp_client_posix.c",
+    "src/core/lib/iomgr/tcp_client_windows.c",
+    "src/core/lib/iomgr/tcp_posix.c",
+    "src/core/lib/iomgr/tcp_server_posix.c",
+    "src/core/lib/iomgr/tcp_server_windows.c",
+    "src/core/lib/iomgr/tcp_windows.c",
+    "src/core/lib/iomgr/time_averaged_stats.c",
+    "src/core/lib/iomgr/timer.c",
+    "src/core/lib/iomgr/timer_heap.c",
+    "src/core/lib/iomgr/udp_server.c",
+    "src/core/lib/iomgr/unix_sockets_posix.c",
+    "src/core/lib/iomgr/unix_sockets_posix_noop.c",
+    "src/core/lib/iomgr/wakeup_fd_eventfd.c",
+    "src/core/lib/iomgr/wakeup_fd_nospecial.c",
+    "src/core/lib/iomgr/wakeup_fd_pipe.c",
+    "src/core/lib/iomgr/wakeup_fd_posix.c",
+    "src/core/lib/iomgr/workqueue_posix.c",
+    "src/core/lib/iomgr/workqueue_windows.c",
+    "src/core/lib/json/json.c",
+    "src/core/lib/json/json_reader.c",
+    "src/core/lib/json/json_string.c",
+    "src/core/lib/json/json_writer.c",
+    "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c",
+    "src/core/lib/security/b64.c",
+    "src/core/lib/security/client_auth_filter.c",
+    "src/core/lib/security/credentials.c",
+    "src/core/lib/security/credentials_metadata.c",
+    "src/core/lib/security/credentials_posix.c",
+    "src/core/lib/security/credentials_win32.c",
+    "src/core/lib/security/google_default_credentials.c",
+    "src/core/lib/security/handshake.c",
+    "src/core/lib/security/json_token.c",
+    "src/core/lib/security/jwt_verifier.c",
+    "src/core/lib/security/secure_endpoint.c",
+    "src/core/lib/security/security_connector.c",
+    "src/core/lib/security/security_context.c",
+    "src/core/lib/security/server_auth_filter.c",
+    "src/core/lib/surface/alarm.c",
+    "src/core/lib/surface/api_trace.c",
+    "src/core/lib/surface/byte_buffer.c",
+    "src/core/lib/surface/byte_buffer_reader.c",
+    "src/core/lib/surface/call.c",
+    "src/core/lib/surface/call_details.c",
+    "src/core/lib/surface/call_log_batch.c",
+    "src/core/lib/surface/channel.c",
+    "src/core/lib/surface/channel_connectivity.c",
+    "src/core/lib/surface/channel_init.c",
+    "src/core/lib/surface/channel_ping.c",
+    "src/core/lib/surface/channel_stack_type.c",
+    "src/core/lib/surface/completion_queue.c",
+    "src/core/lib/surface/event_string.c",
+    "src/core/lib/surface/init.c",
+    "src/core/lib/surface/init_secure.c",
+    "src/core/lib/surface/lame_client.c",
+    "src/core/lib/surface/metadata_array.c",
+    "src/core/lib/surface/server.c",
+    "src/core/lib/surface/validate_metadata.c",
+    "src/core/lib/surface/version.c",
+    "src/core/lib/transport/byte_stream.c",
+    "src/core/lib/transport/connectivity_state.c",
+    "src/core/lib/transport/metadata.c",
+    "src/core/lib/transport/metadata_batch.c",
+    "src/core/lib/transport/static_metadata.c",
+    "src/core/lib/transport/transport.c",
+    "src/core/lib/transport/transport_op_string.c",
+    "src/core/lib/tsi/fake_transport_security.c",
+    "src/core/lib/tsi/ssl_transport_security.c",
+    "src/core/lib/tsi/transport_security.c",
     "third_party/nanopb/pb_common.c",
     "third_party/nanopb/pb_decode.c",
     "third_party/nanopb/pb_encode.c",
@@ -822,6 +832,20 @@
     "third_party/boringssl/ssl/t1_enc.c",
     "third_party/boringssl/ssl/t1_lib.c",
     "third_party/boringssl/ssl/tls_record.c",
+    "include/grpc/impl/codegen/alloc.h",
+    "include/grpc/impl/codegen/atm.h",
+    "include/grpc/impl/codegen/atm_gcc_atomic.h",
+    "include/grpc/impl/codegen/atm_gcc_sync.h",
+    "include/grpc/impl/codegen/atm_win32.h",
+    "include/grpc/impl/codegen/log.h",
+    "include/grpc/impl/codegen/port_platform.h",
+    "include/grpc/impl/codegen/slice.h",
+    "include/grpc/impl/codegen/slice_buffer.h",
+    "include/grpc/impl/codegen/sync.h",
+    "include/grpc/impl/codegen/sync_generic.h",
+    "include/grpc/impl/codegen/sync_posix.h",
+    "include/grpc/impl/codegen/sync_win32.h",
+    "include/grpc/impl/codegen/time.h",
     "include/grpc/support/alloc.h",
     "include/grpc/support/atm.h",
     "include/grpc/support/atm_gcc_atomic.h",
@@ -850,74 +874,62 @@
     "include/grpc/support/tls_msvc.h",
     "include/grpc/support/tls_pthread.h",
     "include/grpc/support/useful.h",
-    "include/grpc/impl/codegen/alloc.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_win32.h",
-    "include/grpc/impl/codegen/log.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/slice_buffer.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_win32.h",
-    "include/grpc/impl/codegen/time.h",
-    "src/core/profiling/timers.h",
-    "src/core/support/block_annotate.h",
-    "src/core/support/env.h",
-    "src/core/support/load_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/time_precise.h",
-    "src/core/support/tmpfile.h",
-    "src/core/profiling/basic_timers.c",
-    "src/core/profiling/stap_timers.c",
-    "src/core/support/alloc.c",
-    "src/core/support/avl.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/histogram.c",
-    "src/core/support/host_port.c",
-    "src/core/support/load_file.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/subprocess_windows.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_precise.c",
-    "src/core/support/time_win32.c",
-    "src/core/support/tls_pthread.c",
-    "src/core/support/tmpfile_posix.c",
-    "src/core/support/tmpfile_win32.c",
-    "src/core/support/wrap_memcpy.c",
+    "src/core/lib/profiling/timers.h",
+    "src/core/lib/support/backoff.h",
+    "src/core/lib/support/block_annotate.h",
+    "src/core/lib/support/env.h",
+    "src/core/lib/support/load_file.h",
+    "src/core/lib/support/murmur_hash.h",
+    "src/core/lib/support/stack_lockfree.h",
+    "src/core/lib/support/string.h",
+    "src/core/lib/support/string_win32.h",
+    "src/core/lib/support/thd_internal.h",
+    "src/core/lib/support/time_precise.h",
+    "src/core/lib/support/tmpfile.h",
+    "src/core/lib/profiling/basic_timers.c",
+    "src/core/lib/profiling/stap_timers.c",
+    "src/core/lib/support/alloc.c",
+    "src/core/lib/support/avl.c",
+    "src/core/lib/support/backoff.c",
+    "src/core/lib/support/cmdline.c",
+    "src/core/lib/support/cpu_iphone.c",
+    "src/core/lib/support/cpu_linux.c",
+    "src/core/lib/support/cpu_posix.c",
+    "src/core/lib/support/cpu_windows.c",
+    "src/core/lib/support/env_linux.c",
+    "src/core/lib/support/env_posix.c",
+    "src/core/lib/support/env_win32.c",
+    "src/core/lib/support/histogram.c",
+    "src/core/lib/support/host_port.c",
+    "src/core/lib/support/load_file.c",
+    "src/core/lib/support/log.c",
+    "src/core/lib/support/log_android.c",
+    "src/core/lib/support/log_linux.c",
+    "src/core/lib/support/log_posix.c",
+    "src/core/lib/support/log_win32.c",
+    "src/core/lib/support/murmur_hash.c",
+    "src/core/lib/support/slice.c",
+    "src/core/lib/support/slice_buffer.c",
+    "src/core/lib/support/stack_lockfree.c",
+    "src/core/lib/support/string.c",
+    "src/core/lib/support/string_posix.c",
+    "src/core/lib/support/string_win32.c",
+    "src/core/lib/support/subprocess_posix.c",
+    "src/core/lib/support/subprocess_windows.c",
+    "src/core/lib/support/sync.c",
+    "src/core/lib/support/sync_posix.c",
+    "src/core/lib/support/sync_win32.c",
+    "src/core/lib/support/thd.c",
+    "src/core/lib/support/thd_posix.c",
+    "src/core/lib/support/thd_win32.c",
+    "src/core/lib/support/time.c",
+    "src/core/lib/support/time_posix.c",
+    "src/core/lib/support/time_precise.c",
+    "src/core/lib/support/time_win32.c",
+    "src/core/lib/support/tls_pthread.c",
+    "src/core/lib/support/tmpfile_posix.c",
+    "src/core/lib/support/tmpfile_win32.c",
+    "src/core/lib/support/wrap_memcpy.c",
     "binding.gyp"
   ],
   "main": "src/node/index.js",
diff --git a/package.xml b/package.xml
index e65ab73..a40cd16 100644
--- a/package.xml
+++ b/package.xml
@@ -27,9 +27,9 @@
  <contents>
   <dir baseinstalldir="/" name="/">
     <file baseinstalldir="/" name="config.m4" role="src" />
+    <file baseinstalldir="/" name="src/php/README.md" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/CREDITS" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/LICENSE" role="src" />
-    <file baseinstalldir="/" name="src/php/ext/grpc/README.md" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/byte_buffer.c" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/call.c" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/call_credentials.c" role="src" />
@@ -50,6 +50,20 @@
     <file baseinstalldir="/" name="src/php/ext/grpc/server.h" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/server_credentials.h" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/timeval.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/alloc.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/atm.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_atomic.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_sync.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_win32.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/log.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/port_platform.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/slice.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/slice_buffer.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/sync.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_generic.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_posix.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_win32.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/time.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/alloc.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/atm.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/atm_gcc_atomic.h" role="src" />
@@ -78,74 +92,67 @@
     <file baseinstalldir="/" name="include/grpc/support/tls_msvc.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/tls_pthread.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/useful.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/alloc.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/atm.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_atomic.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_sync.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_win32.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/log.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/port_platform.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/slice.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/slice_buffer.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/sync.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_generic.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_posix.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_win32.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/impl/codegen/time.h" role="src" />
-    <file baseinstalldir="/" name="src/core/profiling/timers.h" role="src" />
-    <file baseinstalldir="/" name="src/core/support/block_annotate.h" role="src" />
-    <file baseinstalldir="/" name="src/core/support/env.h" role="src" />
-    <file baseinstalldir="/" name="src/core/support/load_file.h" role="src" />
-    <file baseinstalldir="/" name="src/core/support/murmur_hash.h" role="src" />
-    <file baseinstalldir="/" name="src/core/support/stack_lockfree.h" role="src" />
-    <file baseinstalldir="/" name="src/core/support/string.h" role="src" />
-    <file baseinstalldir="/" name="src/core/support/string_win32.h" role="src" />
-    <file baseinstalldir="/" name="src/core/support/thd_internal.h" role="src" />
-    <file baseinstalldir="/" name="src/core/support/time_precise.h" role="src" />
-    <file baseinstalldir="/" name="src/core/support/tmpfile.h" role="src" />
-    <file baseinstalldir="/" name="src/core/profiling/basic_timers.c" role="src" />
-    <file baseinstalldir="/" name="src/core/profiling/stap_timers.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/alloc.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/avl.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/cmdline.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/cpu_iphone.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/cpu_linux.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/cpu_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/cpu_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/env_linux.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/env_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/env_win32.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/histogram.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/host_port.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/load_file.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/log.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/log_android.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/log_linux.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/log_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/log_win32.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/murmur_hash.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/slice.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/slice_buffer.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/stack_lockfree.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/string.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/string_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/string_win32.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/subprocess_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/subprocess_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/sync.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/sync_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/sync_win32.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/thd.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/thd_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/thd_win32.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/time.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/time_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/time_precise.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/time_win32.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/tls_pthread.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/tmpfile_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/tmpfile_win32.c" role="src" />
-    <file baseinstalldir="/" name="src/core/support/wrap_memcpy.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/profiling/timers.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/backoff.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/block_annotate.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/env.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/load_file.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/murmur_hash.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/stack_lockfree.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/string.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/string_win32.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/thd_internal.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/time_precise.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/tmpfile.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/profiling/stap_timers.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/alloc.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/avl.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/backoff.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/cmdline.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/cpu_iphone.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/cpu_linux.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/cpu_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/cpu_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/env_linux.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/env_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/env_win32.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/histogram.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/host_port.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/load_file.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/log.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/log_android.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/log_linux.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/log_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/log_win32.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/murmur_hash.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/slice.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/slice_buffer.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/stack_lockfree.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/string.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/string_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/string_win32.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/subprocess_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/subprocess_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/sync.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/sync_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/sync_win32.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/thd.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/thd_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/thd_win32.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/time.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/time_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/time_precise.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/time_win32.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/tls_pthread.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/tmpfile_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/tmpfile_win32.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/wrap_memcpy.c" role="src" />
+    <file baseinstalldir="/" name="include/grpc/byte_buffer.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/byte_buffer_reader.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/census.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/compression.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/grpc.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/grpc_security.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/byte_buffer.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/compression_types.h" role="src" />
@@ -153,305 +160,309 @@
     <file baseinstalldir="/" name="include/grpc/impl/codegen/grpc_types.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/propagation_bits.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/status.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/byte_buffer.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/byte_buffer_reader.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/compression.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/grpc.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/status.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/census.h" role="src" />
-    <file baseinstalldir="/" name="src/core/census/grpc_filter.h" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/channel_args.h" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/channel_stack.h" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/client_channel.h" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/client_uchannel.h" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/compress_filter.h" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/connected_channel.h" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/context.h" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/http_client_filter.h" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/http_server_filter.h" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/subchannel_call_holder.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/client_config.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/connector.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/initial_connect_string.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/lb_policies/load_balancer_api.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/lb_policies/pick_first.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/lb_policies/round_robin.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/lb_policy.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/lb_policy_factory.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/lb_policy_registry.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/resolver.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/resolver_factory.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/resolver_registry.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/resolvers/dns_resolver.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/resolvers/sockaddr_resolver.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/subchannel.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/subchannel_factory.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/subchannel_index.h" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/uri_parser.h" role="src" />
-    <file baseinstalldir="/" name="src/core/compression/algorithm_metadata.h" role="src" />
-    <file baseinstalldir="/" name="src/core/compression/message_compress.h" role="src" />
-    <file baseinstalldir="/" name="src/core/debug/trace.h" role="src" />
-    <file baseinstalldir="/" name="src/core/httpcli/format_request.h" role="src" />
-    <file baseinstalldir="/" name="src/core/httpcli/httpcli.h" role="src" />
-    <file baseinstalldir="/" name="src/core/httpcli/parser.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/closure.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/endpoint.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/endpoint_pair.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/exec_ctx.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/executor.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/fd_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/iocp_windows.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/iomgr.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/iomgr_internal.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/iomgr_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/pollset.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/pollset_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/pollset_set.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/pollset_set_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/pollset_set_windows.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/pollset_windows.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/resolve_address.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/sockaddr.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/sockaddr_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/sockaddr_utils.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/sockaddr_win32.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/socket_utils_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/socket_windows.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/tcp_client.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/tcp_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/tcp_server.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/tcp_windows.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/time_averaged_stats.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/timer.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/timer_heap.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/udp_server.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/wakeup_fd_pipe.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/wakeup_fd_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/workqueue.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/workqueue_posix.h" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/workqueue_windows.h" role="src" />
-    <file baseinstalldir="/" name="src/core/json/json.h" role="src" />
-    <file baseinstalldir="/" name="src/core/json/json_common.h" role="src" />
-    <file baseinstalldir="/" name="src/core/json/json_reader.h" role="src" />
-    <file baseinstalldir="/" name="src/core/json/json_writer.h" role="src" />
-    <file baseinstalldir="/" name="src/core/proto/grpc/lb/v0/load_balancer.pb.h" role="src" />
-    <file baseinstalldir="/" name="src/core/statistics/census_interface.h" role="src" />
-    <file baseinstalldir="/" name="src/core/statistics/census_rpc_stats.h" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/api_trace.h" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/call.h" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/call_test_only.h" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/channel.h" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/completion_queue.h" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/event_string.h" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/init.h" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/server.h" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/surface_trace.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/byte_stream.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/alpn.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/bin_encoder.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame_data.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame_goaway.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame_ping.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame_rst_stream.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame_settings.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame_window_update.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/hpack_encoder.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/hpack_parser.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/hpack_table.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/http2_errors.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/huffsyms.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/incoming_metadata.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/internal.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/status_conversion.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/stream_map.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/timeout_encoding.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/varint.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2_transport.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/connectivity_state.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/metadata.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/metadata_batch.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/static_metadata.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/transport.h" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/transport_impl.h" role="src" />
-    <file baseinstalldir="/" name="src/core/security/auth_filters.h" role="src" />
-    <file baseinstalldir="/" name="src/core/security/b64.h" role="src" />
-    <file baseinstalldir="/" name="src/core/security/credentials.h" role="src" />
-    <file baseinstalldir="/" name="src/core/security/handshake.h" role="src" />
-    <file baseinstalldir="/" name="src/core/security/json_token.h" role="src" />
-    <file baseinstalldir="/" name="src/core/security/jwt_verifier.h" role="src" />
-    <file baseinstalldir="/" name="src/core/security/secure_endpoint.h" role="src" />
-    <file baseinstalldir="/" name="src/core/security/security_connector.h" role="src" />
-    <file baseinstalldir="/" name="src/core/security/security_context.h" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/fake_transport_security.h" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/ssl_transport_security.h" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/ssl_types.h" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/transport_security.h" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/transport_security_interface.h" role="src" />
-    <file baseinstalldir="/" name="src/core/census/aggregation.h" role="src" />
-    <file baseinstalldir="/" name="src/core/census/mlog.h" role="src" />
-    <file baseinstalldir="/" name="src/core/census/rpc_metric_id.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/alpn.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_encoder.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_transport.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_data.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_goaway.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_ping.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_rst_stream.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_settings.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_window_update.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_encoder.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_parser.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_table.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/http2_errors.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/huffsyms.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/incoming_metadata.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/internal.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/status_conversion.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/stream_map.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/timeout_encoding.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/varint.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/aggregation.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/grpc_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/grpc_plugin.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/mlog.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/rpc_metric_id.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/channel_args.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/client_channel.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/compress_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/context.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/http_client_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/http_server_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/subchannel_call_holder.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/client_config.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/connector.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/initial_connect_string.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/lb_policies/load_balancer_api.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/lb_policies/pick_first.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/lb_policies/round_robin.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/lb_policy.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/lb_policy_factory.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/lb_policy_registry.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/resolver.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/resolver_factory.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/resolver_registry.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/resolvers/dns_resolver.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/resolvers/sockaddr_resolver.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/subchannel.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/subchannel_factory.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/subchannel_index.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/uri_parser.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/compression/algorithm_metadata.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/compression/message_compress.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/debug/trace.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/http/format_request.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/http/httpcli.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/http/parser.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/closure.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/exec_ctx.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/executor.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/fd_posix.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/iocp_windows.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_internal.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_posix.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_posix.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set_posix.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set_windows.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_windows.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_posix.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_win32.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_posix.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/socket_windows.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_posix.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_windows.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/time_averaged_stats.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/timer.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/timer_heap.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/udp_server.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/unix_sockets_posix.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/wakeup_fd_pipe.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/wakeup_fd_posix.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/workqueue.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/workqueue_posix.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/workqueue_windows.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/json/json.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/json/json_common.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/json/json_reader.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/json/json_writer.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/auth_filters.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/b64.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/handshake.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/json_token.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/jwt_verifier.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/secure_endpoint.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/security_connector.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/security_context.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/statistics/census_interface.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/statistics/census_rpc_stats.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/api_trace.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/call.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/call_test_only.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/channel.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/channel_init.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/channel_stack_type.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/completion_queue.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/event_string.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/init.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/lame_client.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/server.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/surface_trace.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/byte_stream.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/connectivity_state.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/metadata.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/static_metadata.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/transport.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/transport_impl.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/tsi/fake_transport_security.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/tsi/ssl_transport_security.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/tsi/ssl_types.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/tsi/transport_security.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/tsi/transport_security_interface.h" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb.h" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_common.h" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_decode.h" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_encode.h" role="src" />
-    <file baseinstalldir="/" name="src/core/census/grpc_context.c" role="src" />
-    <file baseinstalldir="/" name="src/core/census/grpc_filter.c" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/channel_args.c" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/channel_stack.c" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/client_channel.c" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/client_uchannel.c" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/compress_filter.c" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/connected_channel.c" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/http_client_filter.c" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/http_server_filter.c" role="src" />
-    <file baseinstalldir="/" name="src/core/channel/subchannel_call_holder.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/client_config.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/connector.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/default_initial_connect_string.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/initial_connect_string.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/lb_policies/load_balancer_api.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/lb_policies/pick_first.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/lb_policies/round_robin.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/lb_policy.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/lb_policy_factory.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/lb_policy_registry.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/resolver.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/resolver_factory.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/resolver_registry.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/resolvers/dns_resolver.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/resolvers/sockaddr_resolver.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/subchannel.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/subchannel_factory.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/subchannel_index.c" role="src" />
-    <file baseinstalldir="/" name="src/core/client_config/uri_parser.c" role="src" />
-    <file baseinstalldir="/" name="src/core/compression/compression_algorithm.c" role="src" />
-    <file baseinstalldir="/" name="src/core/compression/message_compress.c" role="src" />
-    <file baseinstalldir="/" name="src/core/debug/trace.c" role="src" />
-    <file baseinstalldir="/" name="src/core/httpcli/format_request.c" role="src" />
-    <file baseinstalldir="/" name="src/core/httpcli/httpcli.c" role="src" />
-    <file baseinstalldir="/" name="src/core/httpcli/parser.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/closure.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/endpoint.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/endpoint_pair_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/endpoint_pair_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/exec_ctx.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/executor.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/fd_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/iocp_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/iomgr.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/iomgr_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/iomgr_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/pollset_multipoller_with_epoll.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/pollset_multipoller_with_poll_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/pollset_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/pollset_set_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/pollset_set_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/pollset_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/resolve_address_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/resolve_address_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/sockaddr_utils.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/socket_utils_common_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/socket_utils_linux.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/socket_utils_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/socket_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/tcp_client_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/tcp_client_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/tcp_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/tcp_server_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/tcp_server_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/tcp_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/time_averaged_stats.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/timer.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/timer_heap.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/udp_server.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/wakeup_fd_eventfd.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/wakeup_fd_nospecial.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/wakeup_fd_pipe.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/wakeup_fd_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/workqueue_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/iomgr/workqueue_windows.c" role="src" />
-    <file baseinstalldir="/" name="src/core/json/json.c" role="src" />
-    <file baseinstalldir="/" name="src/core/json/json_reader.c" role="src" />
-    <file baseinstalldir="/" name="src/core/json/json_string.c" role="src" />
-    <file baseinstalldir="/" name="src/core/json/json_writer.c" role="src" />
-    <file baseinstalldir="/" name="src/core/proto/grpc/lb/v0/load_balancer.pb.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/alarm.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/api_trace.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/byte_buffer.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/byte_buffer_reader.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/call.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/call_details.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/call_log_batch.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/channel.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/channel_connectivity.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/channel_create.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/channel_ping.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/completion_queue.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/event_string.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/init.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/lame_client.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/metadata_array.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/server.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/server_chttp2.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/server_create.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/validate_metadata.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/version.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/byte_stream.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/alpn.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/bin_encoder.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame_data.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame_goaway.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame_ping.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame_rst_stream.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame_settings.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/frame_window_update.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/hpack_encoder.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/hpack_parser.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/hpack_table.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/huffsyms.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/incoming_metadata.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/parsing.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/status_conversion.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/stream_lists.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/stream_map.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/timeout_encoding.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/varint.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2/writing.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/chttp2_transport.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/connectivity_state.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/metadata.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/metadata_batch.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/static_metadata.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/transport.c" role="src" />
-    <file baseinstalldir="/" name="src/core/transport/transport_op_string.c" role="src" />
-    <file baseinstalldir="/" name="src/core/httpcli/httpcli_security_connector.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/b64.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/client_auth_filter.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/credentials.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/credentials_metadata.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/credentials_posix.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/credentials_win32.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/google_default_credentials.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/handshake.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/json_token.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/jwt_verifier.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/secure_endpoint.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/security_connector.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/security_context.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/server_auth_filter.c" role="src" />
-    <file baseinstalldir="/" name="src/core/security/server_secure_chttp2.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/init_secure.c" role="src" />
-    <file baseinstalldir="/" name="src/core/surface/secure_channel_create.c" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/fake_transport_security.c" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/ssl_transport_security.c" role="src" />
-    <file baseinstalldir="/" name="src/core/tsi/transport_security.c" role="src" />
-    <file baseinstalldir="/" name="src/core/census/context.c" role="src" />
-    <file baseinstalldir="/" name="src/core/census/initialize.c" role="src" />
-    <file baseinstalldir="/" name="src/core/census/mlog.c" role="src" />
-    <file baseinstalldir="/" name="src/core/census/operation.c" role="src" />
-    <file baseinstalldir="/" name="src/core/census/placeholders.c" role="src" />
-    <file baseinstalldir="/" name="src/core/census/tracing.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/secure/secure_channel_create.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/alpn.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_encoder.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_transport.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_data.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_goaway.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_ping.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_rst_stream.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_settings.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_window_update.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_encoder.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_parser.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_table.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/huffsyms.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/incoming_metadata.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/parsing.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/status_conversion.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/stream_lists.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/stream_map.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/timeout_encoding.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/varint.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/writing.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/context.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/grpc_context.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/grpc_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/grpc_plugin.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/initialize.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/mlog.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/operation.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/placeholders.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/census/tracing.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/channel_args.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/client_channel.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/compress_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/http_client_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/http_server_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/subchannel_call_holder.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/client_config.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/connector.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/default_initial_connect_string.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/initial_connect_string.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/lb_policies/load_balancer_api.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/lb_policies/pick_first.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/lb_policies/round_robin.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/lb_policy.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/lb_policy_factory.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/lb_policy_registry.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/resolver.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/resolver_factory.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/resolver_registry.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/resolvers/dns_resolver.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/resolvers/sockaddr_resolver.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/subchannel.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/subchannel_factory.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/subchannel_index.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/client_config/uri_parser.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/compression/compression_algorithm.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/compression/message_compress.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/debug/trace.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/http/format_request.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/http/httpcli.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/http/httpcli_security_connector.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/http/parser.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/closure.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/exec_ctx.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/executor.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/fd_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/iocp_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_multipoller_with_epoll.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/resolve_address_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_common_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_linux.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/socket_utils_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/socket_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_client_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_server_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/tcp_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/time_averaged_stats.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/timer.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/timer_heap.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/udp_server.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/unix_sockets_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/unix_sockets_posix_noop.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/wakeup_fd_eventfd.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/wakeup_fd_nospecial.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/wakeup_fd_pipe.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/wakeup_fd_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/workqueue_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/workqueue_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/json/json.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/json/json_reader.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/json/json_string.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/json/json_writer.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/b64.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/client_auth_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials_metadata.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/credentials_win32.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/google_default_credentials.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/handshake.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/json_token.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/jwt_verifier.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/secure_endpoint.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/security_connector.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/security_context.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/security/server_auth_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/alarm.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/api_trace.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/byte_buffer.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/byte_buffer_reader.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/call.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/call_details.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/call_log_batch.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/channel.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/channel_connectivity.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/channel_init.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/channel_ping.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/channel_stack_type.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/completion_queue.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/event_string.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/init.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/init_secure.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/lame_client.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/metadata_array.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/server.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/validate_metadata.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/surface/version.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/byte_stream.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/connectivity_state.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/metadata.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/static_metadata.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/transport.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/transport_op_string.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/tsi/fake_transport_security.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/tsi/ssl_transport_security.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/tsi/transport_security.c" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_common.c" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_decode.c" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_encode.c" role="src" />
diff --git a/setup.py b/setup.py
index 45ff2ce..9634de0 100644
--- a/setup.py
+++ b/setup.py
@@ -42,6 +42,7 @@
 # Redirect the manifest template from MANIFEST.in to PYTHON-MANIFEST.in.
 egg_info.manifest_maker.template = 'PYTHON-MANIFEST.in'
 
+PY3 = sys.version_info.major == 3
 PYTHON_STEM = './src/python/grpcio'
 CORE_INCLUDE = ('./include', '.',)
 BORINGSSL_INCLUDE = ('./third_party/boringssl/include',)
@@ -103,10 +104,14 @@
   LDFLAGS += ('-Wl,-wrap,memcpy',)
 if "linux" in sys.platform or "darwin" in sys.platform:
   CFLAGS += ('-fvisibility=hidden',)
-  DEFINE_MACROS += (('PyMODINIT_FUNC', '__attribute__((visibility ("default"))) void'),)
+
+  pymodinit_type = 'PyObject*' if PY3 else 'void'
+
+  pymodinit = '__attribute__((visibility ("default"))) {}'.format(pymodinit_type)
+  DEFINE_MACROS += (('PyMODINIT_FUNC', pymodinit),)
 
 
-def cython_extensions(package_names, module_names, extra_sources, include_dirs,
+def cython_extensions(module_names, extra_sources, include_dirs,
                       libraries, define_macros, build_with_cython=False):
   # Set compiler directives linetrace argument only if we care about tracing;
   # this is due to Cython having different behavior between linetrace being
@@ -139,7 +144,7 @@
     return extensions
 
 CYTHON_EXTENSION_MODULES = cython_extensions(
-    list(CYTHON_EXTENSION_PACKAGE_NAMES), list(CYTHON_EXTENSION_MODULE_NAMES),
+    list(CYTHON_EXTENSION_MODULE_NAMES),
     list(CYTHON_HELPER_C_FILES) + list(CORE_C_FILES),
     list(EXTENSION_INCLUDE_DIRECTORIES), list(EXTENSION_LIBRARIES),
     list(DEFINE_MACROS), bool(BUILD_WITH_CYTHON))
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 97295be..206a6e1 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -83,6 +83,28 @@
 }
 }  // namespace
 
+template<class T, size_t N>
+T *array_end(T (&array)[N]) { return array + N; }
+
+void PrintIncludes(grpc::protobuf::io::Printer *printer, const std::vector<grpc::string>& headers, const Parameters &params) {
+  std::map<grpc::string, grpc::string> vars;
+
+  vars["l"] = params.use_system_headers ? '<' : '"';
+  vars["r"] = params.use_system_headers ? '>' : '"';
+
+  if (!params.grpc_search_path.empty()) {
+    vars["l"] += params.grpc_search_path;
+    if (params.grpc_search_path.back() != '/') {
+      vars["l"] += '/';
+    }
+  }
+
+  for (auto i = headers.begin(); i != headers.end(); i++) {
+    vars["h"] = *i;
+    printer->Print(vars, "#include $l$$h$$r$\n");
+  }
+}
+
 grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file,
                                const Parameters &params) {
   grpc::string output;
@@ -111,36 +133,46 @@
 
 grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
                                const Parameters &params) {
-  grpc::string temp =
-      "#include <grpc++/impl/codegen/async_stream.h>\n"
-      "#include <grpc++/impl/codegen/async_unary_call.h>\n"
-      "#include <grpc++/impl/codegen/proto_utils.h>\n"
-      "#include <grpc++/impl/codegen/rpc_method.h>\n"
-      "#include <grpc++/impl/codegen/service_type.h>\n"
-      "#include <grpc++/impl/codegen/status.h>\n"
-      "#include <grpc++/impl/codegen/stub_options.h>\n"
-      "#include <grpc++/impl/codegen/sync_stream.h>\n"
-      "\n"
-      "namespace grpc {\n"
-      "class CompletionQueue;\n"
-      "class RpcService;\n"
-      "class ServerCompletionQueue;\n"
-      "class ServerContext;\n"
-      "}  // namespace grpc\n\n";
+  grpc::string output;
+  {
+    // 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;
 
-  if (!file->package().empty()) {
-    std::vector<grpc::string> parts =
-        grpc_generator::tokenize(file->package(), ".");
+    static const char *headers_strs[] = {
+      "grpc++/impl/codegen/async_stream.h",
+      "grpc++/impl/codegen/async_unary_call.h",
+      "grpc++/impl/codegen/proto_utils.h",
+      "grpc++/impl/codegen/rpc_method.h",
+      "grpc++/impl/codegen/service_type.h",
+      "grpc++/impl/codegen/status.h",
+      "grpc++/impl/codegen/stub_options.h",
+      "grpc++/impl/codegen/sync_stream.h"
+    };
+    std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
+    PrintIncludes(&printer, headers, params);
+    printer.Print(vars, "\n");
+    printer.Print(vars, "namespace grpc {\n");
+    printer.Print(vars, "class CompletionQueue;\n");
+    printer.Print(vars, "class Channel;\n");
+    printer.Print(vars, "class RpcService;\n");
+    printer.Print(vars, "class ServerCompletionQueue;\n");
+    printer.Print(vars, "class ServerContext;\n");
+    printer.Print(vars, "}  // namespace grpc\n\n");
 
-    for (auto part = parts.begin(); part != parts.end(); part++) {
-      temp.append("namespace ");
-      temp.append(*part);
-      temp.append(" {\n");
+    if (!file->package().empty()) {
+      std::vector<grpc::string> parts =
+          grpc_generator::tokenize(file->package(), ".");
+
+      for (auto part = parts.begin(); part != parts.end(); part++) {
+        vars["part"] = *part;
+        printer.Print(vars, "namespace $part$ {\n");
+      }
+      printer.Print(vars, "\n");
     }
-    temp.append("\n");
   }
-
-  return temp;
+  return output;
 }
 
 void PrintHeaderClientMethodInterfaces(
@@ -852,7 +884,7 @@
 }
 
 grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file,
-                               const Parameters &param) {
+                               const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -860,16 +892,18 @@
     grpc::protobuf::io::Printer printer(&output_stream, '$');
     std::map<grpc::string, grpc::string> vars;
 
-    printer.Print(vars, "#include <grpc++/impl/codegen/async_stream.h>\n");
-    printer.Print(vars, "#include <grpc++/impl/codegen/async_unary_call.h>\n");
-    printer.Print(vars, "#include <grpc++/impl/codegen/channel_interface.h>\n");
-    printer.Print(vars, "#include <grpc++/impl/codegen/client_unary_call.h>\n");
-    printer.Print(vars,
-                  "#include <grpc++/impl/codegen/method_handler_impl.h>\n");
-    printer.Print(vars,
-                  "#include <grpc++/impl/codegen/rpc_service_method.h>\n");
-    printer.Print(vars, "#include <grpc++/impl/codegen/service_type.h>\n");
-    printer.Print(vars, "#include <grpc++/impl/codegen/sync_stream.h>\n");
+    static const char *headers_strs[] = {
+      "grpc++/impl/codegen/async_stream.h",
+      "grpc++/impl/codegen/async_unary_call.h",
+      "grpc++/impl/codegen/channel_interface.h",
+      "grpc++/impl/codegen/client_unary_call.h",
+      "grpc++/impl/codegen/method_handler_impl.h",
+      "grpc++/impl/codegen/rpc_service_method.h",
+      "grpc++/impl/codegen/service_type.h",
+      "grpc++/impl/codegen/sync_stream.h"
+    };
+    std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
+    PrintIncludes(&printer, headers, params);
 
     if (!file->package().empty()) {
       std::vector<grpc::string> parts =
diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h
index 70c2e98..4f9de9d 100644
--- a/src/compiler/cpp_generator.h
+++ b/src/compiler/cpp_generator.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,10 @@
 struct Parameters {
   // Puts the service into a namespace
   grpc::string services_namespace;
+  // Use system includes (<>) or local includes ("")
+  bool use_system_headers;
+  // Prefix to any grpc include
+  grpc::string grpc_search_path;
 };
 
 // Return the prologue of the generated header file.
diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc
index 88c7049..d8ada48 100644
--- a/src/compiler/cpp_plugin.cc
+++ b/src/compiler/cpp_plugin.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -59,6 +59,7 @@
     }
 
     grpc_cpp_generator::Parameters generator_parameters;
+    generator_parameters.use_system_headers = true;
 
     if (!parameter.empty()) {
       std::vector<grpc::string> parameters_list =
@@ -70,6 +71,17 @@
           grpc_generator::tokenize(*parameter_string, "=");
         if (param[0] == "services_namespace") {
           generator_parameters.services_namespace = param[1];
+        } else if (param[0] == "use_system_headers") {
+          if (param[1] == "true") {
+            generator_parameters.use_system_headers = true;
+          } else if (param[1] == "false") {
+            generator_parameters.use_system_headers = false;
+          } else {
+            *error = grpc::string("Invalid parameter: ") + *parameter_string;
+            return false;
+          }
+        } else if (param[0] == "grpc_search_path") {
+          generator_parameters.grpc_search_path = param[1];
         } else {
           *error = grpc::string("Unknown parameter: ") + *parameter_string;
           return false;
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index 4fd5dfb..5a2ecce 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -190,11 +190,10 @@
         "Documentation", doc,
       });
   out->Print("\n");
-  out->Print(dict, "class Beta$Service$Servicer(object):\n");
+  out->Print(dict, "class Beta$Service$Servicer(six.with_metaclass(abc.ABCMeta, object)):\n");
   {
     IndentScope raii_class_indent(out);
     out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
-    out->Print("__metaclass__ = abc.ABCMeta\n");
     for (int i = 0; i < service->method_count(); ++i) {
       auto meth = service->method(i);
       grpc::string arg_name = meth->client_streaming() ?
@@ -219,11 +218,10 @@
         "Documentation", doc,
       });
   out->Print("\n");
-  out->Print(dict, "class Beta$Service$Stub(object):\n");
+  out->Print(dict, "class Beta$Service$Stub(six.with_metaclass(abc.ABCMeta, object)):\n");
   {
     IndentScope raii_class_indent(out);
     out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
-    out->Print("__metaclass__ = abc.ABCMeta\n");
     for (int i = 0; i < service->method_count(); ++i) {
       const MethodDescriptor* meth = service->method(i);
       grpc::string arg_name = meth->client_streaming() ?
@@ -449,6 +447,7 @@
 bool PrintPreamble(const FileDescriptor* file,
                    const GeneratorConfiguration& config, Printer* out) {
   out->Print("import abc\n");
+  out->Print("import six\n");
   out->Print("from $Package$ import implementations as beta_implementations\n",
              "Package", config.beta_package_root);
   out->Print("from grpc.framework.common import cardinality\n");
diff --git a/src/core/census/aggregation.h b/src/core/census/aggregation.h
deleted file mode 100644
index e9bc6ad..0000000
--- a/src/core/census/aggregation.h
+++ /dev/null
@@ -1,66 +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 <stddef.h>
-
-#ifndef GRPC_INTERNAL_CORE_CENSUS_AGGREGATION_H
-#define GRPC_INTERNAL_CORE_CENSUS_AGGREGATION_H
-
-/** Structure used to describe an aggregation type. */
-struct census_aggregation_ops {
-  /* Create a new aggregation. The pointer returned can be used in future calls
-     to clone(), free(), record(), data() and reset(). */
-  void *(*create)(const void *create_arg);
-  /* Make a copy of an aggregation created by create() */
-  void *(*clone)(const void *aggregation);
-  /* Destroy an aggregation created by create() */
-  void (*free)(void *aggregation);
-  /* Record a new value against aggregation. */
-  void (*record)(void *aggregation, double value);
-  /* Return current aggregation data. The caller must cast this object into
-     the correct type for the aggregation result. The object returned can be
-     freed by using free_data(). */
-  void *(*data)(const void *aggregation);
-  /* free data returned by data() */
-  void (*free_data)(void *data);
-  /* Reset an aggregation to default (zero) values. */
-  void (*reset)(void *aggregation);
-  /* Merge 'from' aggregation into 'to'. Both aggregations must be compatible */
-  void (*merge)(void *to, const void *from);
-  /* Fill buffer with printable string version of aggregation contents. For
-     debugging only. Returns the number of bytes added to buffer (a value == n
-     implies the buffer was of insufficient size). */
-  size_t (*print)(const void *aggregation, char *buffer, size_t n);
-};
-
-#endif /* GRPC_INTERNAL_CORE_CENSUS_AGGREGATION_H */
diff --git a/src/core/census/context.c b/src/core/census/context.c
deleted file mode 100644
index 89b8ee0..0000000
--- a/src/core/census/context.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/census.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/useful.h>
-#include <stdbool.h>
-#include <string.h>
-#include "src/core/support/string.h"
-
-// Functions in this file support the public context API, including
-// encoding/decoding as part of context propagation across RPC's. The overall
-// requirements (in approximate priority order) for the
-// context representation:
-// 1. Efficient conversion to/from wire format
-// 2. Minimal bytes used on-wire
-// 3. Efficient context creation
-// 4. Efficient lookup of tag value for a key
-// 5. Efficient iteration over tags
-// 6. Minimal memory footprint
-//
-// Notes on tradeoffs/decisions:
-// * tag includes 1 byte length of key, as well as nil-terminating byte. These
-//   are to aid in efficient parsing and the ability to directly return key
-//   strings. This is more important than saving a single byte/tag on the wire.
-// * The wire encoding uses only single byte values. This eliminates the need
-//   to handle endian-ness conversions. It also means there is a hard upper
-//   limit of 255 for both CENSUS_MAX_TAG_KV_LEN and CENSUS_MAX_PROPAGATED_TAGS.
-// * Keep all tag information (keys/values/flags) in a single memory buffer,
-//   that can be directly copied to the wire.
-
-// min and max valid chars in tag keys and values. All printable ASCII is OK.
-#define MIN_VALID_TAG_CHAR 32   // ' '
-#define MAX_VALID_TAG_CHAR 126  // '~'
-
-// Structure representing a set of tags. Essentially a count of number of tags
-// present, and pointer to a chunk of memory that contains the per-tag details.
-struct tag_set {
-  int ntags;        // number of tags.
-  int ntags_alloc;  // ntags + number of deleted tags (total number of tags
-  // in all of kvm). This will always be == ntags, except during the process
-  // of building a new tag set.
-  size_t kvm_size;  // number of bytes allocated for key/value storage.
-  size_t kvm_used;  // number of bytes of used key/value memory
-  char *kvm;        // key/value memory. Consists of repeated entries of:
-  //   Offset  Size  Description
-  //     0      1    Key length, including trailing 0. (K)
-  //     1      1    Value length, including trailing 0 (V)
-  //     2      1    Flags
-  //     3      K    Key bytes
-  //     3 + K  V    Value bytes
-  //
-  // We refer to the first 3 entries as the 'tag header'. If extra values are
-  // introduced in the header, you will need to modify the TAG_HEADER_SIZE
-  // constant, the raw_tag structure (and everything that uses it) and the
-  // encode/decode functions appropriately.
-};
-
-// Number of bytes in tag header.
-#define TAG_HEADER_SIZE 3  // key length (1) + value length (1) + flags (1)
-// Offsets to tag header entries.
-#define KEY_LEN_OFFSET 0
-#define VALUE_LEN_OFFSET 1
-#define FLAG_OFFSET 2
-
-// raw_tag represents the raw-storage form of a tag in the kvm of a tag_set.
-struct raw_tag {
-  uint8_t key_len;
-  uint8_t value_len;
-  uint8_t flags;
-  char *key;
-  char *value;
-};
-
-// Use a reserved flag bit for indication of deleted tag.
-#define CENSUS_TAG_DELETED CENSUS_TAG_RESERVED
-#define CENSUS_TAG_IS_DELETED(flags) (flags & CENSUS_TAG_DELETED)
-
-// Primary representation of a context. Composed of 2 underlying tag_set
-// structs, one each for propagated and local (non-propagated) tags. This is
-// to efficiently support tag encoding/decoding.
-// TODO(aveitch): need to add tracing id's/structure.
-struct census_context {
-  struct tag_set tags[2];
-  census_context_status status;
-};
-
-// Indices into the tags member of census_context
-#define PROPAGATED_TAGS 0
-#define LOCAL_TAGS 1
-
-// Validate (check all characters are in range and size is less than limit) a
-// key or value string. Returns 0 if the string is invalid, or the length
-// (including terminator) if valid.
-static size_t validate_tag(const char *kv) {
-  size_t len = 1;
-  char ch;
-  while ((ch = *kv++) != 0) {
-    if (ch < MIN_VALID_TAG_CHAR || ch > MAX_VALID_TAG_CHAR) {
-      return 0;
-    }
-    len++;
-  }
-  if (len > CENSUS_MAX_TAG_KV_LEN) {
-    return 0;
-  }
-  return len;
-}
-
-// Extract a raw tag given a pointer (raw) to the tag header. Allow for some
-// extra bytes in the tag header (see encode/decode functions for usage: this
-// allows for future expansion of the tag header).
-static char *decode_tag(struct raw_tag *tag, char *header, int offset) {
-  tag->key_len = (uint8_t)(*header++);
-  tag->value_len = (uint8_t)(*header++);
-  tag->flags = (uint8_t)(*header++);
-  header += offset;
-  tag->key = header;
-  header += tag->key_len;
-  tag->value = header;
-  return header + tag->value_len;
-}
-
-// Make a copy (in 'to') of an existing tag_set.
-static void tag_set_copy(struct tag_set *to, const struct tag_set *from) {
-  memcpy(to, from, sizeof(struct tag_set));
-  to->kvm = gpr_malloc(to->kvm_size);
-  memcpy(to->kvm, from->kvm, from->kvm_used);
-}
-
-// Delete a tag from a tag_set, if it exists (returns true if it did).
-static bool tag_set_delete_tag(struct tag_set *tags, const char *key,
-                               size_t key_len) {
-  char *kvp = tags->kvm;
-  for (int i = 0; i < tags->ntags_alloc; i++) {
-    uint8_t *flags = (uint8_t *)(kvp + FLAG_OFFSET);
-    struct raw_tag tag;
-    kvp = decode_tag(&tag, kvp, 0);
-    if (CENSUS_TAG_IS_DELETED(tag.flags)) continue;
-    if ((key_len == tag.key_len) && (memcmp(key, tag.key, key_len) == 0)) {
-      *flags |= CENSUS_TAG_DELETED;
-      tags->ntags--;
-      return true;
-    }
-  }
-  return false;
-}
-
-// Delete a tag from a context, return true if it existed.
-static bool context_delete_tag(census_context *context, const census_tag *tag,
-                               size_t key_len) {
-  return (
-      tag_set_delete_tag(&context->tags[LOCAL_TAGS], tag->key, key_len) ||
-      tag_set_delete_tag(&context->tags[PROPAGATED_TAGS], tag->key, key_len));
-}
-
-// Add a tag to a tag_set. Return true on success, false if the tag could
-// not be added because of constraints on tag set size. This function should
-// not be called if the tag may already exist (in a non-deleted state) in
-// the tag_set, as that would result in two tags with the same key.
-static bool tag_set_add_tag(struct tag_set *tags, const census_tag *tag,
-                            size_t key_len, size_t value_len) {
-  if (tags->ntags == CENSUS_MAX_PROPAGATED_TAGS) {
-    return false;
-  }
-  const size_t tag_size = key_len + value_len + TAG_HEADER_SIZE;
-  if (tags->kvm_used + tag_size > tags->kvm_size) {
-    // allocate new memory if needed
-    tags->kvm_size += 2 * CENSUS_MAX_TAG_KV_LEN + TAG_HEADER_SIZE;
-    char *new_kvm = gpr_malloc(tags->kvm_size);
-    memcpy(new_kvm, tags->kvm, tags->kvm_used);
-    gpr_free(tags->kvm);
-    tags->kvm = new_kvm;
-  }
-  char *kvp = tags->kvm + tags->kvm_used;
-  *kvp++ = (char)key_len;
-  *kvp++ = (char)value_len;
-  // ensure reserved flags are not used.
-  *kvp++ = (char)(tag->flags & (CENSUS_TAG_PROPAGATE | CENSUS_TAG_STATS));
-  memcpy(kvp, tag->key, key_len);
-  kvp += key_len;
-  memcpy(kvp, tag->value, value_len);
-  tags->kvm_used += tag_size;
-  tags->ntags++;
-  tags->ntags_alloc++;
-  return true;
-}
-
-// Add/modify/delete a tag to/in a context. Caller must validate that tag key
-// etc. are valid.
-static void context_modify_tag(census_context *context, const census_tag *tag,
-                               size_t key_len, size_t value_len) {
-  // First delete the tag if it is already present.
-  bool deleted = context_delete_tag(context, tag, key_len);
-  bool added = false;
-  if (CENSUS_TAG_IS_PROPAGATED(tag->flags)) {
-    added = tag_set_add_tag(&context->tags[PROPAGATED_TAGS], tag, key_len,
-                            value_len);
-  } else {
-    added =
-        tag_set_add_tag(&context->tags[LOCAL_TAGS], tag, key_len, value_len);
-  }
-
-  if (deleted) {
-    context->status.n_modified_tags++;
-  } else {
-    if (added) {
-      context->status.n_added_tags++;
-    } else {
-      context->status.n_ignored_tags++;
-    }
-  }
-}
-
-// Remove memory used for deleted tags from a tag set. Basic algorithm:
-// 1) Walk through tag set to find first deleted tag. Record where it is.
-// 2) Find the next not-deleted tag. Copy all of kvm from there to the end
-//    "over" the deleted tags
-// 3) repeat #1 and #2 until we have seen all tags
-// 4) if we are still looking for a not-deleted tag, then all the end portion
-//    of the kvm is deleted. Just reduce the used amount of memory by the
-//    appropriate amount.
-static void tag_set_flatten(struct tag_set *tags) {
-  if (tags->ntags == tags->ntags_alloc) return;
-  bool found_deleted = false;  // found a deleted tag.
-  char *kvp = tags->kvm;
-  char *dbase = NULL;  // record location of deleted tag
-  for (int i = 0; i < tags->ntags_alloc; i++) {
-    struct raw_tag tag;
-    char *next_kvp = decode_tag(&tag, kvp, 0);
-    if (found_deleted) {
-      if (!CENSUS_TAG_IS_DELETED(tag.flags)) {
-        ptrdiff_t reduce = kvp - dbase;  // #bytes in deleted tags
-        GPR_ASSERT(reduce > 0);
-        ptrdiff_t copy_size = tags->kvm + tags->kvm_used - kvp;
-        GPR_ASSERT(copy_size > 0);
-        memmove(dbase, kvp, (size_t)copy_size);
-        tags->kvm_used -= (size_t)reduce;
-        next_kvp -= reduce;
-        found_deleted = false;
-      }
-    } else {
-      if (CENSUS_TAG_IS_DELETED(tag.flags)) {
-        dbase = kvp;
-        found_deleted = true;
-      }
-    }
-    kvp = next_kvp;
-  }
-  if (found_deleted) {
-    GPR_ASSERT(dbase > tags->kvm);
-    tags->kvm_used = (size_t)(dbase - tags->kvm);
-  }
-  tags->ntags_alloc = tags->ntags;
-}
-
-census_context *census_context_create(const census_context *base,
-                                      const census_tag *tags, int ntags,
-                                      census_context_status const **status) {
-  census_context *context = gpr_malloc(sizeof(census_context));
-  // If we are given a base, copy it into our new tag set. Otherwise set it
-  // to zero/NULL everything.
-  if (base == NULL) {
-    memset(context, 0, sizeof(census_context));
-  } else {
-    tag_set_copy(&context->tags[PROPAGATED_TAGS], &base->tags[PROPAGATED_TAGS]);
-    tag_set_copy(&context->tags[LOCAL_TAGS], &base->tags[LOCAL_TAGS]);
-    memset(&context->status, 0, sizeof(context->status));
-  }
-  // Walk over the additional tags and, for those that aren't invalid, modify
-  // the context to add/replace/delete as required.
-  for (int i = 0; i < ntags; i++) {
-    const census_tag *tag = &tags[i];
-    size_t key_len = validate_tag(tag->key);
-    // ignore the tag if it is invalid or too short.
-    if (key_len <= 1) {
-      context->status.n_invalid_tags++;
-    } else {
-      if (tag->value != NULL) {
-        size_t value_len = validate_tag(tag->value);
-        if (value_len != 0) {
-          context_modify_tag(context, tag, key_len, value_len);
-        } else {
-          context->status.n_invalid_tags++;
-        }
-      } else {
-        if (context_delete_tag(context, tag, key_len)) {
-          context->status.n_deleted_tags++;
-        }
-      }
-    }
-  }
-  // Remove any deleted tags, update status if needed, and return.
-  tag_set_flatten(&context->tags[PROPAGATED_TAGS]);
-  tag_set_flatten(&context->tags[LOCAL_TAGS]);
-  context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags;
-  context->status.n_local_tags = context->tags[LOCAL_TAGS].ntags;
-  if (status) {
-    *status = &context->status;
-  }
-  return context;
-}
-
-const census_context_status *census_context_get_status(
-    const census_context *context) {
-  return &context->status;
-}
-
-void census_context_destroy(census_context *context) {
-  gpr_free(context->tags[PROPAGATED_TAGS].kvm);
-  gpr_free(context->tags[LOCAL_TAGS].kvm);
-  gpr_free(context);
-}
-
-void census_context_initialize_iterator(const census_context *context,
-                                        census_context_iterator *iterator) {
-  iterator->context = context;
-  iterator->index = 0;
-  if (context->tags[PROPAGATED_TAGS].ntags != 0) {
-    iterator->base = PROPAGATED_TAGS;
-    iterator->kvm = context->tags[PROPAGATED_TAGS].kvm;
-  } else if (context->tags[LOCAL_TAGS].ntags != 0) {
-    iterator->base = LOCAL_TAGS;
-    iterator->kvm = context->tags[LOCAL_TAGS].kvm;
-  } else {
-    iterator->base = -1;
-  }
-}
-
-int census_context_next_tag(census_context_iterator *iterator,
-                            census_tag *tag) {
-  if (iterator->base < 0) {
-    return 0;
-  }
-  struct raw_tag raw;
-  iterator->kvm = decode_tag(&raw, iterator->kvm, 0);
-  tag->key = raw.key;
-  tag->value = raw.value;
-  tag->flags = raw.flags;
-  if (++iterator->index == iterator->context->tags[iterator->base].ntags) {
-    do {
-      if (iterator->base == LOCAL_TAGS) {
-        iterator->base = -1;
-        return 1;
-      }
-    } while (iterator->context->tags[++iterator->base].ntags == 0);
-    iterator->index = 0;
-    iterator->kvm = iterator->context->tags[iterator->base].kvm;
-  }
-  return 1;
-}
-
-// Find a tag in a tag_set by key. Return true if found, false otherwise.
-static bool tag_set_get_tag(const struct tag_set *tags, const char *key,
-                            size_t key_len, census_tag *tag) {
-  char *kvp = tags->kvm;
-  for (int i = 0; i < tags->ntags; i++) {
-    struct raw_tag raw;
-    kvp = decode_tag(&raw, kvp, 0);
-    if (key_len == raw.key_len && memcmp(raw.key, key, key_len) == 0) {
-      tag->key = raw.key;
-      tag->value = raw.value;
-      tag->flags = raw.flags;
-      return true;
-    }
-  }
-  return false;
-}
-
-int census_context_get_tag(const census_context *context, const char *key,
-                           census_tag *tag) {
-  size_t key_len = strlen(key) + 1;
-  if (key_len == 1) {
-    return 0;
-  }
-  if (tag_set_get_tag(&context->tags[PROPAGATED_TAGS], key, key_len, tag) ||
-      tag_set_get_tag(&context->tags[LOCAL_TAGS], key, key_len, tag)) {
-    return 1;
-  }
-  return 0;
-}
-
-// Context encoding and decoding functions.
-//
-// Wire format for tag_set's on the wire:
-//
-// First, a tag set header:
-//
-// offset   bytes  description
-//   0        1    version number
-//   1        1    number of bytes in this header. This allows for future
-//                 expansion.
-//   2        1    number of bytes in each tag header.
-//   3        1    ntags value from tag set.
-//
-//   This is followed by the key/value memory from struct tag_set.
-
-#define ENCODED_VERSION 0      // Version number
-#define ENCODED_HEADER_SIZE 4  // size of tag set header
-
-// Encode a tag set. Returns 0 if buffer is too small.
-static size_t tag_set_encode(const struct tag_set *tags, char *buffer,
-                             size_t buf_size) {
-  if (buf_size < ENCODED_HEADER_SIZE + tags->kvm_used) {
-    return 0;
-  }
-  buf_size -= ENCODED_HEADER_SIZE;
-  *buffer++ = (char)ENCODED_VERSION;
-  *buffer++ = (char)ENCODED_HEADER_SIZE;
-  *buffer++ = (char)TAG_HEADER_SIZE;
-  *buffer++ = (char)tags->ntags;
-  if (tags->ntags == 0) {
-    return ENCODED_HEADER_SIZE;
-  }
-  memcpy(buffer, tags->kvm, tags->kvm_used);
-  return ENCODED_HEADER_SIZE + tags->kvm_used;
-}
-
-size_t census_context_encode(const census_context *context, char *buffer,
-                             size_t buf_size) {
-  return tag_set_encode(&context->tags[PROPAGATED_TAGS], buffer, buf_size);
-}
-
-// Decode a tag set.
-static void tag_set_decode(struct tag_set *tags, const char *buffer,
-                           size_t size) {
-  uint8_t version = (uint8_t)(*buffer++);
-  uint8_t header_size = (uint8_t)(*buffer++);
-  uint8_t tag_header_size = (uint8_t)(*buffer++);
-  tags->ntags = tags->ntags_alloc = (int)(*buffer++);
-  if (tags->ntags == 0) {
-    tags->ntags_alloc = 0;
-    tags->kvm_size = 0;
-    tags->kvm_used = 0;
-    tags->kvm = NULL;
-    return;
-  }
-  if (header_size != ENCODED_HEADER_SIZE) {
-    GPR_ASSERT(version != ENCODED_VERSION);
-    GPR_ASSERT(ENCODED_HEADER_SIZE < header_size);
-    buffer += (header_size - ENCODED_HEADER_SIZE);
-  }
-  tags->kvm_used = size - header_size;
-  tags->kvm_size = tags->kvm_used + CENSUS_MAX_TAG_KV_LEN;
-  tags->kvm = gpr_malloc(tags->kvm_size);
-  if (tag_header_size != TAG_HEADER_SIZE) {
-    // something new in the tag information. I don't understand it, so
-    // don't copy it over.
-    GPR_ASSERT(version != ENCODED_VERSION);
-    GPR_ASSERT(tag_header_size > TAG_HEADER_SIZE);
-    char *kvp = tags->kvm;
-    for (int i = 0; i < tags->ntags; i++) {
-      memcpy(kvp, buffer, TAG_HEADER_SIZE);
-      kvp += header_size;
-      struct raw_tag raw;
-      buffer =
-          decode_tag(&raw, (char *)buffer, tag_header_size - TAG_HEADER_SIZE);
-      memcpy(kvp, raw.key, (size_t)raw.key_len + raw.value_len);
-      kvp += raw.key_len + raw.value_len;
-    }
-  } else {
-    memcpy(tags->kvm, buffer, tags->kvm_used);
-  }
-}
-
-census_context *census_context_decode(const char *buffer, size_t size) {
-  census_context *context = gpr_malloc(sizeof(census_context));
-  memset(&context->tags[LOCAL_TAGS], 0, sizeof(struct tag_set));
-  if (buffer == NULL) {
-    memset(&context->tags[PROPAGATED_TAGS], 0, sizeof(struct tag_set));
-  } else {
-    tag_set_decode(&context->tags[PROPAGATED_TAGS], buffer, size);
-  }
-  memset(&context->status, 0, sizeof(context->status));
-  context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags;
-  return context;
-}
diff --git a/src/core/census/grpc_context.c b/src/core/census/grpc_context.c
deleted file mode 100644
index 4b61382..0000000
--- a/src/core/census/grpc_context.c
+++ /dev/null
@@ -1,53 +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/census.h>
-#include <grpc/grpc.h>
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/call.h"
-
-void grpc_census_call_set_context(grpc_call *call, census_context *context) {
-  GRPC_API_TRACE("grpc_census_call_set_context(call=%p, census_context=%p)", 2,
-                 (call, context));
-  if (census_enabled() == CENSUS_FEATURE_NONE) {
-    return;
-  }
-  if (context != NULL) {
-    grpc_call_context_set(call, GRPC_CONTEXT_TRACING, context, NULL);
-  }
-}
-
-census_context *grpc_census_call_get_context(grpc_call *call) {
-  GRPC_API_TRACE("grpc_census_call_get_context(call=%p)", 1, (call));
-  return (census_context *)grpc_call_context_get(call, GRPC_CONTEXT_TRACING);
-}
diff --git a/src/core/census/grpc_filter.c b/src/core/census/grpc_filter.c
deleted file mode 100644
index c8aaf31..0000000
--- a/src/core/census/grpc_filter.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/census/grpc_filter.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include <grpc/census.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/time.h>
-
-#include "src/core/channel/channel_stack.h"
-#include "src/core/statistics/census_interface.h"
-#include "src/core/statistics/census_rpc_stats.h"
-#include "src/core/transport/static_metadata.h"
-
-typedef struct call_data {
-  census_op_id op_id;
-  census_context *ctxt;
-  gpr_timespec start_ts;
-  int error;
-
-  /* recv callback */
-  grpc_metadata_batch *recv_initial_metadata;
-  grpc_closure *on_done_recv;
-  grpc_closure finish_recv;
-} call_data;
-
-typedef struct channel_data { uint8_t unused; } channel_data;
-
-static void extract_and_annotate_method_tag(grpc_metadata_batch *md,
-                                            call_data *calld,
-                                            channel_data *chand) {
-  grpc_linked_mdelem *m;
-  for (m = md->list.head; m != NULL; m = m->next) {
-    if (m->md->key == GRPC_MDSTR_PATH) {
-      gpr_log(GPR_DEBUG, "%s",
-              (const char *)GPR_SLICE_START_PTR(m->md->value->slice));
-      /* Add method tag here */
-    }
-  }
-}
-
-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_initial_metadata) {
-    extract_and_annotate_method_tag(op->send_initial_metadata, calld, chand);
-  }
-}
-
-static void client_start_transport_op(grpc_exec_ctx *exec_ctx,
-                                      grpc_call_element *elem,
-                                      grpc_transport_stream_op *op) {
-  client_mutate_op(elem, op);
-  grpc_call_next_op(exec_ctx, elem, op);
-}
-
-static void server_on_done_recv(grpc_exec_ctx *exec_ctx, void *ptr,
-                                bool success) {
-  grpc_call_element *elem = ptr;
-  call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
-  if (success) {
-    extract_and_annotate_method_tag(calld->recv_initial_metadata, calld, chand);
-  }
-  calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success);
-}
-
-static void server_mutate_op(grpc_call_element *elem,
-                             grpc_transport_stream_op *op) {
-  call_data *calld = elem->call_data;
-  if (op->recv_initial_metadata) {
-    /* substitute our callback for the op callback */
-    calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready = &calld->finish_recv;
-  }
-}
-
-static void server_start_transport_op(grpc_exec_ctx *exec_ctx,
-                                      grpc_call_element *elem,
-                                      grpc_transport_stream_op *op) {
-  /* TODO(ctiller): this code fails. I don't know why. I expect it's
-                    incomplete, and someone should look at it soon.
-
-  call_data *calld = elem->call_data;
-  GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); */
-  server_mutate_op(elem, op);
-  grpc_call_next_op(exec_ctx, elem, op);
-}
-
-static void client_init_call_elem(grpc_exec_ctx *exec_ctx,
-                                  grpc_call_element *elem,
-                                  grpc_call_element_args *args) {
-  call_data *d = elem->call_data;
-  GPR_ASSERT(d != NULL);
-  memset(d, 0, sizeof(*d));
-  d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
-}
-
-static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                                     grpc_call_element *elem) {
-  call_data *d = elem->call_data;
-  GPR_ASSERT(d != NULL);
-  /* TODO(hongyu): record rpc client stats and census_rpc_end_op here */
-}
-
-static void server_init_call_elem(grpc_exec_ctx *exec_ctx,
-                                  grpc_call_element *elem,
-                                  grpc_call_element_args *args) {
-  call_data *d = elem->call_data;
-  GPR_ASSERT(d != NULL);
-  memset(d, 0, sizeof(*d));
-  d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
-  /* TODO(hongyu): call census_tracing_start_op here. */
-  grpc_closure_init(&d->finish_recv, server_on_done_recv, elem);
-}
-
-static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                                     grpc_call_element *elem) {
-  call_data *d = elem->call_data;
-  GPR_ASSERT(d != NULL);
-  /* TODO(hongyu): record rpc server stats and census_tracing_end_op here */
-}
-
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
-  channel_data *chand = elem->channel_data;
-  GPR_ASSERT(chand != NULL);
-}
-
-static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem) {
-  channel_data *chand = elem->channel_data;
-  GPR_ASSERT(chand != NULL);
-}
-
-const grpc_channel_filter grpc_client_census_filter = {
-    client_start_transport_op, grpc_channel_next_op, sizeof(call_data),
-    client_init_call_elem, grpc_call_stack_ignore_set_pollset,
-    client_destroy_call_elem, sizeof(channel_data), init_channel_elem,
-    destroy_channel_elem, grpc_call_next_get_peer, "census-client"};
-
-const grpc_channel_filter grpc_server_census_filter = {
-    server_start_transport_op, grpc_channel_next_op, sizeof(call_data),
-    server_init_call_elem, grpc_call_stack_ignore_set_pollset,
-    server_destroy_call_elem, sizeof(channel_data), init_channel_elem,
-    destroy_channel_elem, grpc_call_next_get_peer, "census-server"};
diff --git a/src/core/census/grpc_filter.h b/src/core/census/grpc_filter.h
deleted file mode 100644
index b3de3ad..0000000
--- a/src/core/census/grpc_filter.h
+++ /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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H
-#define GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H
-
-#include "src/core/channel/channel_stack.h"
-
-/* Census filters: provides tracing and stats collection functionalities. It
-   needs to reside right below the surface filter in the channel stack. */
-extern const grpc_channel_filter grpc_client_census_filter;
-extern const grpc_channel_filter grpc_server_census_filter;
-
-#endif /* GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H */
diff --git a/src/core/census/mlog.c b/src/core/census/mlog.c
deleted file mode 100644
index a2cc46d..0000000
--- a/src/core/census/mlog.c
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-// Implements an efficient in-memory log, optimized for multiple writers and
-// a single reader. Available log space is divided up in blocks of
-// CENSUS_LOG_2_MAX_RECORD_SIZE bytes. A block can be in one of the following
-// three data structures:
-// - Free blocks (free_block_list)
-// - Blocks with unread data (dirty_block_list)
-// - Blocks currently attached to cores (core_local_blocks[])
-//
-// census_log_start_write() moves a block from core_local_blocks[] to the end of
-// dirty_block_list when block:
-// - is out-of-space OR
-// - has an incomplete record (an incomplete record occurs when a thread calls
-//   census_log_start_write() and is context-switched before calling
-//   census_log_end_write()
-// So, blocks in dirty_block_list are ordered, from oldest to newest, by the
-// time when block is detached from the core.
-//
-// census_log_read_next() first iterates over dirty_block_list and then
-// core_local_blocks[]. It moves completely read blocks from dirty_block_list
-// to free_block_list. Blocks in core_local_blocks[] are not freed, even when
-// completely read.
-//
-// If the log is configured to discard old records and free_block_list is empty,
-// census_log_start_write() iterates over dirty_block_list to allocate a
-// new block. It moves the oldest available block (no pending read/write) to
-// core_local_blocks[].
-//
-// core_local_block_struct is used to implement a map from core id to the block
-// associated with that core. This mapping is advisory. It is possible that the
-// block returned by this mapping is no longer associated with that core. This
-// mapping is updated, lazily, by census_log_start_write().
-//
-// Locking in block struct:
-//
-// Exclusive g_log.lock must be held before calling any functions operating on
-// block structs except census_log_start_write() and census_log_end_write().
-//
-// Writes to a block are serialized via writer_lock. census_log_start_write()
-// acquires this lock and census_log_end_write() releases it. On failure to
-// acquire the lock, writer allocates a new block for the current core and
-// updates core_local_block accordingly.
-//
-// Simultaneous read and write access is allowed. Readers can safely read up to
-// committed bytes (bytes_committed).
-//
-// reader_lock protects the block, currently being read, from getting recycled.
-// start_read() acquires reader_lock and end_read() releases the lock.
-//
-// Read/write access to a block is disabled via try_disable_access(). It returns
-// with both writer_lock and reader_lock held. These locks are subsequently
-// released by enable_access() to enable access to the block.
-//
-// A note on naming: Most function/struct names are prepended by cl_
-// (shorthand for census_log). Further, functions that manipulate structures
-// include the name of the structure, which will be passed as the first
-// argument. E.g. cl_block_initialize() will initialize a cl_block.
-
-#include "src/core/census/mlog.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/atm.h>
-#include <grpc/support/cpu.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
-#include <stdbool.h>
-#include <string.h>
-
-// End of platform specific code
-
-typedef struct census_log_block_list_struct {
-  struct census_log_block_list_struct* next;
-  struct census_log_block_list_struct* prev;
-  struct census_log_block* block;
-} cl_block_list_struct;
-
-typedef struct census_log_block {
-  // Pointer to underlying buffer.
-  char* buffer;
-  gpr_atm writer_lock;
-  gpr_atm reader_lock;
-  // Keeps completely written bytes. Declared atomic because accessed
-  // simultaneously by reader and writer.
-  gpr_atm bytes_committed;
-  // Bytes already read.
-  size_t bytes_read;
-  // Links for list.
-  cl_block_list_struct link;
-// We want this structure to be cacheline aligned. We assume the following
-// sizes for the various parts on 32/64bit systems:
-// type                 32b size    64b size
-// char*                   4           8
-// 3x gpr_atm             12          24
-// size_t                  4           8
-// cl_block_list_struct   12          24
-// TOTAL                  32          64
-//
-// Depending on the size of our cacheline and the architecture, we
-// selectively add char buffering to this structure. The size is checked
-// via assert in census_log_initialize().
-#if defined(GPR_ARCH_64)
-#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 64)
-#else
-#if defined(GPR_ARCH_32)
-#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 32)
-#else
-#error "Unknown architecture"
-#endif
-#endif
-#if CL_BLOCK_PAD_SIZE > 0
-  char padding[CL_BLOCK_PAD_SIZE];
-#endif
-} cl_block;
-
-// A list of cl_blocks, doubly-linked through cl_block::link.
-typedef struct census_log_block_list {
-  int32_t count;            // Number of items in list.
-  cl_block_list_struct ht;  // head/tail of linked list.
-} cl_block_list;
-
-// Cacheline aligned block pointers to avoid false sharing. Block pointer must
-// be initialized via set_block(), before calling other functions
-typedef struct census_log_core_local_block {
-  gpr_atm block;
-// Ensure cachline alignment: we assume sizeof(gpr_atm) == 4 or 8
-#if defined(GPR_ARCH_64)
-#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 8)
-#else
-#if defined(GPR_ARCH_32)
-#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 4)
-#else
-#error "Unknown architecture"
-#endif
-#endif
-#if CL_CORE_LOCAL_BLOCK_PAD_SIZE > 0
-  char padding[CL_CORE_LOCAL_BLOCK_PAD_SIZE];
-#endif
-} cl_core_local_block;
-
-struct census_log {
-  int discard_old_records;
-  // Number of cores (aka hardware-contexts)
-  unsigned num_cores;
-  // number of CENSUS_LOG_2_MAX_RECORD_SIZE blocks in log
-  uint32_t num_blocks;
-  cl_block* blocks;                        // Block metadata.
-  cl_core_local_block* core_local_blocks;  // Keeps core to block mappings.
-  gpr_mu lock;
-  int initialized;  // has log been initialized?
-  // Keeps the state of the reader iterator. A value of 0 indicates that
-  // iterator has reached the end. census_log_init_reader() resets the value
-  // to num_core to restart iteration.
-  uint32_t read_iterator_state;
-  // Points to the block being read. If non-NULL, the block is locked for
-  // reading(block_being_read_->reader_lock is held).
-  cl_block* block_being_read;
-  char* buffer;
-  cl_block_list free_block_list;
-  cl_block_list dirty_block_list;
-  gpr_atm out_of_space_count;
-};
-
-// Single internal log.
-static struct census_log g_log;
-
-// Functions that operate on an atomic memory location used as a lock.
-
-// Returns non-zero if lock is acquired.
-static int cl_try_lock(gpr_atm* lock) { return gpr_atm_acq_cas(lock, 0, 1); }
-
-static void cl_unlock(gpr_atm* lock) { gpr_atm_rel_store(lock, 0); }
-
-// Functions that operate on cl_core_local_block's.
-
-static void cl_core_local_block_set_block(cl_core_local_block* clb,
-                                          cl_block* block) {
-  gpr_atm_rel_store(&clb->block, (gpr_atm)block);
-}
-
-static cl_block* cl_core_local_block_get_block(cl_core_local_block* clb) {
-  return (cl_block*)gpr_atm_acq_load(&clb->block);
-}
-
-// Functions that operate on cl_block_list_struct's.
-
-static void cl_block_list_struct_initialize(cl_block_list_struct* bls,
-                                            cl_block* block) {
-  bls->next = bls->prev = bls;
-  bls->block = block;
-}
-
-// Functions that operate on cl_block_list's.
-
-static void cl_block_list_initialize(cl_block_list* list) {
-  list->count = 0;
-  cl_block_list_struct_initialize(&list->ht, NULL);
-}
-
-// Returns head of *this, or NULL if empty.
-static cl_block* cl_block_list_head(cl_block_list* list) {
-  return list->ht.next->block;
-}
-
-// Insert element *e after *pos.
-static void cl_block_list_insert(cl_block_list* list, cl_block_list_struct* pos,
-                                 cl_block_list_struct* e) {
-  list->count++;
-  e->next = pos->next;
-  e->prev = pos;
-  e->next->prev = e;
-  e->prev->next = e;
-}
-
-// Insert block at the head of the list
-static void cl_block_list_insert_at_head(cl_block_list* list, cl_block* block) {
-  cl_block_list_insert(list, &list->ht, &block->link);
-}
-
-// Insert block at the tail of the list.
-static void cl_block_list_insert_at_tail(cl_block_list* list, cl_block* block) {
-  cl_block_list_insert(list, list->ht.prev, &block->link);
-}
-
-// Removes block *b. Requires *b be in the list.
-static void cl_block_list_remove(cl_block_list* list, cl_block* b) {
-  list->count--;
-  b->link.next->prev = b->link.prev;
-  b->link.prev->next = b->link.next;
-}
-
-// Functions that operate on cl_block's
-
-static void cl_block_initialize(cl_block* block, char* buffer) {
-  block->buffer = buffer;
-  gpr_atm_rel_store(&block->writer_lock, 0);
-  gpr_atm_rel_store(&block->reader_lock, 0);
-  gpr_atm_rel_store(&block->bytes_committed, 0);
-  block->bytes_read = 0;
-  cl_block_list_struct_initialize(&block->link, block);
-}
-
-// Guards against exposing partially written buffer to the reader.
-static void cl_block_set_bytes_committed(cl_block* block,
-                                         size_t bytes_committed) {
-  gpr_atm_rel_store(&block->bytes_committed, (gpr_atm)bytes_committed);
-}
-
-static size_t cl_block_get_bytes_committed(cl_block* block) {
-  return (size_t)gpr_atm_acq_load(&block->bytes_committed);
-}
-
-// Tries to disable future read/write access to this block. Succeeds if:
-// - no in-progress write AND
-// - no in-progress read AND
-// - 'discard_data' set to true OR no unread data
-// On success, clears the block state and returns with writer_lock_ and
-// reader_lock_ held. These locks are released by a subsequent
-// cl_block_access_enable() call.
-static bool cl_block_try_disable_access(cl_block* block, int discard_data) {
-  if (!cl_try_lock(&block->writer_lock)) {
-    return false;
-  }
-  if (!cl_try_lock(&block->reader_lock)) {
-    cl_unlock(&block->writer_lock);
-    return false;
-  }
-  if (!discard_data &&
-      (block->bytes_read != cl_block_get_bytes_committed(block))) {
-    cl_unlock(&block->reader_lock);
-    cl_unlock(&block->writer_lock);
-    return false;
-  }
-  cl_block_set_bytes_committed(block, 0);
-  block->bytes_read = 0;
-  return true;
-}
-
-static void cl_block_enable_access(cl_block* block) {
-  cl_unlock(&block->reader_lock);
-  cl_unlock(&block->writer_lock);
-}
-
-// Returns with writer_lock held.
-static void* cl_block_start_write(cl_block* block, size_t size) {
-  if (!cl_try_lock(&block->writer_lock)) {
-    return NULL;
-  }
-  size_t bytes_committed = cl_block_get_bytes_committed(block);
-  if (bytes_committed + size > CENSUS_LOG_MAX_RECORD_SIZE) {
-    cl_unlock(&block->writer_lock);
-    return NULL;
-  }
-  return block->buffer + bytes_committed;
-}
-
-// Releases writer_lock and increments committed bytes by 'bytes_written'.
-// 'bytes_written' must be <= 'size' specified in the corresponding
-// StartWrite() call. This function is thread-safe.
-static void cl_block_end_write(cl_block* block, size_t bytes_written) {
-  cl_block_set_bytes_committed(
-      block, cl_block_get_bytes_committed(block) + bytes_written);
-  cl_unlock(&block->writer_lock);
-}
-
-// Returns a pointer to the first unread byte in buffer. The number of bytes
-// available are returned in 'bytes_available'. Acquires reader lock that is
-// released by a subsequent cl_block_end_read() call. Returns NULL if:
-// - read in progress
-// - no data available
-static void* cl_block_start_read(cl_block* block, size_t* bytes_available) {
-  if (!cl_try_lock(&block->reader_lock)) {
-    return NULL;
-  }
-  // bytes_committed may change from under us. Use bytes_available to update
-  // bytes_read below.
-  size_t bytes_committed = cl_block_get_bytes_committed(block);
-  GPR_ASSERT(bytes_committed >= block->bytes_read);
-  *bytes_available = bytes_committed - block->bytes_read;
-  if (*bytes_available == 0) {
-    cl_unlock(&block->reader_lock);
-    return NULL;
-  }
-  void* record = block->buffer + block->bytes_read;
-  block->bytes_read += *bytes_available;
-  return record;
-}
-
-static void cl_block_end_read(cl_block* block) {
-  cl_unlock(&block->reader_lock);
-}
-
-// Internal functions operating on g_log
-
-// Allocates a new free block (or recycles an available dirty block if log is
-// configured to discard old records). Returns NULL if out-of-space.
-static cl_block* cl_allocate_block(void) {
-  cl_block* block = cl_block_list_head(&g_log.free_block_list);
-  if (block != NULL) {
-    cl_block_list_remove(&g_log.free_block_list, block);
-    return block;
-  }
-  if (!g_log.discard_old_records) {
-    // No free block and log is configured to keep old records.
-    return NULL;
-  }
-  // Recycle dirty block. Start from the oldest.
-  for (block = cl_block_list_head(&g_log.dirty_block_list); block != NULL;
-       block = block->link.next->block) {
-    if (cl_block_try_disable_access(block, 1 /* discard data */)) {
-      cl_block_list_remove(&g_log.dirty_block_list, block);
-      return block;
-    }
-  }
-  return NULL;
-}
-
-// Allocates a new block and updates core id => block mapping. 'old_block'
-// points to the block that the caller thinks is attached to
-// 'core_id'. 'old_block' may be NULL. Returns true if:
-// - allocated a new block OR
-// - 'core_id' => 'old_block' mapping changed (another thread allocated a
-//   block before lock was acquired).
-static bool cl_allocate_core_local_block(uint32_t core_id,
-                                         cl_block* old_block) {
-  // Now that we have the lock, check if core-local mapping has changed.
-  cl_core_local_block* core_local_block = &g_log.core_local_blocks[core_id];
-  cl_block* block = cl_core_local_block_get_block(core_local_block);
-  if ((block != NULL) && (block != old_block)) {
-    return true;
-  }
-  if (block != NULL) {
-    cl_core_local_block_set_block(core_local_block, NULL);
-    cl_block_list_insert_at_tail(&g_log.dirty_block_list, block);
-  }
-  block = cl_allocate_block();
-  if (block == NULL) {
-    return false;
-  }
-  cl_core_local_block_set_block(core_local_block, block);
-  cl_block_enable_access(block);
-  return true;
-}
-
-static cl_block* cl_get_block(void* record) {
-  uintptr_t p = (uintptr_t)((char*)record - g_log.buffer);
-  uintptr_t index = p >> CENSUS_LOG_2_MAX_RECORD_SIZE;
-  return &g_log.blocks[index];
-}
-
-// Gets the next block to read and tries to free 'prev' block (if not NULL).
-// Returns NULL if reached the end.
-static cl_block* cl_next_block_to_read(cl_block* prev) {
-  cl_block* block = NULL;
-  if (g_log.read_iterator_state == g_log.num_cores) {
-    // We are traversing dirty list; find the next dirty block.
-    if (prev != NULL) {
-      // Try to free the previous block if there is no unread data. This
-      // block
-      // may have unread data if previously incomplete record completed
-      // between
-      // read_next() calls.
-      block = prev->link.next->block;
-      if (cl_block_try_disable_access(prev, 0 /* do not discard data */)) {
-        cl_block_list_remove(&g_log.dirty_block_list, prev);
-        cl_block_list_insert_at_head(&g_log.free_block_list, prev);
-      }
-    } else {
-      block = cl_block_list_head(&g_log.dirty_block_list);
-    }
-    if (block != NULL) {
-      return block;
-    }
-    // We are done with the dirty list; moving on to core-local blocks.
-  }
-  while (g_log.read_iterator_state > 0) {
-    g_log.read_iterator_state--;
-    block = cl_core_local_block_get_block(
-        &g_log.core_local_blocks[g_log.read_iterator_state]);
-    if (block != NULL) {
-      return block;
-    }
-  }
-  return NULL;
-}
-
-#define CL_LOG_2_MB 20  // 2^20 = 1MB
-
-// External functions: primary stats_log interface
-void census_log_initialize(size_t size_in_mb, int discard_old_records) {
-  // Check cacheline alignment.
-  GPR_ASSERT(sizeof(cl_block) % GPR_CACHELINE_SIZE == 0);
-  GPR_ASSERT(sizeof(cl_core_local_block) % GPR_CACHELINE_SIZE == 0);
-  GPR_ASSERT(!g_log.initialized);
-  g_log.discard_old_records = discard_old_records;
-  g_log.num_cores = gpr_cpu_num_cores();
-  // Ensure that we will not get any overflow in calaculating num_blocks
-  GPR_ASSERT(CL_LOG_2_MB >= CENSUS_LOG_2_MAX_RECORD_SIZE);
-  GPR_ASSERT(size_in_mb < 1000);
-  // Ensure at least 2x as many blocks as there are cores.
-  g_log.num_blocks =
-      (uint32_t)GPR_MAX(2 * g_log.num_cores, (size_in_mb << CL_LOG_2_MB) >>
-                                                 CENSUS_LOG_2_MAX_RECORD_SIZE);
-  gpr_mu_init(&g_log.lock);
-  g_log.read_iterator_state = 0;
-  g_log.block_being_read = NULL;
-  g_log.core_local_blocks = (cl_core_local_block*)gpr_malloc_aligned(
-      g_log.num_cores * sizeof(cl_core_local_block), GPR_CACHELINE_SIZE_LOG);
-  memset(g_log.core_local_blocks, 0,
-         g_log.num_cores * sizeof(cl_core_local_block));
-  g_log.blocks = (cl_block*)gpr_malloc_aligned(
-      g_log.num_blocks * sizeof(cl_block), GPR_CACHELINE_SIZE_LOG);
-  memset(g_log.blocks, 0, g_log.num_blocks * sizeof(cl_block));
-  g_log.buffer = gpr_malloc(g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE);
-  memset(g_log.buffer, 0, g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE);
-  cl_block_list_initialize(&g_log.free_block_list);
-  cl_block_list_initialize(&g_log.dirty_block_list);
-  for (uint32_t i = 0; i < g_log.num_blocks; ++i) {
-    cl_block* block = g_log.blocks + i;
-    cl_block_initialize(block, g_log.buffer + (CENSUS_LOG_MAX_RECORD_SIZE * i));
-    cl_block_try_disable_access(block, 1 /* discard data */);
-    cl_block_list_insert_at_tail(&g_log.free_block_list, block);
-  }
-  gpr_atm_rel_store(&g_log.out_of_space_count, 0);
-  g_log.initialized = 1;
-}
-
-void census_log_shutdown(void) {
-  GPR_ASSERT(g_log.initialized);
-  gpr_mu_destroy(&g_log.lock);
-  gpr_free_aligned(g_log.core_local_blocks);
-  g_log.core_local_blocks = NULL;
-  gpr_free_aligned(g_log.blocks);
-  g_log.blocks = NULL;
-  gpr_free(g_log.buffer);
-  g_log.buffer = NULL;
-  g_log.initialized = 0;
-}
-
-void* census_log_start_write(size_t size) {
-  // Used to bound number of times block allocation is attempted.
-  GPR_ASSERT(size > 0);
-  GPR_ASSERT(g_log.initialized);
-  if (size > CENSUS_LOG_MAX_RECORD_SIZE) {
-    return NULL;
-  }
-  uint32_t attempts_remaining = g_log.num_blocks;
-  uint32_t core_id = gpr_cpu_current_cpu();
-  do {
-    void* record = NULL;
-    cl_block* block =
-        cl_core_local_block_get_block(&g_log.core_local_blocks[core_id]);
-    if (block && (record = cl_block_start_write(block, size))) {
-      return record;
-    }
-    // Need to allocate a new block. We are here if:
-    // - No block associated with the core OR
-    // - Write in-progress on the block OR
-    // - block is out of space
-    gpr_mu_lock(&g_log.lock);
-    bool allocated = cl_allocate_core_local_block(core_id, block);
-    gpr_mu_unlock(&g_log.lock);
-    if (!allocated) {
-      gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
-      return NULL;
-    }
-  } while (attempts_remaining--);
-  // Give up.
-  gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
-  return NULL;
-}
-
-void census_log_end_write(void* record, size_t bytes_written) {
-  GPR_ASSERT(g_log.initialized);
-  cl_block_end_write(cl_get_block(record), bytes_written);
-}
-
-void census_log_init_reader(void) {
-  GPR_ASSERT(g_log.initialized);
-  gpr_mu_lock(&g_log.lock);
-  // If a block is locked for reading unlock it.
-  if (g_log.block_being_read != NULL) {
-    cl_block_end_read(g_log.block_being_read);
-    g_log.block_being_read = NULL;
-  }
-  g_log.read_iterator_state = g_log.num_cores;
-  gpr_mu_unlock(&g_log.lock);
-}
-
-const void* census_log_read_next(size_t* bytes_available) {
-  GPR_ASSERT(g_log.initialized);
-  gpr_mu_lock(&g_log.lock);
-  if (g_log.block_being_read != NULL) {
-    cl_block_end_read(g_log.block_being_read);
-  }
-  do {
-    g_log.block_being_read = cl_next_block_to_read(g_log.block_being_read);
-    if (g_log.block_being_read != NULL) {
-      void* record =
-          cl_block_start_read(g_log.block_being_read, bytes_available);
-      if (record != NULL) {
-        gpr_mu_unlock(&g_log.lock);
-        return record;
-      }
-    }
-  } while (g_log.block_being_read != NULL);
-  gpr_mu_unlock(&g_log.lock);
-  return NULL;
-}
-
-size_t census_log_remaining_space(void) {
-  GPR_ASSERT(g_log.initialized);
-  size_t space = 0;
-  gpr_mu_lock(&g_log.lock);
-  if (g_log.discard_old_records) {
-    // Remaining space is not meaningful; just return the entire log space.
-    space = g_log.num_blocks << CENSUS_LOG_2_MAX_RECORD_SIZE;
-  } else {
-    GPR_ASSERT(g_log.free_block_list.count >= 0);
-    space = (size_t)g_log.free_block_list.count * CENSUS_LOG_MAX_RECORD_SIZE;
-  }
-  gpr_mu_unlock(&g_log.lock);
-  return space;
-}
-
-int64_t census_log_out_of_space_count(void) {
-  GPR_ASSERT(g_log.initialized);
-  return gpr_atm_acq_load(&g_log.out_of_space_count);
-}
diff --git a/src/core/census/mlog.h b/src/core/census/mlog.h
deleted file mode 100644
index aaba9e1..0000000
--- a/src/core/census/mlog.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* A very fast in-memory log, optimized for multiple writers. */
-
-#ifndef GRPC_INTERNAL_CORE_CENSUS_MLOG_H
-#define GRPC_INTERNAL_CORE_CENSUS_MLOG_H
-
-#include <grpc/support/port_platform.h>
-#include <stddef.h>
-
-/* Maximum record size, in bytes. */
-#define CENSUS_LOG_2_MAX_RECORD_SIZE 14 /* 2^14 = 16KB */
-#define CENSUS_LOG_MAX_RECORD_SIZE (1 << CENSUS_LOG_2_MAX_RECORD_SIZE)
-
-/* Initialize the statistics logging subsystem with the given log size. A log
-   size of 0 will result in the smallest possible log for the platform
-   (approximately CENSUS_LOG_MAX_RECORD_SIZE * gpr_cpu_num_cores()). If
-   discard_old_records is non-zero, then new records will displace older ones
-   when the log is full. This function must be called before any other
-   census_log functions.
-*/
-void census_log_initialize(size_t size_in_mb, int discard_old_records);
-
-/* Shutdown the logging subsystem. Caller must ensure that:
-   - no in progress or future call to any census_log functions
-   - no incomplete records
-*/
-void census_log_shutdown(void);
-
-/* Allocates and returns a 'size' bytes record and marks it in use. A
-   subsequent census_log_end_write() marks the record complete. The
-   'bytes_written' census_log_end_write() argument must be <=
-   'size'. Returns NULL if out-of-space AND:
-       - log is configured to keep old records OR
-       - all blocks are pinned by incomplete records.
-*/
-void* census_log_start_write(size_t size);
-
-void census_log_end_write(void* record, size_t bytes_written);
-
-void census_log_init_reader(void);
-
-/* census_log_read_next() iterates over blocks with data and for each block
-   returns a pointer to the first unread byte. The number of bytes that can be
-   read are returned in 'bytes_available'. Reader is expected to read all
-   available data. Reading the data consumes it i.e. it cannot be read again.
-   census_log_read_next() returns NULL if the end is reached i.e last block
-   is read. census_log_init_reader() starts the iteration or aborts the
-   current iteration.
-*/
-const void* census_log_read_next(size_t* bytes_available);
-
-/* Returns estimated remaining space across all blocks, in bytes. If log is
-   configured to discard old records, returns total log space. Otherwise,
-   returns space available in empty blocks (partially filled blocks are
-   treated as full).
-*/
-size_t census_log_remaining_space(void);
-
-/* Returns the number of times gprc_stats_log_start_write() failed due to
-   out-of-space. */
-int64_t census_log_out_of_space_count(void);
-
-#endif /* GRPC_INTERNAL_CORE_CENSUS_LOG_H */
diff --git a/src/core/census/operation.c b/src/core/census/operation.c
deleted file mode 100644
index 5c58704..0000000
--- a/src/core/census/operation.c
+++ /dev/null
@@ -1,63 +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/census.h>
-
-/* TODO(aveitch): These are all placeholder implementations. */
-
-census_timestamp census_start_rpc_op_timestamp(void) {
-  census_timestamp ct;
-  /* TODO(aveitch): assumes gpr_timespec implementation of census_timestamp. */
-  ct.ts = gpr_now(GPR_CLOCK_MONOTONIC);
-  return ct;
-}
-
-census_context *census_start_client_rpc_op(
-    const census_context *context, int64_t rpc_name_id,
-    const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask,
-    const census_timestamp *start_time) {
-  return NULL;
-}
-
-census_context *census_start_server_rpc_op(
-    const char *buffer, int64_t rpc_name_id,
-    const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask,
-    census_timestamp *start_time) {
-  return NULL;
-}
-
-census_context *census_start_op(census_context *context, const char *family,
-                                const char *name, int trace_mask) {
-  return NULL;
-}
-
-void census_end_op(census_context *context, int status) {}
diff --git a/src/core/census/rpc_metric_id.h b/src/core/census/rpc_metric_id.h
deleted file mode 100644
index f199839..0000000
--- a/src/core/census/rpc_metric_id.h
+++ /dev/null
@@ -1,51 +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 CENSUS_RPC_METRIC_ID_H
-#define CENSUS_RPC_METRIC_ID_H
-
-/* Metric ID's used for RPC measurements. */
-/* Count of client requests sent. */
-#define CENSUS_METRIC_RPC_CLIENT_REQUESTS ((uint32_t)0)
-/* Count of server requests sent. */
-#define CENSUS_METRIC_RPC_SERVER_REQUESTS ((uint32_t)1)
-/* Client error counts. */
-#define CENSUS_METRIC_RPC_CLIENT_ERRORS ((uint32_t)2)
-/* Server error counts. */
-#define CENSUS_METRIC_RPC_SERVER_ERRORS ((uint32_t)3)
-/* Client side request latency. */
-#define CENSUS_METRIC_RPC_CLIENT_LATENCY ((uint32_t)4)
-/* Server side request latency. */
-#define CENSUS_METRIC_RPC_SERVER_LATENCY ((uint32_t)5)
-
-#endif /* CENSUS_RPC_METRIC_ID_H */
diff --git a/src/core/census/tracing.c b/src/core/census/tracing.c
deleted file mode 100644
index 3b5d6da..0000000
--- a/src/core/census/tracing.c
+++ /dev/null
@@ -1,45 +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/census.h>
-
-/* TODO(aveitch): These are all placeholder implementations. */
-
-int census_trace_mask(const census_context *context) {
-  return CENSUS_TRACE_MASK_NONE;
-}
-
-void census_set_trace_mask(int trace_mask) {}
-
-void census_trace_print(census_context *context, uint32_t type,
-                        const char *buffer, size_t n) {}
diff --git a/src/core/channel/channel_args.c b/src/core/channel/channel_args.c
deleted file mode 100644
index bae7a90..0000000
--- a/src/core/channel/channel_args.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/grpc.h>
-#include "src/core/channel/channel_args.h"
-#include "src/core/support/string.h"
-
-#include <grpc/census.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
-
-#include <string.h>
-
-static grpc_arg copy_arg(const grpc_arg *src) {
-  grpc_arg dst;
-  dst.type = src->type;
-  dst.key = gpr_strdup(src->key);
-  switch (dst.type) {
-    case GRPC_ARG_STRING:
-      dst.value.string = gpr_strdup(src->value.string);
-      break;
-    case GRPC_ARG_INTEGER:
-      dst.value.integer = src->value.integer;
-      break;
-    case GRPC_ARG_POINTER:
-      dst.value.pointer = src->value.pointer;
-      dst.value.pointer.p =
-          src->value.pointer.vtable->copy(src->value.pointer.p);
-      break;
-  }
-  return dst;
-}
-
-grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
-                                                  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;
-  if (!src && !to_add) {
-    dst->num_args = 0;
-    dst->args = NULL;
-    return dst;
-  }
-  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]);
-  }
-  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, 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);
-}
-
-static int cmp_arg(const grpc_arg *a, const grpc_arg *b) {
-  int c = GPR_ICMP(a->type, b->type);
-  if (c != 0) return c;
-  c = strcmp(a->key, b->key);
-  if (c != 0) return c;
-  switch (a->type) {
-    case GRPC_ARG_STRING:
-      return strcmp(a->value.string, b->value.string);
-    case GRPC_ARG_INTEGER:
-      return GPR_ICMP(a->value.integer, b->value.integer);
-    case GRPC_ARG_POINTER:
-      c = GPR_ICMP(a->value.pointer.p, b->value.pointer.p);
-      if (c != 0) {
-        c = GPR_ICMP(a->value.pointer.vtable, b->value.pointer.vtable);
-        if (c == 0) {
-          c = a->value.pointer.vtable->cmp(a->value.pointer.p,
-                                           b->value.pointer.p);
-        }
-      }
-      return c;
-  }
-  GPR_UNREACHABLE_CODE(return 0);
-}
-
-/* stabilizing comparison function: since channel_args ordering matters for
- * keys with the same name, we need to preserve that ordering */
-static int cmp_key_stable(const void *ap, const void *bp) {
-  const grpc_arg *const *a = ap;
-  const grpc_arg *const *b = bp;
-  int c = strcmp((*a)->key, (*b)->key);
-  if (c == 0) c = GPR_ICMP(*a, *b);
-  return c;
-}
-
-grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a) {
-  grpc_arg **args = gpr_malloc(sizeof(grpc_arg *) * a->num_args);
-  for (size_t i = 0; i < a->num_args; i++) {
-    args[i] = &a->args[i];
-  }
-  qsort(args, a->num_args, sizeof(grpc_arg *), cmp_key_stable);
-
-  grpc_channel_args *b = gpr_malloc(sizeof(grpc_channel_args));
-  b->num_args = a->num_args;
-  b->args = gpr_malloc(sizeof(grpc_arg) * b->num_args);
-  for (size_t i = 0; i < a->num_args; i++) {
-    b->args[i] = copy_arg(args[i]);
-  }
-
-  gpr_free(args);
-  return b;
-}
-
-void grpc_channel_args_destroy(grpc_channel_args *a) {
-  size_t i;
-  for (i = 0; i < a->num_args; i++) {
-    switch (a->args[i].type) {
-      case GRPC_ARG_STRING:
-        gpr_free(a->args[i].value.string);
-        break;
-      case GRPC_ARG_INTEGER:
-        break;
-      case GRPC_ARG_POINTER:
-        a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p);
-        break;
-    }
-    gpr_free(a->args[i].key);
-  }
-  gpr_free(a->args);
-  gpr_free(a);
-}
-
-int grpc_channel_args_is_census_enabled(const grpc_channel_args *a) {
-  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)) {
-      return a->args[i].value.integer != 0 && census_enabled();
-    }
-  }
-  return census_enabled();
-}
-
-grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
-    const grpc_channel_args *a) {
-  size_t i;
-  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 (grpc_compression_algorithm)a->args[i].value.integer;
-      break;
-    }
-  }
-  return GRPC_COMPRESS_NONE;
-}
-
-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_ALGORITHM_ARG;
-  tmp.value.integer = algorithm;
-  return grpc_channel_args_copy_and_add(a, &tmp, 1);
-}
-
-/** Returns 1 if the argument for compression algorithm's enabled states bitset
- * was found in \a a, returning the arg's value in \a states. Otherwise, returns
- * 0. */
-static int find_compression_algorithm_states_bitset(const grpc_channel_args *a,
-                                                    int **states_arg) {
-  if (a != NULL) {
-    size_t i;
-    for (i = 0; i < a->num_args; ++i) {
-      if (a->args[i].type == GRPC_ARG_INTEGER &&
-          !strcmp(GRPC_COMPRESSION_ALGORITHM_STATE_ARG, a->args[i].key)) {
-        *states_arg = &a->args[i].value.integer;
-        return 1; /* GPR_TRUE */
-      }
-    }
-  }
-  return 0; /* GPR_FALSE */
-}
-
-grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
-    grpc_channel_args **a, grpc_compression_algorithm algorithm, int state) {
-  int *states_arg;
-  grpc_channel_args *result = *a;
-  const int states_arg_found =
-      find_compression_algorithm_states_bitset(*a, &states_arg);
-
-  if (states_arg_found) {
-    if (state != 0) {
-      GPR_BITSET((unsigned *)states_arg, algorithm);
-    } else {
-      GPR_BITCLEAR((unsigned *)states_arg, algorithm);
-    }
-  } else {
-    /* create a new arg */
-    grpc_arg tmp;
-    tmp.type = GRPC_ARG_INTEGER;
-    tmp.key = GRPC_COMPRESSION_ALGORITHM_STATE_ARG;
-    /* all enabled by default */
-    tmp.value.integer = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
-    if (state != 0) {
-      GPR_BITSET((unsigned *)&tmp.value.integer, algorithm);
-    } else {
-      GPR_BITCLEAR((unsigned *)&tmp.value.integer, algorithm);
-    }
-    result = grpc_channel_args_copy_and_add(*a, &tmp, 1);
-    grpc_channel_args_destroy(*a);
-    *a = result;
-  }
-  return result;
-}
-
-int grpc_channel_args_compression_algorithm_get_states(
-    const grpc_channel_args *a) {
-  int *states_arg;
-  if (find_compression_algorithm_states_bitset(a, &states_arg)) {
-    return *states_arg;
-  } else {
-    return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */
-  }
-}
-
-int grpc_channel_args_compare(const grpc_channel_args *a,
-                              const grpc_channel_args *b) {
-  int c = GPR_ICMP(a->num_args, b->num_args);
-  if (c != 0) return c;
-  for (size_t i = 0; i < a->num_args; i++) {
-    c = cmp_arg(&a->args[i], &b->args[i]);
-    if (c != 0) return c;
-  }
-  return 0;
-}
diff --git a/src/core/channel/channel_args.h b/src/core/channel/channel_args.h
deleted file mode 100644
index b3a7c9f..0000000
--- a/src/core/channel/channel_args.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H
-#define GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H
-
-#include <grpc/compression.h>
-#include <grpc/grpc.h>
-
-/* Copy some arguments */
-grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src);
-
-/* Copy some arguments, stably sorting keys */
-grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a);
-
-/** 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,
-                                                  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);
-
-/** Reads census_enabled settings from channel args. Returns 1 if census_enabled
- * is specified in channel args, otherwise returns 0. */
-int grpc_channel_args_is_census_enabled(const grpc_channel_args *a);
-
-/** Returns the compression algorithm set in \a a. */
-grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
-    const grpc_channel_args *a);
-
-/** 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);
-
-/** Sets the support for the given compression algorithm. By default, all
- * compression algorithms are enabled. It's an error to disable an algorithm set
- * by grpc_channel_args_set_compression_algorithm.
- *
- * Returns an instance with the updated algorithm states. The \a a pointer is
- * modified to point to the returned instance (which may be different from the
- * input value of \a a). */
-grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
-    grpc_channel_args **a, grpc_compression_algorithm algorithm, int enabled);
-
-/** Returns the bitset representing the support state (true for enabled, false
- * for disabled) for compression algorithms.
- *
- * The i-th bit of the returned bitset corresponds to the i-th entry in the
- * grpc_compression_algorithm enum. */
-int grpc_channel_args_compression_algorithm_get_states(
-    const grpc_channel_args *a);
-
-int grpc_channel_args_compare(const grpc_channel_args *a,
-                              const grpc_channel_args *b);
-
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H */
diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c
deleted file mode 100644
index 3e61688..0000000
--- a/src/core/channel/channel_stack.c
+++ /dev/null
@@ -1,262 +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/channel_stack.h"
-#include <grpc/support/log.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-int grpc_trace_channel = 0;
-
-/* Memory layouts.
-
-   Channel stack is laid out as: {
-     grpc_channel_stack stk;
-     padding to GPR_MAX_ALIGNMENT
-     grpc_channel_element[stk.count];
-     per-filter memory, aligned to GPR_MAX_ALIGNMENT
-   }
-
-   Call stack is laid out as: {
-     grpc_call_stack stk;
-     padding to GPR_MAX_ALIGNMENT
-     grpc_call_element[stk.count];
-     per-filter memory, aligned to GPR_MAX_ALIGNMENT
-   } */
-
-/* Given a size, round up to the next multiple of sizeof(void*) */
-#define ROUND_UP_TO_ALIGNMENT_SIZE(x) \
-  (((x) + GPR_MAX_ALIGNMENT - 1u) & ~(GPR_MAX_ALIGNMENT - 1u))
-
-size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
-                               size_t filter_count) {
-  /* always need the header, and size for the channel elements */
-  size_t size =
-      ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)) +
-      ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element));
-  size_t i;
-
-  GPR_ASSERT((GPR_MAX_ALIGNMENT & (GPR_MAX_ALIGNMENT - 1)) == 0 &&
-             "GPR_MAX_ALIGNMENT must be a power of two");
-
-  /* add the size for each filter */
-  for (i = 0; i < filter_count; i++) {
-    size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
-  }
-
-  return size;
-}
-
-#define CHANNEL_ELEMS_FROM_STACK(stk)                                   \
-  ((grpc_channel_element *)((char *)(stk) + ROUND_UP_TO_ALIGNMENT_SIZE( \
-                                                sizeof(grpc_channel_stack))))
-
-#define CALL_ELEMS_FROM_STACK(stk)       \
-  ((grpc_call_element *)((char *)(stk) + \
-                         ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack))))
-
-grpc_channel_element *grpc_channel_stack_element(
-    grpc_channel_stack *channel_stack, size_t index) {
-  return CHANNEL_ELEMS_FROM_STACK(channel_stack) + index;
-}
-
-grpc_channel_element *grpc_channel_stack_last_element(
-    grpc_channel_stack *channel_stack) {
-  return grpc_channel_stack_element(channel_stack, channel_stack->count - 1);
-}
-
-grpc_call_element *grpc_call_stack_element(grpc_call_stack *call_stack,
-                                           size_t index) {
-  return CALL_ELEMS_FROM_STACK(call_stack) + index;
-}
-
-void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
-                             grpc_iomgr_cb_func destroy, void *destroy_arg,
-                             const grpc_channel_filter **filters,
-                             size_t filter_count,
-                             const grpc_channel_args *channel_args,
-                             const char *name, grpc_channel_stack *stack) {
-  size_t call_size =
-      ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
-      ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element));
-  grpc_channel_element *elems;
-  grpc_channel_element_args args;
-  char *user_data;
-  size_t i;
-
-  stack->count = filter_count;
-  GRPC_STREAM_REF_INIT(&stack->refcount, initial_refs, destroy, destroy_arg,
-                       name);
-  elems = CHANNEL_ELEMS_FROM_STACK(stack);
-  user_data =
-      ((char *)elems) +
-      ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element));
-
-  /* init per-filter data */
-  for (i = 0; i < filter_count; i++) {
-    args.channel_stack = stack;
-    args.channel_args = channel_args;
-    args.is_first = i == 0;
-    args.is_last = i == (filter_count - 1);
-    elems[i].filter = filters[i];
-    elems[i].channel_data = user_data;
-    elems[i].filter->init_channel_elem(exec_ctx, &elems[i], &args);
-    user_data += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
-    call_size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_call_data);
-  }
-
-  GPR_ASSERT(user_data > (char *)stack);
-  GPR_ASSERT((uintptr_t)(user_data - (char *)stack) ==
-             grpc_channel_stack_size(filters, filter_count));
-
-  stack->call_stack_size = call_size;
-}
-
-void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
-                                grpc_channel_stack *stack) {
-  grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(stack);
-  size_t count = stack->count;
-  size_t i;
-
-  /* destroy per-filter data */
-  for (i = 0; i < count; i++) {
-    channel_elems[i].filter->destroy_channel_elem(exec_ctx, &channel_elems[i]);
-  }
-}
-
-void grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
-                          grpc_channel_stack *channel_stack, int initial_refs,
-                          grpc_iomgr_cb_func destroy, void *destroy_arg,
-                          grpc_call_context_element *context,
-                          const void *transport_server_data,
-                          grpc_call_stack *call_stack) {
-  grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
-  grpc_call_element_args args;
-  size_t count = channel_stack->count;
-  grpc_call_element *call_elems;
-  char *user_data;
-  size_t i;
-
-  call_stack->count = count;
-  GRPC_STREAM_REF_INIT(&call_stack->refcount, initial_refs, destroy,
-                       destroy_arg, "CALL_STACK");
-  call_elems = CALL_ELEMS_FROM_STACK(call_stack);
-  user_data = ((char *)call_elems) +
-              ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
-
-  /* init per-filter data */
-  for (i = 0; i < count; i++) {
-    args.call_stack = call_stack;
-    args.server_transport_data = transport_server_data;
-    args.context = context;
-    call_elems[i].filter = channel_elems[i].filter;
-    call_elems[i].channel_data = channel_elems[i].channel_data;
-    call_elems[i].call_data = user_data;
-    call_elems[i].filter->init_call_elem(exec_ctx, &call_elems[i], &args);
-    user_data +=
-        ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
-  }
-}
-
-void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx,
-                                 grpc_call_stack *call_stack,
-                                 grpc_pollset *pollset) {
-  size_t count = call_stack->count;
-  grpc_call_element *call_elems;
-  char *user_data;
-  size_t i;
-
-  call_elems = CALL_ELEMS_FROM_STACK(call_stack);
-  user_data = ((char *)call_elems) +
-              ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
-
-  /* init per-filter data */
-  for (i = 0; i < count; i++) {
-    call_elems[i].filter->set_pollset(exec_ctx, &call_elems[i], pollset);
-    user_data +=
-        ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
-  }
-}
-
-void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx,
-                                        grpc_call_element *elem,
-                                        grpc_pollset *pollset) {}
-
-void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack) {
-  grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack);
-  size_t count = stack->count;
-  size_t i;
-
-  /* destroy per-filter data */
-  for (i = 0; i < count; i++) {
-    elems[i].filter->destroy_call_elem(exec_ctx, &elems[i]);
-  }
-}
-
-void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                       grpc_transport_stream_op *op) {
-  grpc_call_element *next_elem = elem + 1;
-  next_elem->filter->start_transport_stream_op(exec_ctx, next_elem, op);
-}
-
-char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {
-  grpc_call_element *next_elem = elem + 1;
-  return next_elem->filter->get_peer(exec_ctx, next_elem);
-}
-
-void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
-                          grpc_transport_op *op) {
-  grpc_channel_element *next_elem = elem + 1;
-  next_elem->filter->start_transport_op(exec_ctx, next_elem, op);
-}
-
-grpc_channel_stack *grpc_channel_stack_from_top_element(
-    grpc_channel_element *elem) {
-  return (grpc_channel_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE(
-      sizeof(grpc_channel_stack)));
-}
-
-grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) {
-  return (grpc_call_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE(
-      sizeof(grpc_call_stack)));
-}
-
-void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx,
-                                   grpc_call_element *cur_elem) {
-  grpc_transport_stream_op op;
-  memset(&op, 0, sizeof(op));
-  op.cancel_with_status = GRPC_STATUS_CANCELLED;
-  grpc_call_next_op(exec_ctx, cur_elem, &op);
-}
diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h
deleted file mode 100644
index c01050e..0000000
--- a/src/core/channel/channel_stack.h
+++ /dev/null
@@ -1,260 +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_CHANNEL_STACK_H
-#define GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_STACK_H
-
-/* A channel filter defines how operations on a channel are implemented.
-   Channel filters are chained together to create full channels, and if those
-   chains are linear, then channel stacks provide a mechanism to minimize
-   allocations for that chain.
-   Call stacks are created by channel stacks and represent the per-call data
-   for that stack. */
-
-#include <stddef.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
-#include "src/core/debug/trace.h"
-#include "src/core/transport/transport.h"
-
-typedef struct grpc_channel_element grpc_channel_element;
-typedef struct grpc_call_element grpc_call_element;
-
-typedef struct grpc_channel_stack grpc_channel_stack;
-typedef struct grpc_call_stack grpc_call_stack;
-
-typedef struct {
-  grpc_channel_stack *channel_stack;
-  const grpc_channel_args *channel_args;
-  int is_first;
-  int is_last;
-} grpc_channel_element_args;
-
-typedef struct {
-  grpc_call_stack *call_stack;
-  const void *server_transport_data;
-  grpc_call_context_element *context;
-} grpc_call_element_args;
-
-/* Channel filters specify:
-   1. the amount of memory needed in the channel & call (via the sizeof_XXX
-      members)
-   2. functions to initialize and destroy channel & call data
-      (init_XXX, destroy_XXX)
-   3. functions to implement call operations and channel operations (call_op,
-      channel_op)
-   4. a name, which is useful when debugging
-
-   Members are laid out in approximate frequency of use order. */
-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_stream_op)(grpc_exec_ctx *exec_ctx,
-                                    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 (*start_transport_op)(grpc_exec_ctx *exec_ctx,
-                             grpc_channel_element *elem, grpc_transport_op *op);
-
-  /* sizeof(per call data) */
-  size_t sizeof_call_data;
-  /* Initialize per call data.
-     elem is initialized at the start of the call, and elem->call_data is what
-     needs initializing.
-     The filter does not need to do any chaining.
-     server_transport_data is an opaque pointer. If it is NULL, this call is
-     on a client; if it is non-NULL, then it points to memory owned by the
-     transport and is on the server. Most filters want to ignore this
-     argument. */
-  void (*init_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                         grpc_call_element_args *args);
-  void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                      grpc_pollset *pollset);
-  /* Destroy per call data.
-     The filter does not need to do any chaining */
-  void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
-
-  /* sizeof(per channel data) */
-  size_t sizeof_channel_data;
-  /* Initialize per-channel data.
-     elem is initialized at the start of the call, and elem->channel_data is
-     what needs initializing.
-     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_exec_ctx *exec_ctx, grpc_channel_element *elem,
-                            grpc_channel_element_args *args);
-  /* Destroy per channel data.
-     The filter does not need to do any chaining */
-  void (*destroy_channel_elem)(grpc_exec_ctx *exec_ctx,
-                               grpc_channel_element *elem);
-
-  /* Implement grpc_call_get_peer() */
-  char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
-
-  /* The name of this filter */
-  const char *name;
-} grpc_channel_filter;
-
-/* A channel_element tracks its filter and the filter requested memory within
-   a channel allocation */
-struct grpc_channel_element {
-  const grpc_channel_filter *filter;
-  void *channel_data;
-};
-
-/* A call_element tracks its filter, the filter requested memory within
-   a channel allocation, and the filter requested memory within a call
-   allocation */
-struct grpc_call_element {
-  const grpc_channel_filter *filter;
-  void *channel_data;
-  void *call_data;
-};
-
-/* A channel stack tracks a set of related filters for one channel, and
-   guarantees they live within a single malloc() allocation */
-struct grpc_channel_stack {
-  grpc_stream_refcount refcount;
-  size_t count;
-  /* Memory required for a call stack (computed at channel stack
-     initialization) */
-  size_t call_stack_size;
-};
-
-/* A call stack tracks a set of related filters for one call, and guarantees
-   they live within a single malloc() allocation */
-struct grpc_call_stack {
-  /* shared refcount for this channel stack.
-     MUST be the first element: the underlying code calls destroy
-     with the address of the refcount, but higher layers prefer to think
-     about the address of the call stack itself. */
-  grpc_stream_refcount refcount;
-  size_t count;
-};
-
-/* Get a channel element given a channel stack and its index */
-grpc_channel_element *grpc_channel_stack_element(grpc_channel_stack *stack,
-                                                 size_t i);
-/* Get the last channel element in a channel stack */
-grpc_channel_element *grpc_channel_stack_last_element(
-    grpc_channel_stack *stack);
-/* Get a call stack element given a call stack and an index */
-grpc_call_element *grpc_call_stack_element(grpc_call_stack *stack, size_t i);
-
-/* Determine memory required for a channel stack containing a set of filters */
-size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
-                               size_t filter_count);
-/* Initialize a channel stack given some filters */
-void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
-                             grpc_iomgr_cb_func destroy, void *destroy_arg,
-                             const grpc_channel_filter **filters,
-                             size_t filter_count, const grpc_channel_args *args,
-                             const char *name, grpc_channel_stack *stack);
-/* Destroy a channel stack */
-void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
-                                grpc_channel_stack *stack);
-
-/* Initialize a call stack given a channel stack. transport_server_data is
-   expected to be NULL on a client, or an opaque transport owned pointer on the
-   server. */
-void grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
-                          grpc_channel_stack *channel_stack, int initial_refs,
-                          grpc_iomgr_cb_func destroy, void *destroy_arg,
-                          grpc_call_context_element *context,
-                          const void *transport_server_data,
-                          grpc_call_stack *call_stack);
-/* Set a pollset for a call stack: must occur before the first op is started */
-void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx,
-                                 grpc_call_stack *call_stack,
-                                 grpc_pollset *pollset);
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-#define GRPC_CALL_STACK_REF(call_stack, reason) \
-  grpc_stream_ref(&(call_stack)->refcount, reason)
-#define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \
-  grpc_stream_unref(exec_ctx, &(call_stack)->refcount, reason)
-#define GRPC_CHANNEL_STACK_REF(channel_stack, reason) \
-  grpc_stream_ref(&(channel_stack)->refcount, reason)
-#define GRPC_CHANNEL_STACK_UNREF(exec_ctx, channel_stack, reason) \
-  grpc_stream_unref(exec_ctx, &(channel_stack)->refcount, reason)
-#else
-#define GRPC_CALL_STACK_REF(call_stack, reason) \
-  grpc_stream_ref(&(call_stack)->refcount)
-#define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \
-  grpc_stream_unref(exec_ctx, &(call_stack)->refcount)
-#define GRPC_CHANNEL_STACK_REF(channel_stack, reason) \
-  grpc_stream_ref(&(channel_stack)->refcount)
-#define GRPC_CHANNEL_STACK_UNREF(exec_ctx, channel_stack, reason) \
-  grpc_stream_unref(exec_ctx, &(channel_stack)->refcount)
-#endif
-
-/* Destroy a call stack */
-void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack);
-
-/* Ignore set pollset - used by filters to implement the set_pollset method
-   if they don't care about pollsets at all. Does nothing. */
-void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx,
-                                        grpc_call_element *elem,
-                                        grpc_pollset *pollset);
-/* Call the next operation in a call stack */
-void grpc_call_next_op(grpc_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx, grpc_channel_element *elem,
-                          grpc_transport_op *op);
-/* Pass through a request to get_peer to the next child element */
-char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
-
-/* Given the top element of a channel stack, get the channel stack itself */
-grpc_channel_stack *grpc_channel_stack_from_top_element(
-    grpc_channel_element *elem);
-/* Given the top element of a call stack, get the call stack itself */
-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_stream_op *op);
-
-void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx,
-                                   grpc_call_element *cur_elem);
-
-extern int grpc_trace_channel;
-
-#define GRPC_CALL_LOG_OP(sev, elem, op) \
-  if (grpc_trace_channel) grpc_call_log_op(sev, elem, op)
-
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_STACK_H */
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
deleted file mode 100644
index f021a8a..0000000
--- a/src/core/channel/client_channel.c
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/channel/client_channel.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/connected_channel.h"
-#include "src/core/channel/subchannel_call_holder.h"
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/profiling/timers.h"
-#include "src/core/support/string.h"
-#include "src/core/surface/channel.h"
-#include "src/core/transport/connectivity_state.h"
-
-/* Client channel implementation */
-
-typedef grpc_subchannel_call_holder call_data;
-
-typedef struct client_channel_channel_data {
-  /** resolver for this channel */
-  grpc_resolver *resolver;
-  /** have we started resolving this channel */
-  int started_resolving;
-
-  /** 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_closure_list waiting_for_config_closures;
-  /** resolver callback */
-  grpc_closure on_config_changed;
-  /** connectivity state being tracked */
-  grpc_connectivity_state_tracker state_tracker;
-  /** when an lb_policy arrives, should we try to exit idle */
-  int exit_idle_when_lb_policy_arrives;
-  /** owning stack */
-  grpc_channel_stack *owning_stack;
-  /** interested parties (owned) */
-  grpc_pollset_set *interested_parties;
-} channel_data;
-
-/** We create one watcher for each new lb_policy that is returned from a
-   resolver,
-    to watch for state changes from the lb_policy. When a state change is seen,
-   we
-    update the channel, and create a new watcher */
-typedef struct {
-  channel_data *chand;
-  grpc_closure on_changed;
-  grpc_connectivity_state state;
-  grpc_lb_policy *lb_policy;
-} lb_policy_connectivity_watcher;
-
-typedef struct {
-  grpc_closure closure;
-  grpc_call_element *elem;
-} waiting_call;
-
-static char *cc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
-  return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data);
-}
-
-static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                         grpc_call_element *elem,
-                                         grpc_transport_stream_op *op) {
-  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-  grpc_subchannel_call_holder_perform_op(exec_ctx, elem->call_data, op);
-}
-
-static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
-                            grpc_lb_policy *lb_policy,
-                            grpc_connectivity_state current_state);
-
-static void on_lb_policy_state_changed_locked(
-    grpc_exec_ctx *exec_ctx, lb_policy_connectivity_watcher *w) {
-  grpc_connectivity_state publish_state = w->state;
-  /* check if the notification is for a stale policy */
-  if (w->lb_policy != w->chand->lb_policy) return;
-
-  if (publish_state == GRPC_CHANNEL_FATAL_FAILURE &&
-      w->chand->resolver != NULL) {
-    publish_state = GRPC_CHANNEL_TRANSIENT_FAILURE;
-    grpc_resolver_channel_saw_error(exec_ctx, w->chand->resolver);
-    GRPC_LB_POLICY_UNREF(exec_ctx, w->chand->lb_policy, "channel");
-    w->chand->lb_policy = NULL;
-  }
-  grpc_connectivity_state_set(exec_ctx, &w->chand->state_tracker, publish_state,
-                              "lb_changed");
-  if (w->state != GRPC_CHANNEL_FATAL_FAILURE) {
-    watch_lb_policy(exec_ctx, w->chand, w->lb_policy, w->state);
-  }
-}
-
-static void on_lb_policy_state_changed(grpc_exec_ctx *exec_ctx, void *arg,
-                                       bool iomgr_success) {
-  lb_policy_connectivity_watcher *w = arg;
-
-  gpr_mu_lock(&w->chand->mu_config);
-  on_lb_policy_state_changed_locked(exec_ctx, w);
-  gpr_mu_unlock(&w->chand->mu_config);
-
-  GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy");
-  gpr_free(w);
-}
-
-static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
-                            grpc_lb_policy *lb_policy,
-                            grpc_connectivity_state current_state) {
-  lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w));
-  GRPC_CHANNEL_STACK_REF(chand->owning_stack, "watch_lb_policy");
-
-  w->chand = chand;
-  grpc_closure_init(&w->on_changed, on_lb_policy_state_changed, w);
-  w->state = current_state;
-  w->lb_policy = lb_policy;
-  grpc_lb_policy_notify_on_state_change(exec_ctx, lb_policy, &w->state,
-                                        &w->on_changed);
-}
-
-static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
-                                 bool iomgr_success) {
-  channel_data *chand = arg;
-  grpc_lb_policy *lb_policy = NULL;
-  grpc_lb_policy *old_lb_policy;
-  grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
-  int exit_idle = 0;
-
-  if (chand->incoming_configuration != NULL) {
-    lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration);
-    if (lb_policy != NULL) {
-      GRPC_LB_POLICY_REF(lb_policy, "channel");
-      GRPC_LB_POLICY_REF(lb_policy, "config_change");
-      state = grpc_lb_policy_check_connectivity(exec_ctx, lb_policy);
-    }
-
-    grpc_client_config_unref(exec_ctx, chand->incoming_configuration);
-  }
-
-  chand->incoming_configuration = NULL;
-
-  if (lb_policy != NULL) {
-    grpc_pollset_set_add_pollset_set(exec_ctx, lb_policy->interested_parties,
-                                     chand->interested_parties);
-  }
-
-  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 */) {
-    grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures,
-                               NULL);
-  }
-  if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) {
-    GRPC_LB_POLICY_REF(lb_policy, "exit_idle");
-    exit_idle = 1;
-    chand->exit_idle_when_lb_policy_arrives = 0;
-  }
-
-  if (iomgr_success && chand->resolver) {
-    grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state,
-                                "new_lb+resolver");
-    if (lb_policy != NULL) {
-      watch_lb_policy(exec_ctx, chand, lb_policy, state);
-    }
-    GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
-    grpc_resolver_next(exec_ctx, chand->resolver,
-                       &chand->incoming_configuration,
-                       &chand->on_config_changed);
-    gpr_mu_unlock(&chand->mu_config);
-  } else {
-    if (chand->resolver != NULL) {
-      grpc_resolver_shutdown(exec_ctx, chand->resolver);
-      GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
-      chand->resolver = NULL;
-    }
-    grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
-                                GRPC_CHANNEL_FATAL_FAILURE, "resolver_gone");
-    gpr_mu_unlock(&chand->mu_config);
-  }
-
-  if (exit_idle) {
-    grpc_lb_policy_exit_idle(exec_ctx, lb_policy);
-    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "exit_idle");
-  }
-
-  if (old_lb_policy != NULL) {
-    grpc_pollset_set_del_pollset_set(
-        exec_ctx, old_lb_policy->interested_parties, chand->interested_parties);
-    GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel");
-  }
-
-  if (lb_policy != NULL) {
-    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "config_change");
-  }
-
-  GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver");
-}
-
-static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
-                                  grpc_channel_element *elem,
-                                  grpc_transport_op *op) {
-  channel_data *chand = elem->channel_data;
-
-  grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
-
-  GPR_ASSERT(op->set_accept_stream == false);
-  if (op->bind_pollset != NULL) {
-    grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties,
-                                 op->bind_pollset);
-  }
-
-  gpr_mu_lock(&chand->mu_config);
-  if (op->on_connectivity_state_change != NULL) {
-    grpc_connectivity_state_notify_on_state_change(
-        exec_ctx, &chand->state_tracker, op->connectivity_state,
-        op->on_connectivity_state_change);
-    op->on_connectivity_state_change = NULL;
-    op->connectivity_state = NULL;
-  }
-
-  if (op->send_ping != NULL) {
-    if (chand->lb_policy == NULL) {
-      grpc_exec_ctx_enqueue(exec_ctx, op->send_ping, false, NULL);
-    } else {
-      grpc_lb_policy_ping_one(exec_ctx, chand->lb_policy, op->send_ping);
-      op->bind_pollset = NULL;
-    }
-    op->send_ping = NULL;
-  }
-
-  if (op->disconnect && chand->resolver != NULL) {
-    grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
-                                GRPC_CHANNEL_FATAL_FAILURE, "disconnect");
-    grpc_resolver_shutdown(exec_ctx, chand->resolver);
-    GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
-    chand->resolver = NULL;
-    if (chand->lb_policy != NULL) {
-      grpc_pollset_set_del_pollset_set(exec_ctx,
-                                       chand->lb_policy->interested_parties,
-                                       chand->interested_parties);
-      GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
-      chand->lb_policy = NULL;
-    }
-  }
-  gpr_mu_unlock(&chand->mu_config);
-}
-
-typedef struct {
-  grpc_metadata_batch *initial_metadata;
-  grpc_connected_subchannel **connected_subchannel;
-  grpc_closure *on_ready;
-  grpc_call_element *elem;
-  grpc_closure closure;
-} continue_picking_args;
-
-static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
-                              grpc_metadata_batch *initial_metadata,
-                              grpc_connected_subchannel **connected_subchannel,
-                              grpc_closure *on_ready);
-
-static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  continue_picking_args *cpa = arg;
-  if (!success) {
-    grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL);
-  } else if (cpa->connected_subchannel == NULL) {
-    /* cancelled, do nothing */
-  } else if (cc_pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata,
-                                cpa->connected_subchannel, cpa->on_ready)) {
-    grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, true, NULL);
-  }
-  gpr_free(cpa);
-}
-
-static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
-                              grpc_metadata_batch *initial_metadata,
-                              grpc_connected_subchannel **connected_subchannel,
-                              grpc_closure *on_ready) {
-  grpc_call_element *elem = elemp;
-  channel_data *chand = elem->channel_data;
-  call_data *calld = elem->call_data;
-  continue_picking_args *cpa;
-  grpc_closure *closure;
-
-  GPR_ASSERT(connected_subchannel);
-
-  gpr_mu_lock(&chand->mu_config);
-  if (initial_metadata == NULL) {
-    if (chand->lb_policy != NULL) {
-      grpc_lb_policy_cancel_pick(exec_ctx, chand->lb_policy,
-                                 connected_subchannel);
-    }
-    for (closure = chand->waiting_for_config_closures.head; closure != NULL;
-         closure = grpc_closure_next(closure)) {
-      cpa = closure->cb_arg;
-      if (cpa->connected_subchannel == connected_subchannel) {
-        cpa->connected_subchannel = NULL;
-        grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL);
-      }
-    }
-    gpr_mu_unlock(&chand->mu_config);
-    return 1;
-  }
-  if (chand->lb_policy != NULL) {
-    grpc_lb_policy *lb_policy = chand->lb_policy;
-    int r;
-    GRPC_LB_POLICY_REF(lb_policy, "cc_pick_subchannel");
-    gpr_mu_unlock(&chand->mu_config);
-    r = grpc_lb_policy_pick(exec_ctx, lb_policy, calld->pollset,
-                            initial_metadata, connected_subchannel, on_ready);
-    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "cc_pick_subchannel");
-    return r;
-  }
-  if (chand->resolver != NULL && !chand->started_resolving) {
-    chand->started_resolving = 1;
-    GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
-    grpc_resolver_next(exec_ctx, chand->resolver,
-                       &chand->incoming_configuration,
-                       &chand->on_config_changed);
-  }
-  cpa = gpr_malloc(sizeof(*cpa));
-  cpa->initial_metadata = initial_metadata;
-  cpa->connected_subchannel = connected_subchannel;
-  cpa->on_ready = on_ready;
-  cpa->elem = elem;
-  grpc_closure_init(&cpa->closure, continue_picking, cpa);
-  grpc_closure_list_add(&chand->waiting_for_config_closures, &cpa->closure, 1);
-  gpr_mu_unlock(&chand->mu_config);
-  return 0;
-}
-
-/* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
-  grpc_subchannel_call_holder_init(elem->call_data, cc_pick_subchannel, elem,
-                                   args->call_stack);
-}
-
-/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {
-  grpc_subchannel_call_holder_destroy(exec_ctx, elem->call_data);
-}
-
-/* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
-  channel_data *chand = elem->channel_data;
-
-  memset(chand, 0, sizeof(*chand));
-
-  GPR_ASSERT(args->is_last);
-  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
-
-  gpr_mu_init(&chand->mu_config);
-  grpc_closure_init(&chand->on_config_changed, cc_on_config_changed, chand);
-  chand->owning_stack = args->channel_stack;
-
-  grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
-                               "client_channel");
-  chand->interested_parties = grpc_pollset_set_create();
-}
-
-/* Destructor for channel_data */
-static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem) {
-  channel_data *chand = elem->channel_data;
-
-  if (chand->resolver != NULL) {
-    grpc_resolver_shutdown(exec_ctx, chand->resolver);
-    GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
-  }
-  if (chand->lb_policy != NULL) {
-    grpc_pollset_set_del_pollset_set(exec_ctx,
-                                     chand->lb_policy->interested_parties,
-                                     chand->interested_parties);
-    GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
-  }
-  grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
-  grpc_pollset_set_destroy(chand->interested_parties);
-  gpr_mu_destroy(&chand->mu_config);
-}
-
-static void cc_set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_pollset *pollset) {
-  call_data *calld = elem->call_data;
-  calld->pollset = pollset;
-}
-
-const grpc_channel_filter grpc_client_channel_filter = {
-    cc_start_transport_stream_op, cc_start_transport_op, sizeof(call_data),
-    init_call_elem, cc_set_pollset, destroy_call_elem, sizeof(channel_data),
-    init_channel_elem, destroy_channel_elem, cc_get_peer, "client-channel",
-};
-
-void grpc_client_channel_set_resolver(grpc_exec_ctx *exec_ctx,
-                                      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_mu_lock(&chand->mu_config);
-  GPR_ASSERT(!chand->resolver);
-  chand->resolver = resolver;
-  GRPC_RESOLVER_REF(resolver, "channel");
-  if (!grpc_closure_list_empty(chand->waiting_for_config_closures) ||
-      chand->exit_idle_when_lb_policy_arrives) {
-    chand->started_resolving = 1;
-    GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
-    grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration,
-                       &chand->on_config_changed);
-  }
-  gpr_mu_unlock(&chand->mu_config);
-}
-
-grpc_connectivity_state grpc_client_channel_check_connectivity_state(
-    grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) {
-  channel_data *chand = elem->channel_data;
-  grpc_connectivity_state out;
-  gpr_mu_lock(&chand->mu_config);
-  out = grpc_connectivity_state_check(&chand->state_tracker);
-  if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
-    if (chand->lb_policy != NULL) {
-      grpc_lb_policy_exit_idle(exec_ctx, chand->lb_policy);
-    } else {
-      chand->exit_idle_when_lb_policy_arrives = 1;
-      if (!chand->started_resolving && chand->resolver != NULL) {
-        GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
-        chand->started_resolving = 1;
-        grpc_resolver_next(exec_ctx, chand->resolver,
-                           &chand->incoming_configuration,
-                           &chand->on_config_changed);
-      }
-    }
-  }
-  gpr_mu_unlock(&chand->mu_config);
-  return out;
-}
-
-typedef struct {
-  channel_data *chand;
-  grpc_pollset *pollset;
-  grpc_closure *on_complete;
-  grpc_closure my_closure;
-} external_connectivity_watcher;
-
-static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
-                                       bool iomgr_success) {
-  external_connectivity_watcher *w = arg;
-  grpc_closure *follow_up = w->on_complete;
-  grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties,
-                               w->pollset);
-  GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
-                           "external_connectivity_watcher");
-  gpr_free(w);
-  follow_up->cb(exec_ctx, follow_up->cb_arg, iomgr_success);
-}
-
-void grpc_client_channel_watch_connectivity_state(
-    grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
-    grpc_connectivity_state *state, grpc_closure *on_complete) {
-  channel_data *chand = elem->channel_data;
-  external_connectivity_watcher *w = gpr_malloc(sizeof(*w));
-  w->chand = chand;
-  w->pollset = pollset;
-  w->on_complete = on_complete;
-  grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, pollset);
-  grpc_closure_init(&w->my_closure, on_external_watch_complete, w);
-  GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
-                         "external_connectivity_watcher");
-  gpr_mu_lock(&chand->mu_config);
-  grpc_connectivity_state_notify_on_state_change(
-      exec_ctx, &chand->state_tracker, state, &w->my_closure);
-  gpr_mu_unlock(&chand->mu_config);
-}
diff --git a/src/core/channel/client_channel.h b/src/core/channel/client_channel.h
deleted file mode 100644
index d9bc497..0000000
--- a/src/core/channel/client_channel.h
+++ /dev/null
@@ -1,63 +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_CHANNEL_H
-#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
-   connected to again later.
-
-   Calls on a disconnected client channel are queued until a connection is
-   established. */
-
-extern const grpc_channel_filter grpc_client_channel_filter;
-
-/* 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_resolver(grpc_exec_ctx *exec_ctx,
-                                      grpc_channel_stack *channel_stack,
-                                      grpc_resolver *resolver);
-
-grpc_connectivity_state grpc_client_channel_check_connectivity_state(
-    grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect);
-
-void grpc_client_channel_watch_connectivity_state(
-    grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
-    grpc_connectivity_state *state, grpc_closure *on_complete);
-
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */
diff --git a/src/core/channel/client_uchannel.c b/src/core/channel/client_uchannel.c
deleted file mode 100644
index 83fcc3a..0000000
--- a/src/core/channel/client_uchannel.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/channel/client_uchannel.h"
-
-#include <string.h>
-
-#include "src/core/census/grpc_filter.h"
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/client_channel.h"
-#include "src/core/channel/compress_filter.h"
-#include "src/core/channel/subchannel_call_holder.h"
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/support/string.h"
-#include "src/core/surface/channel.h"
-#include "src/core/transport/connectivity_state.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
-
-/** Microchannel (uchannel) implementation: a lightweight channel without any
- * load-balancing mechanisms meant for communication from within the core. */
-
-typedef struct client_uchannel_channel_data {
-  /** 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_stack *owning_stack;
-
-  /** connectivity state being tracked */
-  grpc_connectivity_state_tracker state_tracker;
-
-  /** the subchannel wrapped by the microchannel */
-  grpc_connected_subchannel *connected_subchannel;
-
-  /** the callback used to stay subscribed to subchannel connectivity
-   * notifications */
-  grpc_closure connectivity_cb;
-
-  /** the current connectivity state of the wrapped subchannel */
-  grpc_connectivity_state subchannel_connectivity;
-
-  gpr_mu mu_state;
-} channel_data;
-
-typedef grpc_subchannel_call_holder call_data;
-
-static void monitor_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
-                               bool iomgr_success) {
-  channel_data *chand = arg;
-  grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
-                              chand->subchannel_connectivity,
-                              "uchannel_monitor_subchannel");
-  grpc_connected_subchannel_notify_on_state_change(
-      exec_ctx, chand->connected_subchannel, NULL,
-      &chand->subchannel_connectivity, &chand->connectivity_cb);
-}
-
-static char *cuc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
-  return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data);
-}
-
-static void cuc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                          grpc_call_element *elem,
-                                          grpc_transport_stream_op *op) {
-  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-  grpc_subchannel_call_holder_perform_op(exec_ctx, elem->call_data, op);
-}
-
-static void cuc_start_transport_op(grpc_exec_ctx *exec_ctx,
-                                   grpc_channel_element *elem,
-                                   grpc_transport_op *op) {
-  channel_data *chand = elem->channel_data;
-
-  grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
-
-  GPR_ASSERT(op->set_accept_stream == false);
-  GPR_ASSERT(op->bind_pollset == NULL);
-
-  if (op->on_connectivity_state_change != NULL) {
-    grpc_connectivity_state_notify_on_state_change(
-        exec_ctx, &chand->state_tracker, op->connectivity_state,
-        op->on_connectivity_state_change);
-    op->on_connectivity_state_change = NULL;
-    op->connectivity_state = NULL;
-  }
-
-  if (op->disconnect) {
-    grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
-                                GRPC_CHANNEL_FATAL_FAILURE, "disconnect");
-  }
-}
-
-static int cuc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
-                               grpc_metadata_batch *initial_metadata,
-                               grpc_connected_subchannel **connected_subchannel,
-                               grpc_closure *on_ready) {
-  channel_data *chand = arg;
-  GPR_ASSERT(initial_metadata != NULL);
-  *connected_subchannel = chand->connected_subchannel;
-  return 1;
-}
-
-/* Constructor for call_data */
-static void cuc_init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                               grpc_call_element_args *args) {
-  grpc_subchannel_call_holder_init(elem->call_data, cuc_pick_subchannel,
-                                   elem->channel_data, args->call_stack);
-}
-
-/* Destructor for call_data */
-static void cuc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                                  grpc_call_element *elem) {
-  grpc_subchannel_call_holder_destroy(exec_ctx, elem->call_data);
-}
-
-/* Constructor for channel_data */
-static void cuc_init_channel_elem(grpc_exec_ctx *exec_ctx,
-                                  grpc_channel_element *elem,
-                                  grpc_channel_element_args *args) {
-  channel_data *chand = elem->channel_data;
-  memset(chand, 0, sizeof(*chand));
-  grpc_closure_init(&chand->connectivity_cb, monitor_subchannel, chand);
-  GPR_ASSERT(args->is_last);
-  GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter);
-  chand->owning_stack = args->channel_stack;
-  grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
-                               "client_uchannel");
-  gpr_mu_init(&chand->mu_state);
-}
-
-/* Destructor for channel_data */
-static void cuc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
-                                     grpc_channel_element *elem) {
-  channel_data *chand = elem->channel_data;
-  /* cancel subscription */
-  grpc_connected_subchannel_notify_on_state_change(
-      exec_ctx, chand->connected_subchannel, NULL, NULL,
-      &chand->connectivity_cb);
-  grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
-  gpr_mu_destroy(&chand->mu_state);
-  GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, chand->connected_subchannel,
-                                  "uchannel");
-}
-
-static void cuc_set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                            grpc_pollset *pollset) {
-  call_data *calld = elem->call_data;
-  calld->pollset = pollset;
-}
-
-const grpc_channel_filter grpc_client_uchannel_filter = {
-    cuc_start_transport_stream_op, cuc_start_transport_op, sizeof(call_data),
-    cuc_init_call_elem, cuc_set_pollset, cuc_destroy_call_elem,
-    sizeof(channel_data), cuc_init_channel_elem, cuc_destroy_channel_elem,
-    cuc_get_peer, "client-uchannel",
-};
-
-grpc_connectivity_state grpc_client_uchannel_check_connectivity_state(
-    grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) {
-  channel_data *chand = elem->channel_data;
-  grpc_connectivity_state out;
-  gpr_mu_lock(&chand->mu_state);
-  out = grpc_connectivity_state_check(&chand->state_tracker);
-  gpr_mu_unlock(&chand->mu_state);
-  return out;
-}
-
-void grpc_client_uchannel_watch_connectivity_state(
-    grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
-    grpc_connectivity_state *state, grpc_closure *on_complete) {
-  channel_data *chand = elem->channel_data;
-  gpr_mu_lock(&chand->mu_state);
-  grpc_connectivity_state_notify_on_state_change(
-      exec_ctx, &chand->state_tracker, state, on_complete);
-  gpr_mu_unlock(&chand->mu_state);
-}
-
-grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel,
-                                          grpc_channel_args *args) {
-  grpc_channel *channel = NULL;
-#define MAX_FILTERS 3
-  const grpc_channel_filter *filters[MAX_FILTERS];
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  size_t n = 0;
-
-  if (grpc_channel_args_is_census_enabled(args)) {
-    filters[n++] = &grpc_client_census_filter;
-  }
-  filters[n++] = &grpc_compress_filter;
-  filters[n++] = &grpc_client_uchannel_filter;
-  GPR_ASSERT(n <= MAX_FILTERS);
-
-  channel =
-      grpc_channel_create_from_filters(&exec_ctx, NULL, filters, n, args, 1);
-
-  return channel;
-}
-
-void grpc_client_uchannel_set_connected_subchannel(
-    grpc_channel *uchannel, grpc_connected_subchannel *connected_subchannel) {
-  grpc_channel_element *elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(uchannel));
-  channel_data *chand = elem->channel_data;
-  GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter);
-  gpr_mu_lock(&chand->mu_state);
-  chand->connected_subchannel = connected_subchannel;
-  GRPC_CONNECTED_SUBCHANNEL_REF(connected_subchannel, "uchannel");
-  gpr_mu_unlock(&chand->mu_state);
-}
diff --git a/src/core/channel/client_uchannel.h b/src/core/channel/client_uchannel.h
deleted file mode 100644
index 92a8314..0000000
--- a/src/core/channel/client_uchannel.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CHANNEL_CLIENT_MICROCHANNEL_H
-#define GRPC_INTERNAL_CORE_CHANNEL_CLIENT_MICROCHANNEL_H
-
-#include "src/core/channel/channel_stack.h"
-#include "src/core/client_config/resolver.h"
-
-#define GRPC_MICROCHANNEL_SUBCHANNEL_ARG "grpc.microchannel_subchannel_key"
-
-/* A client microchannel (aka uchannel) is a channel wrapping a subchannel, for
- * the purposes of lightweight RPC communications from within the core.*/
-
-extern const grpc_channel_filter grpc_client_uchannel_filter;
-
-grpc_connectivity_state grpc_client_uchannel_check_connectivity_state(
-    grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect);
-
-void grpc_client_uchannel_watch_connectivity_state(
-    grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
-    grpc_connectivity_state *state, grpc_closure *on_complete);
-
-grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel,
-                                          grpc_channel_args *args);
-
-void grpc_client_uchannel_set_connected_subchannel(
-    grpc_channel *uchannel, grpc_connected_subchannel *connected_subchannel);
-
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_MICROCHANNEL_H */
diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c
deleted file mode 100644
index 3e7ca08..0000000
--- a/src/core/channel/compress_filter.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <assert.h>
-#include <string.h>
-
-#include <grpc/compression.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
-
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/compress_filter.h"
-#include "src/core/compression/algorithm_metadata.h"
-#include "src/core/compression/message_compress.h"
-#include "src/core/profiling/timers.h"
-#include "src/core/support/string.h"
-#include "src/core/transport/static_metadata.h"
-
-typedef struct call_data {
-  gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */
-  grpc_linked_mdelem compression_algorithm_storage;
-  grpc_linked_mdelem accept_encoding_storage;
-  uint32_t remaining_slice_bytes;
-  /** 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;
-
-  grpc_transport_stream_op send_op;
-  uint32_t send_length;
-  uint32_t send_flags;
-  gpr_slice incoming_slice;
-  grpc_slice_buffer_stream replacement_stream;
-  grpc_closure *post_send;
-  grpc_closure send_done;
-  grpc_closure got_slice;
-} call_data;
-
-typedef struct channel_data {
-  /** The default, channel-level, compression algorithm */
-  grpc_compression_algorithm default_compression_algorithm;
-  /** Compression options for the channel */
-  grpc_compression_options compression_options;
-  /** Supported compression algorithms */
-  uint32_t supported_compression_algorithms;
-} channel_data;
-
-/** 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 == GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST) {
-    const char *md_c_str = grpc_mdstr_as_c_string(md->value);
-    if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
-                                          &calld->compression_algorithm)) {
-      gpr_log(GPR_ERROR,
-              "Invalid compression algorithm: '%s' (unknown). Ignoring.",
-              md_c_str);
-      calld->compression_algorithm = GRPC_COMPRESS_NONE;
-    }
-    if (grpc_compression_options_is_algorithm_enabled(
-            &channeld->compression_options, calld->compression_algorithm) ==
-        0) {
-      gpr_log(GPR_ERROR,
-              "Invalid compression algorithm: '%s' (previously disabled). "
-              "Ignoring.",
-              md_c_str);
-      calld->compression_algorithm = GRPC_COMPRESS_NONE;
-    }
-    calld->has_compression_algorithm = 1;
-    return NULL;
-  }
-
-  return md;
-}
-
-static int skip_compression(grpc_call_element *elem) {
-  call_data *calld = elem->call_data;
-  channel_data *channeld = elem->channel_data;
-  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;
-}
-
-/** Filter initial metadata */
-static void process_send_initial_metadata(
-    grpc_call_element *elem, grpc_metadata_batch *initial_metadata) {
-  call_data *calld = elem->call_data;
-  channel_data *channeld = elem->channel_data;
-  /* Parse incoming request for compression. If any, it'll be available
-   * at calld->compression_algorithm */
-  grpc_metadata_batch_filter(initial_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 */
-  }
-  /* hint compression algorithm */
-  grpc_metadata_batch_add_tail(
-      initial_metadata, &calld->compression_algorithm_storage,
-      grpc_compression_encoding_mdelem(calld->compression_algorithm));
-
-  /* convey supported compression algorithms */
-  grpc_metadata_batch_add_tail(initial_metadata,
-                               &calld->accept_encoding_storage,
-                               GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(
-                                   channeld->supported_compression_algorithms));
-}
-
-static void continue_send_message(grpc_exec_ctx *exec_ctx,
-                                  grpc_call_element *elem);
-
-static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, bool success) {
-  grpc_call_element *elem = elemp;
-  call_data *calld = elem->call_data;
-  gpr_slice_buffer_reset_and_unref(&calld->slices);
-  calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, success);
-}
-
-static void finish_send_message(grpc_exec_ctx *exec_ctx,
-                                grpc_call_element *elem) {
-  call_data *calld = elem->call_data;
-  int did_compress;
-  gpr_slice_buffer tmp;
-  gpr_slice_buffer_init(&tmp);
-  did_compress =
-      grpc_msg_compress(calld->compression_algorithm, &calld->slices, &tmp);
-  if (did_compress) {
-    gpr_slice_buffer_swap(&calld->slices, &tmp);
-    calld->send_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
-  }
-  gpr_slice_buffer_destroy(&tmp);
-
-  grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
-                                calld->send_flags);
-  calld->send_op.send_message = &calld->replacement_stream.base;
-  calld->post_send = calld->send_op.on_complete;
-  calld->send_op.on_complete = &calld->send_done;
-
-  grpc_call_next_op(exec_ctx, elem, &calld->send_op);
-}
-
-static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, bool success) {
-  grpc_call_element *elem = elemp;
-  call_data *calld = elem->call_data;
-  gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
-  if (calld->send_length == calld->slices.length) {
-    finish_send_message(exec_ctx, elem);
-  } else {
-    continue_send_message(exec_ctx, elem);
-  }
-}
-
-static void continue_send_message(grpc_exec_ctx *exec_ctx,
-                                  grpc_call_element *elem) {
-  call_data *calld = elem->call_data;
-  while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message,
-                               &calld->incoming_slice, ~(size_t)0,
-                               &calld->got_slice)) {
-    gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
-    if (calld->send_length == calld->slices.length) {
-      finish_send_message(exec_ctx, elem);
-      break;
-    }
-  }
-}
-
-static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                               grpc_call_element *elem,
-                                               grpc_transport_stream_op *op) {
-  call_data *calld = elem->call_data;
-
-  GPR_TIMER_BEGIN("compress_start_transport_stream_op", 0);
-
-  if (op->send_initial_metadata) {
-    process_send_initial_metadata(elem, op->send_initial_metadata);
-  }
-  if (op->send_message != NULL && !skip_compression(elem) &&
-      0 == (op->send_message->flags & GRPC_WRITE_NO_COMPRESS)) {
-    calld->send_op = *op;
-    calld->send_length = op->send_message->length;
-    calld->send_flags = op->send_message->flags;
-    continue_send_message(exec_ctx, elem);
-  } else {
-    /* pass control down the stack */
-    grpc_call_next_op(exec_ctx, elem, op);
-  }
-
-  GPR_TIMER_END("compress_start_transport_stream_op", 0);
-}
-
-/* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
-  /* 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;
-  grpc_closure_init(&calld->got_slice, got_slice, elem);
-  grpc_closure_init(&calld->send_done, send_done, elem);
-}
-
-/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              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_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
-  channel_data *channeld = elem->channel_data;
-  grpc_compression_algorithm algo_idx;
-
-  grpc_compression_options_init(&channeld->compression_options);
-  channeld->compression_options.enabled_algorithms_bitset =
-      (uint32_t)grpc_channel_args_compression_algorithm_get_states(
-          args->channel_args);
-
-  channeld->default_compression_algorithm =
-      grpc_channel_args_get_compression_algorithm(args->channel_args);
-  /* Make sure the default isn't disabled. */
-  GPR_ASSERT(grpc_compression_options_is_algorithm_enabled(
-      &channeld->compression_options, channeld->default_compression_algorithm));
-  channeld->compression_options.default_compression_algorithm =
-      channeld->default_compression_algorithm;
-
-  channeld->supported_compression_algorithms = 0;
-  for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
-    /* skip disabled algorithms */
-    if (grpc_compression_options_is_algorithm_enabled(
-            &channeld->compression_options, algo_idx) == 0) {
-      continue;
-    }
-    channeld->supported_compression_algorithms |= 1u << algo_idx;
-  }
-
-  GPR_ASSERT(!args->is_last);
-}
-
-/* Destructor for channel data */
-static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem) {}
-
-const grpc_channel_filter grpc_compress_filter = {
-    compress_start_transport_stream_op, grpc_channel_next_op, sizeof(call_data),
-    init_call_elem, grpc_call_stack_ignore_set_pollset, destroy_call_elem,
-    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
-    grpc_call_next_get_peer, "compress"};
diff --git a/src/core/channel/compress_filter.h b/src/core/channel/compress_filter.h
deleted file mode 100644
index 415459b..0000000
--- a/src/core/channel/compress_filter.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_COMPRESS_FILTER_H
-#define GRPC_INTERNAL_CORE_CHANNEL_COMPRESS_FILTER_H
-
-#include "src/core/channel/channel_stack.h"
-
-#define GRPC_COMPRESS_REQUEST_ALGORITHM_KEY "grpc-internal-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
deleted file mode 100644
index e8eb9dc..0000000
--- a/src/core/channel/connected_channel.c
+++ /dev/null
@@ -1,167 +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/connected_channel.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "src/core/support/string.h"
-#include "src/core/transport/transport.h"
-#include "src/core/profiling/timers.h"
-#include <grpc/byte_buffer.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
-
-#define MAX_BUFFER_LENGTH 8192
-
-typedef struct connected_channel_channel_data {
-  grpc_transport *transport;
-} channel_data;
-
-typedef struct connected_channel_call_data { void *unused; } call_data;
-
-/* We perform a small hack to locate transport data alongside the connected
-   channel data in call allocations, to allow everything to be pulled in minimal
-   cache line requests */
-#define TRANSPORT_STREAM_FROM_CALL_DATA(calld) ((grpc_stream *)((calld) + 1))
-#define CALL_DATA_FROM_TRANSPORT_STREAM(transport_stream) \
-  (((call_data *)(transport_stream)) - 1)
-
-/* Intercept a call operation and either push it directly up or translate it
-   into transport stream operations */
-static void con_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                          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_stream_op(exec_ctx, chand->transport,
-                                   TRANSPORT_STREAM_FROM_CALL_DATA(calld), op);
-}
-
-static void con_start_transport_op(grpc_exec_ctx *exec_ctx,
-                                   grpc_channel_element *elem,
-                                   grpc_transport_op *op) {
-  channel_data *chand = elem->channel_data;
-  grpc_transport_perform_op(exec_ctx, chand->transport, op);
-}
-
-/* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
-  call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
-  int r;
-
-  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
-  r = grpc_transport_init_stream(
-      exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld),
-      &args->call_stack->refcount, args->server_transport_data);
-  GPR_ASSERT(r == 0);
-}
-
-static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                        grpc_pollset *pollset) {
-  call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
-  grpc_transport_set_pollset(exec_ctx, chand->transport,
-                             TRANSPORT_STREAM_FROM_CALL_DATA(calld), pollset);
-}
-
-/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {
-  call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
-  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
-  grpc_transport_destroy_stream(exec_ctx, chand->transport,
-                                TRANSPORT_STREAM_FROM_CALL_DATA(calld));
-}
-
-/* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
-  channel_data *cd = (channel_data *)elem->channel_data;
-  GPR_ASSERT(args->is_last);
-  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
-  cd->transport = NULL;
-}
-
-/* Destructor for channel_data */
-static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem) {
-  channel_data *cd = (channel_data *)elem->channel_data;
-  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
-  grpc_transport_destroy(exec_ctx, cd->transport);
-}
-
-static char *con_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
-  channel_data *chand = elem->channel_data;
-  return grpc_transport_get_peer(exec_ctx, chand->transport);
-}
-
-const grpc_channel_filter grpc_connected_channel_filter = {
-    con_start_transport_stream_op, con_start_transport_op, sizeof(call_data),
-    init_call_elem, set_pollset, destroy_call_elem, sizeof(channel_data),
-    init_channel_elem, destroy_channel_elem, con_get_peer, "connected",
-};
-
-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;
-  GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
-  GPR_ASSERT(cd->transport == NULL);
-  cd->transport = transport;
-
-  /* HACK(ctiller): increase call stack size for the channel to make space
-     for channel data. We need a cleaner (but performant) way to do this,
-     and I'm not sure what that is yet.
-     This is only "safe" because call stacks place no additional data after
-     the last call element, and the last call element MUST be the connected
-     channel. */
-  channel_stack->call_stack_size += grpc_transport_stream_size(transport);
-}
-
-grpc_stream *grpc_connected_channel_get_stream(grpc_call_element *elem) {
-  call_data *calld = elem->call_data;
-  return TRANSPORT_STREAM_FROM_CALL_DATA(calld);
-}
diff --git a/src/core/channel/connected_channel.h b/src/core/channel/connected_channel.h
deleted file mode 100644
index 95c1834..0000000
--- a/src/core/channel/connected_channel.h
+++ /dev/null
@@ -1,51 +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_CONNECTED_CHANNEL_H
-#define GRPC_INTERNAL_CORE_CHANNEL_CONNECTED_CHANNEL_H
-
-#include "src/core/channel/channel_stack.h"
-
-/* A channel filter representing a channel that is on a connected transport.
-   This filter performs actual sending and receiving of messages. */
-
-extern const grpc_channel_filter grpc_connected_channel_filter;
-
-/* Post construction fixup: set the transport in the connected channel.
-   Must be called before any call stack using this filter is used. */
-void grpc_connected_channel_bind_transport(grpc_channel_stack* channel_stack,
-                                           grpc_transport* transport);
-
-grpc_stream* grpc_connected_channel_get_stream(grpc_call_element* elem);
-
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_CONNECTED_CHANNEL_H */
diff --git a/src/core/channel/context.h b/src/core/channel/context.h
deleted file mode 100644
index ac5796b..0000000
--- a/src/core/channel/context.h
+++ /dev/null
@@ -1,49 +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_CONTEXT_H
-#define GRPC_INTERNAL_CORE_CHANNEL_CONTEXT_H
-
-/* Call object context pointers */
-typedef enum {
-  GRPC_CONTEXT_SECURITY = 0,
-  GRPC_CONTEXT_TRACING,
-  GRPC_CONTEXT_COUNT
-} grpc_context_index;
-
-typedef struct {
-  void *value;
-  void (*destroy)(void *);
-} grpc_call_context_element;
-
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_CONTEXT_H */
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
deleted file mode 100644
index 1aa2720..0000000
--- a/src/core/channel/http_client_filter.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/channel/http_client_filter.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <string.h>
-#include "src/core/profiling/timers.h"
-#include "src/core/support/string.h"
-#include "src/core/transport/static_metadata.h"
-
-typedef struct call_data {
-  grpc_linked_mdelem method;
-  grpc_linked_mdelem scheme;
-  grpc_linked_mdelem authority;
-  grpc_linked_mdelem te_trailers;
-  grpc_linked_mdelem content_type;
-  grpc_linked_mdelem user_agent;
-
-  grpc_metadata_batch *recv_initial_metadata;
-
-  /** Closure to call when finished with the hc_on_recv hook */
-  grpc_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_closure hc_on_recv;
-} call_data;
-
-typedef struct channel_data {
-  grpc_mdelem *static_scheme;
-  grpc_mdelem *user_agent;
-} channel_data;
-
-typedef struct {
-  grpc_call_element *elem;
-  grpc_exec_ctx *exec_ctx;
-} client_recv_filter_args;
-
-static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
-  client_recv_filter_args *a = user_data;
-  if (md == GRPC_MDELEM_STATUS_200) {
-    return NULL;
-  } else if (md->key == GRPC_MDSTR_STATUS) {
-    grpc_call_element_send_cancel(a->exec_ctx, a->elem);
-    return NULL;
-  } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
-    return NULL;
-  }
-  return md;
-}
-
-static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
-  grpc_call_element *elem = user_data;
-  call_data *calld = elem->call_data;
-  client_recv_filter_args a;
-  a.elem = elem;
-  a.exec_ctx = exec_ctx;
-  grpc_metadata_batch_filter(calld->recv_initial_metadata, client_recv_filter,
-                             &a);
-  calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success);
-}
-
-static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
-  /* eat the things we'd like to set ourselves */
-  if (md->key == GRPC_MDSTR_METHOD) return NULL;
-  if (md->key == GRPC_MDSTR_SCHEME) return NULL;
-  if (md->key == GRPC_MDSTR_TE) return NULL;
-  if (md->key == GRPC_MDSTR_CONTENT_TYPE) return NULL;
-  if (md->key == GRPC_MDSTR_USER_AGENT) return NULL;
-  return md;
-}
-
-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;
-  if (op->send_initial_metadata != NULL) {
-    grpc_metadata_batch_filter(op->send_initial_metadata, client_strip_filter,
-                               elem);
-    /* Send : prefixed headers, which have to be before any application
-       layer headers. */
-    grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method,
-                                 GRPC_MDELEM_METHOD_POST);
-    grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme,
-                                 channeld->static_scheme);
-    grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers,
-                                 GRPC_MDELEM_TE_TRAILERS);
-    grpc_metadata_batch_add_tail(
-        op->send_initial_metadata, &calld->content_type,
-        GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
-    grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->user_agent,
-                                 GRPC_MDELEM_REF(channeld->user_agent));
-  }
-
-  if (op->recv_initial_metadata != NULL) {
-    /* substitute our callback for the higher callback */
-    calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready = &calld->hc_on_recv;
-  }
-}
-
-static void hc_start_transport_op(grpc_exec_ctx *exec_ctx,
-                                  grpc_call_element *elem,
-                                  grpc_transport_stream_op *op) {
-  GPR_TIMER_BEGIN("hc_start_transport_op", 0);
-  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-  hc_mutate_op(elem, op);
-  GPR_TIMER_END("hc_start_transport_op", 0);
-  grpc_call_next_op(exec_ctx, elem, op);
-}
-
-/* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
-  call_data *calld = elem->call_data;
-  calld->on_done_recv = NULL;
-  grpc_closure_init(&calld->hc_on_recv, hc_on_recv, elem);
-}
-
-/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {}
-
-static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
-  unsigned i;
-  size_t j;
-  grpc_mdelem *valid_schemes[] = {GRPC_MDELEM_SCHEME_HTTP,
-                                  GRPC_MDELEM_SCHEME_HTTPS};
-  if (args != NULL) {
-    for (i = 0; i < args->num_args; ++i) {
-      if (args->args[i].type == GRPC_ARG_STRING &&
-          strcmp(args->args[i].key, GRPC_ARG_HTTP2_SCHEME) == 0) {
-        for (j = 0; j < GPR_ARRAY_SIZE(valid_schemes); j++) {
-          if (0 == strcmp(grpc_mdstr_as_c_string(valid_schemes[j]->value),
-                          args->args[i].value.string)) {
-            return valid_schemes[j];
-          }
-        }
-      }
-    }
-  }
-  return GRPC_MDELEM_SCHEME_HTTP;
-}
-
-static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args) {
-  gpr_strvec v;
-  size_t i;
-  int is_first = 1;
-  char *tmp;
-  grpc_mdstr *result;
-
-  gpr_strvec_init(&v);
-
-  for (i = 0; args && i < args->num_args; i++) {
-    if (0 == strcmp(args->args[i].key, GRPC_ARG_PRIMARY_USER_AGENT_STRING)) {
-      if (args->args[i].type != GRPC_ARG_STRING) {
-        gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
-                GRPC_ARG_PRIMARY_USER_AGENT_STRING);
-      } else {
-        if (!is_first) gpr_strvec_add(&v, gpr_strdup(" "));
-        is_first = 0;
-        gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string));
-      }
-    }
-  }
-
-  gpr_asprintf(&tmp, "%sgrpc-c/%s (%s)", is_first ? "" : " ",
-               grpc_version_string(), GPR_PLATFORM_STRING);
-  is_first = 0;
-  gpr_strvec_add(&v, tmp);
-
-  for (i = 0; args && i < args->num_args; i++) {
-    if (0 == strcmp(args->args[i].key, GRPC_ARG_SECONDARY_USER_AGENT_STRING)) {
-      if (args->args[i].type != GRPC_ARG_STRING) {
-        gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
-                GRPC_ARG_SECONDARY_USER_AGENT_STRING);
-      } else {
-        if (!is_first) gpr_strvec_add(&v, gpr_strdup(" "));
-        is_first = 0;
-        gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string));
-      }
-    }
-  }
-
-  tmp = gpr_strvec_flatten(&v, NULL);
-  gpr_strvec_destroy(&v);
-  result = grpc_mdstr_from_string(tmp);
-  gpr_free(tmp);
-
-  return result;
-}
-
-/* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
-  channel_data *chand = elem->channel_data;
-  GPR_ASSERT(!args->is_last);
-  chand->static_scheme = scheme_from_args(args->channel_args);
-  chand->user_agent = grpc_mdelem_from_metadata_strings(
-      GRPC_MDSTR_USER_AGENT, user_agent_from_args(args->channel_args));
-}
-
-/* Destructor for channel data */
-static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem) {
-  channel_data *chand = elem->channel_data;
-  GRPC_MDELEM_UNREF(chand->user_agent);
-}
-
-const grpc_channel_filter grpc_http_client_filter = {
-    hc_start_transport_op, grpc_channel_next_op, sizeof(call_data),
-    init_call_elem, grpc_call_stack_ignore_set_pollset, destroy_call_elem,
-    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
-    grpc_call_next_get_peer, "http-client"};
diff --git a/src/core/channel/http_client_filter.h b/src/core/channel/http_client_filter.h
deleted file mode 100644
index 21c66b9..0000000
--- a/src/core/channel/http_client_filter.h
+++ /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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CHANNEL_HTTP_CLIENT_FILTER_H
-#define GRPC_INTERNAL_CORE_CHANNEL_HTTP_CLIENT_FILTER_H
-
-#include "src/core/channel/channel_stack.h"
-
-/* Processes metadata on the client side for HTTP2 transports */
-extern const grpc_channel_filter grpc_http_client_filter;
-
-#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme"
-
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_CLIENT_FILTER_H */
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
deleted file mode 100644
index 370f8db..0000000
--- a/src/core/channel/http_server_filter.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/channel/http_server_filter.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <string.h>
-#include "src/core/profiling/timers.h"
-#include "src/core/transport/static_metadata.h"
-
-typedef struct call_data {
-  uint8_t seen_path;
-  uint8_t seen_post;
-  uint8_t sent_status;
-  uint8_t seen_scheme;
-  uint8_t seen_te_trailers;
-  uint8_t seen_authority;
-  grpc_linked_mdelem status;
-  grpc_linked_mdelem content_type;
-
-  grpc_metadata_batch *recv_initial_metadata;
-  /** Closure to call when finished with the hs_on_recv hook */
-  grpc_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_closure hs_on_recv;
-} call_data;
-
-typedef struct channel_data { uint8_t unused; } channel_data;
-
-typedef struct {
-  grpc_call_element *elem;
-  grpc_exec_ctx *exec_ctx;
-} server_filter_args;
-
-static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
-  server_filter_args *a = user_data;
-  grpc_call_element *elem = a->elem;
-  call_data *calld = elem->call_data;
-
-  /* Check if it is one of the headers we care about. */
-  if (md == GRPC_MDELEM_TE_TRAILERS || md == GRPC_MDELEM_METHOD_POST ||
-      md == GRPC_MDELEM_SCHEME_HTTP || md == GRPC_MDELEM_SCHEME_HTTPS ||
-      md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
-    /* swallow it */
-    if (md == GRPC_MDELEM_METHOD_POST) {
-      calld->seen_post = 1;
-    } else if (md->key == GRPC_MDSTR_SCHEME) {
-      calld->seen_scheme = 1;
-    } else if (md == GRPC_MDELEM_TE_TRAILERS) {
-      calld->seen_te_trailers = 1;
-    }
-    /* TODO(klempner): Track that we've seen all the headers we should
-       require */
-    return NULL;
-  } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
-    if (strncmp(grpc_mdstr_as_c_string(md->value), "application/grpc+", 17) ==
-        0) {
-      /* Although the C implementation doesn't (currently) generate them,
-         any custom +-suffix is explicitly valid. */
-      /* TODO(klempner): We should consider preallocating common values such
-         as +proto or +json, or at least stashing them if we see them. */
-      /* TODO(klempner): Should we be surfacing this to application code? */
-    } else {
-      /* TODO(klempner): We're currently allowing this, but we shouldn't
-         see it without a proxy so log for now. */
-      gpr_log(GPR_INFO, "Unexpected content-type %s",
-              grpc_mdstr_as_c_string(md->value));
-    }
-    return NULL;
-  } else if (md->key == GRPC_MDSTR_TE || md->key == GRPC_MDSTR_METHOD ||
-             md->key == GRPC_MDSTR_SCHEME) {
-    gpr_log(GPR_ERROR, "Invalid %s: header: '%s'",
-            grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value));
-    /* swallow it and error everything out. */
-    /* TODO(klempner): We ought to generate more descriptive error messages
-       on the wire here. */
-    grpc_call_element_send_cancel(a->exec_ctx, elem);
-    return NULL;
-  } else if (md->key == GRPC_MDSTR_PATH) {
-    if (calld->seen_path) {
-      gpr_log(GPR_ERROR, "Received :path twice");
-      return NULL;
-    }
-    calld->seen_path = 1;
-    return md;
-  } else if (md->key == GRPC_MDSTR_AUTHORITY) {
-    calld->seen_authority = 1;
-    return md;
-  } else if (md->key == GRPC_MDSTR_HOST) {
-    /* translate host to :authority since :authority may be
-       omitted */
-    grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
-        GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value));
-    calld->seen_authority = 1;
-    return authority;
-  } else {
-    return md;
-  }
-}
-
-static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
-  grpc_call_element *elem = user_data;
-  call_data *calld = elem->call_data;
-  if (success) {
-    server_filter_args a;
-    a.elem = elem;
-    a.exec_ctx = exec_ctx;
-    grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, &a);
-    /* Have we seen the required http2 transport headers?
-       (:method, :scheme, content-type, with :path and :authority covered
-       at the channel level right now) */
-    if (calld->seen_post && calld->seen_scheme && calld->seen_te_trailers &&
-        calld->seen_path && calld->seen_authority) {
-      /* do nothing */
-    } else {
-      if (!calld->seen_path) {
-        gpr_log(GPR_ERROR, "Missing :path header");
-      }
-      if (!calld->seen_authority) {
-        gpr_log(GPR_ERROR, "Missing :authority header");
-      }
-      if (!calld->seen_post) {
-        gpr_log(GPR_ERROR, "Missing :method header");
-      }
-      if (!calld->seen_scheme) {
-        gpr_log(GPR_ERROR, "Missing :scheme header");
-      }
-      if (!calld->seen_te_trailers) {
-        gpr_log(GPR_ERROR, "Missing te trailers header");
-      }
-      /* Error this call out */
-      success = 0;
-      grpc_call_element_send_cancel(exec_ctx, elem);
-    }
-  }
-  calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success);
-}
-
-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;
-
-  if (op->send_initial_metadata != NULL && !calld->sent_status) {
-    calld->sent_status = 1;
-    grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->status,
-                                 GRPC_MDELEM_STATUS_200);
-    grpc_metadata_batch_add_tail(
-        op->send_initial_metadata, &calld->content_type,
-        GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
-  }
-
-  if (op->recv_initial_metadata) {
-    /* substitute our callback for the higher callback */
-    calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready = &calld->hs_on_recv;
-  }
-}
-
-static void hs_start_transport_op(grpc_exec_ctx *exec_ctx,
-                                  grpc_call_element *elem,
-                                  grpc_transport_stream_op *op) {
-  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-  GPR_TIMER_BEGIN("hs_start_transport_op", 0);
-  hs_mutate_op(elem, op);
-  grpc_call_next_op(exec_ctx, elem, op);
-  GPR_TIMER_END("hs_start_transport_op", 0);
-}
-
-/* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
-  /* grab pointers to our data from the call element */
-  call_data *calld = elem->call_data;
-  /* initialize members */
-  memset(calld, 0, sizeof(*calld));
-  grpc_closure_init(&calld->hs_on_recv, hs_on_recv, elem);
-}
-
-/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {}
-
-/* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
-  GPR_ASSERT(!args->is_last);
-}
-
-/* Destructor for channel data */
-static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem) {}
-
-const grpc_channel_filter grpc_http_server_filter = {
-    hs_start_transport_op, grpc_channel_next_op, sizeof(call_data),
-    init_call_elem, grpc_call_stack_ignore_set_pollset, destroy_call_elem,
-    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
-    grpc_call_next_get_peer, "http-server"};
diff --git a/src/core/channel/http_server_filter.h b/src/core/channel/http_server_filter.h
deleted file mode 100644
index f219d4e..0000000
--- a/src/core/channel/http_server_filter.h
+++ /dev/null
@@ -1,42 +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_HTTP_SERVER_FILTER_H
-#define GRPC_INTERNAL_CORE_CHANNEL_HTTP_SERVER_FILTER_H
-
-#include "src/core/channel/channel_stack.h"
-
-/* Processes metadata on the client side for HTTP2 transports */
-extern const grpc_channel_filter grpc_http_server_filter;
-
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_SERVER_FILTER_H */
diff --git a/src/core/channel/subchannel_call_holder.c b/src/core/channel/subchannel_call_holder.c
deleted file mode 100644
index 9c087dc..0000000
--- a/src/core/channel/subchannel_call_holder.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/channel/subchannel_call_holder.h"
-
-#include <grpc/support/alloc.h>
-
-#include "src/core/profiling/timers.h"
-
-#define GET_CALL(holder) \
-  ((grpc_subchannel_call *)(gpr_atm_acq_load(&(holder)->subchannel_call)))
-
-#define CANCELLED_CALL ((grpc_subchannel_call *)1)
-
-static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder,
-                             bool success);
-static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args,
-                      bool success);
-
-static void add_waiting_locked(grpc_subchannel_call_holder *holder,
-                               grpc_transport_stream_op *op);
-static void fail_locked(grpc_exec_ctx *exec_ctx,
-                        grpc_subchannel_call_holder *holder);
-static void retry_waiting_locked(grpc_exec_ctx *exec_ctx,
-                                 grpc_subchannel_call_holder *holder);
-
-void grpc_subchannel_call_holder_init(
-    grpc_subchannel_call_holder *holder,
-    grpc_subchannel_call_holder_pick_subchannel pick_subchannel,
-    void *pick_subchannel_arg, grpc_call_stack *owning_call) {
-  gpr_atm_rel_store(&holder->subchannel_call, 0);
-  holder->pick_subchannel = pick_subchannel;
-  holder->pick_subchannel_arg = pick_subchannel_arg;
-  gpr_mu_init(&holder->mu);
-  holder->connected_subchannel = NULL;
-  holder->waiting_ops = NULL;
-  holder->waiting_ops_count = 0;
-  holder->waiting_ops_capacity = 0;
-  holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
-  holder->owning_call = owning_call;
-}
-
-void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx,
-                                         grpc_subchannel_call_holder *holder) {
-  grpc_subchannel_call *call = GET_CALL(holder);
-  if (call != NULL && call != CANCELLED_CALL) {
-    GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "holder");
-  }
-  GPR_ASSERT(holder->creation_phase ==
-             GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING);
-  gpr_mu_destroy(&holder->mu);
-  GPR_ASSERT(holder->waiting_ops_count == 0);
-  gpr_free(holder->waiting_ops);
-}
-
-void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx,
-                                            grpc_subchannel_call_holder *holder,
-                                            grpc_transport_stream_op *op) {
-  /* try to (atomically) get the call */
-  grpc_subchannel_call *call = GET_CALL(holder);
-  GPR_TIMER_BEGIN("grpc_subchannel_call_holder_perform_op", 0);
-  if (call == CANCELLED_CALL) {
-    grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
-    GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
-    return;
-  }
-  if (call != NULL) {
-    grpc_subchannel_call_process_op(exec_ctx, call, op);
-    GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
-    return;
-  }
-  /* we failed; lock and figure out what to do */
-  gpr_mu_lock(&holder->mu);
-retry:
-  /* need to recheck that another thread hasn't set the call */
-  call = GET_CALL(holder);
-  if (call == CANCELLED_CALL) {
-    gpr_mu_unlock(&holder->mu);
-    grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
-    GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
-    return;
-  }
-  if (call != NULL) {
-    gpr_mu_unlock(&holder->mu);
-    grpc_subchannel_call_process_op(exec_ctx, call, op);
-    GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
-    return;
-  }
-  /* if this is a cancellation, then we can raise our cancelled flag */
-  if (op->cancel_with_status != GRPC_STATUS_OK) {
-    if (!gpr_atm_rel_cas(&holder->subchannel_call, 0, 1)) {
-      goto retry;
-    } else {
-      switch (holder->creation_phase) {
-        case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING:
-          fail_locked(exec_ctx, holder);
-          break;
-        case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL:
-          holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL,
-                                  &holder->connected_subchannel, NULL);
-          break;
-      }
-      gpr_mu_unlock(&holder->mu);
-      grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
-      GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
-      return;
-    }
-  }
-  /* if we don't have a subchannel, try to get one */
-  if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
-      holder->connected_subchannel == NULL &&
-      op->send_initial_metadata != NULL) {
-    holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL;
-    grpc_closure_init(&holder->next_step, subchannel_ready, holder);
-    GRPC_CALL_STACK_REF(holder->owning_call, "pick_subchannel");
-    if (holder->pick_subchannel(
-            exec_ctx, holder->pick_subchannel_arg, op->send_initial_metadata,
-            &holder->connected_subchannel, &holder->next_step)) {
-      holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
-      GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel");
-    }
-  }
-  /* if we've got a subchannel, then let's ask it to create a call */
-  if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
-      holder->connected_subchannel != NULL) {
-    gpr_atm_rel_store(
-        &holder->subchannel_call,
-        (gpr_atm)(uintptr_t)grpc_connected_subchannel_create_call(
-            exec_ctx, holder->connected_subchannel, holder->pollset));
-    retry_waiting_locked(exec_ctx, holder);
-    goto retry;
-  }
-  /* nothing to be done but wait */
-  add_waiting_locked(holder, op);
-  gpr_mu_unlock(&holder->mu);
-  GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
-}
-
-static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  grpc_subchannel_call_holder *holder = arg;
-  gpr_mu_lock(&holder->mu);
-  GPR_ASSERT(holder->creation_phase ==
-             GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL);
-  holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
-  if (holder->connected_subchannel == NULL) {
-    fail_locked(exec_ctx, holder);
-  } else if (1 == gpr_atm_acq_load(&holder->subchannel_call)) {
-    /* already cancelled before subchannel became ready */
-    fail_locked(exec_ctx, holder);
-  } else {
-    gpr_atm_rel_store(
-        &holder->subchannel_call,
-        (gpr_atm)(uintptr_t)grpc_connected_subchannel_create_call(
-            exec_ctx, holder->connected_subchannel, holder->pollset));
-    retry_waiting_locked(exec_ctx, holder);
-  }
-  gpr_mu_unlock(&holder->mu);
-  GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel");
-}
-
-typedef struct {
-  grpc_transport_stream_op *ops;
-  size_t nops;
-  grpc_subchannel_call *call;
-} retry_ops_args;
-
-static void retry_waiting_locked(grpc_exec_ctx *exec_ctx,
-                                 grpc_subchannel_call_holder *holder) {
-  retry_ops_args *a = gpr_malloc(sizeof(*a));
-  a->ops = holder->waiting_ops;
-  a->nops = holder->waiting_ops_count;
-  a->call = GET_CALL(holder);
-  if (a->call == CANCELLED_CALL) {
-    gpr_free(a);
-    fail_locked(exec_ctx, holder);
-    return;
-  }
-  holder->waiting_ops = NULL;
-  holder->waiting_ops_count = 0;
-  holder->waiting_ops_capacity = 0;
-  GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops");
-  grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(retry_ops, a), true,
-                        NULL);
-}
-
-static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, bool success) {
-  retry_ops_args *a = args;
-  size_t i;
-  for (i = 0; i < a->nops; i++) {
-    grpc_subchannel_call_process_op(exec_ctx, a->call, &a->ops[i]);
-  }
-  GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, a->call, "retry_ops");
-  gpr_free(a->ops);
-  gpr_free(a);
-}
-
-static void add_waiting_locked(grpc_subchannel_call_holder *holder,
-                               grpc_transport_stream_op *op) {
-  GPR_TIMER_BEGIN("add_waiting_locked", 0);
-  if (holder->waiting_ops_count == holder->waiting_ops_capacity) {
-    holder->waiting_ops_capacity = GPR_MAX(3, 2 * holder->waiting_ops_capacity);
-    holder->waiting_ops =
-        gpr_realloc(holder->waiting_ops, holder->waiting_ops_capacity *
-                                             sizeof(*holder->waiting_ops));
-  }
-  holder->waiting_ops[holder->waiting_ops_count++] = *op;
-  GPR_TIMER_END("add_waiting_locked", 0);
-}
-
-static void fail_locked(grpc_exec_ctx *exec_ctx,
-                        grpc_subchannel_call_holder *holder) {
-  size_t i;
-  for (i = 0; i < holder->waiting_ops_count; i++) {
-    grpc_transport_stream_op_finish_with_failure(exec_ctx,
-                                                 &holder->waiting_ops[i]);
-  }
-  holder->waiting_ops_count = 0;
-}
-
-char *grpc_subchannel_call_holder_get_peer(
-    grpc_exec_ctx *exec_ctx, grpc_subchannel_call_holder *holder) {
-  grpc_subchannel_call *subchannel_call = GET_CALL(holder);
-
-  if (subchannel_call) {
-    return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call);
-  } else {
-    return NULL;
-  }
-}
diff --git a/src/core/channel/subchannel_call_holder.h b/src/core/channel/subchannel_call_holder.h
deleted file mode 100644
index 9cf72c6..0000000
--- a/src/core/channel/subchannel_call_holder.h
+++ /dev/null
@@ -1,98 +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_SUBCHANNEL_CALL_HOLDER_H
-#define GRPC_INTERNAL_CORE_CHANNEL_SUBCHANNEL_CALL_HOLDER_H
-
-#include "src/core/client_config/subchannel.h"
-
-/** Pick a subchannel for grpc_subchannel_call_holder;
-    Return 1 if subchannel is available immediately (in which case on_ready
-    should not be called), or 0 otherwise (in which case on_ready should be
-    called when the subchannel is available) */
-typedef int (*grpc_subchannel_call_holder_pick_subchannel)(
-    grpc_exec_ctx *exec_ctx, void *arg, grpc_metadata_batch *initial_metadata,
-    grpc_connected_subchannel **connected_subchannel, grpc_closure *on_ready);
-
-typedef enum {
-  GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING,
-  GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL
-} grpc_subchannel_call_holder_creation_phase;
-
-/** Wrapper for holding a pointer to grpc_subchannel_call, and the
-    associated machinery to create such a pointer.
-    Handles queueing of stream ops until a call object is ready, waiting
-    for initial metadata before trying to create a call object,
-    and handling cancellation gracefully.
-
-    Both the channel and uchannel filter use this as their call_data. */
-typedef struct grpc_subchannel_call_holder {
-  /** either 0 for no call, 1 for cancelled, or a pointer to a
-      grpc_subchannel_call */
-  gpr_atm subchannel_call;
-  /** Helper function to choose the subchannel on which to create
-      the call object. Channel filter delegates to the load
-      balancing policy (once it's ready); uchannel returns
-      immediately */
-  grpc_subchannel_call_holder_pick_subchannel pick_subchannel;
-  void *pick_subchannel_arg;
-
-  gpr_mu mu;
-
-  grpc_subchannel_call_holder_creation_phase creation_phase;
-  grpc_connected_subchannel *connected_subchannel;
-  grpc_pollset *pollset;
-
-  grpc_transport_stream_op *waiting_ops;
-  size_t waiting_ops_count;
-  size_t waiting_ops_capacity;
-
-  grpc_closure next_step;
-
-  grpc_call_stack *owning_call;
-} grpc_subchannel_call_holder;
-
-void grpc_subchannel_call_holder_init(
-    grpc_subchannel_call_holder *holder,
-    grpc_subchannel_call_holder_pick_subchannel pick_subchannel,
-    void *pick_subchannel_arg, grpc_call_stack *owning_call);
-void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx,
-                                         grpc_subchannel_call_holder *holder);
-
-void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx,
-                                            grpc_subchannel_call_holder *holder,
-                                            grpc_transport_stream_op *op);
-char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx,
-                                           grpc_subchannel_call_holder *holder);
-
-#endif
diff --git a/src/core/client_config/client_config.c b/src/core/client_config/client_config.c
deleted file mode 100644
index 6ecffb3..0000000
--- a/src/core/client_config/client_config.c
+++ /dev/null
@@ -1,72 +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/client_config/client_config.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.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_exec_ctx *exec_ctx, grpc_client_config *c) {
-  if (gpr_unref(&c->refs)) {
-    GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "client_config");
-    gpr_free(c);
-  }
-}
-
-void grpc_client_config_set_lb_policy(grpc_client_config *c,
-                                      grpc_lb_policy *lb_policy) {
-  GPR_ASSERT(c->lb_policy == NULL);
-  if (lb_policy) {
-    GRPC_LB_POLICY_REF(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/client_config/client_config.h b/src/core/client_config/client_config.h
deleted file mode 100644
index 04bf036..0000000
--- a/src/core/client_config/client_config.h
+++ /dev/null
@@ -1,53 +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_CLIENT_CONFIG_CLIENT_CONFIG_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_CLIENT_CONFIG_H
-
-#include "src/core/client_config/lb_policy.h"
-
-/** Total configuration for a client. Provided, and updated, by
-    grpc_resolver */
-typedef struct grpc_client_config grpc_client_config;
-
-grpc_client_config *grpc_client_config_create();
-void grpc_client_config_ref(grpc_client_config *client_config);
-void grpc_client_config_unref(grpc_exec_ctx *exec_ctx,
-                              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/client_config/connector.c b/src/core/client_config/connector.c
deleted file mode 100644
index aa34aa7..0000000
--- a/src/core/client_config/connector.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/client_config/connector.h"
-
-grpc_connector* grpc_connector_ref(grpc_connector* connector) {
-  connector->vtable->ref(connector);
-  return connector;
-}
-
-void grpc_connector_unref(grpc_exec_ctx* exec_ctx, grpc_connector* connector) {
-  connector->vtable->unref(exec_ctx, connector);
-}
-
-void grpc_connector_connect(grpc_exec_ctx* exec_ctx, grpc_connector* connector,
-                            const grpc_connect_in_args* in_args,
-                            grpc_connect_out_args* out_args,
-                            grpc_closure* notify) {
-  connector->vtable->connect(exec_ctx, connector, in_args, out_args, notify);
-}
-
-void grpc_connector_shutdown(grpc_exec_ctx* exec_ctx,
-                             grpc_connector* connector) {
-  connector->vtable->shutdown(exec_ctx, connector);
-}
diff --git a/src/core/client_config/connector.h b/src/core/client_config/connector.h
deleted file mode 100644
index b91eb51..0000000
--- a/src/core/client_config/connector.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_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;
-  size_t addr_len;
-  /** initial connect string to send */
-  gpr_slice initial_connect_string;
-  /** deadline for connection */
-  gpr_timespec deadline;
-  /** channel arguments (to be passed to transport) */
-  const grpc_channel_args *channel_args;
-} 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;
-
-  /** channel arguments (to be passed to the filters) */
-  const grpc_channel_args *channel_args;
-} grpc_connect_out_args;
-
-struct grpc_connector_vtable {
-  void (*ref)(grpc_connector *connector);
-  void (*unref)(grpc_exec_ctx *exec_ctx, grpc_connector *connector);
-  /** Implementation of grpc_connector_shutdown */
-  void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_connector *connector);
-  /** Implementation of grpc_connector_connect */
-  void (*connect)(grpc_exec_ctx *exec_ctx, grpc_connector *connector,
-                  const grpc_connect_in_args *in_args,
-                  grpc_connect_out_args *out_args, grpc_closure *notify);
-};
-
-grpc_connector *grpc_connector_ref(grpc_connector *connector);
-void grpc_connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *connector);
-/** Connect using the connector: max one outstanding call at a time */
-void grpc_connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *connector,
-                            const grpc_connect_in_args *in_args,
-                            grpc_connect_out_args *out_args,
-                            grpc_closure *notify);
-/** Cancel any pending connection */
-void grpc_connector_shutdown(grpc_exec_ctx *exec_ctx,
-                             grpc_connector *connector);
-
-#endif
diff --git a/src/core/client_config/default_initial_connect_string.c b/src/core/client_config/default_initial_connect_string.c
deleted file mode 100644
index 6a4e23e..0000000
--- a/src/core/client_config/default_initial_connect_string.c
+++ /dev/null
@@ -1,39 +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/support/slice.h>
-#include "src/core/iomgr/sockaddr.h"
-
-void grpc_set_default_initial_connect_string(struct sockaddr **addr,
-                                             size_t *addr_len,
-                                             gpr_slice *initial_str) {}
diff --git a/src/core/client_config/initial_connect_string.c b/src/core/client_config/initial_connect_string.c
deleted file mode 100644
index 19afa16..0000000
--- a/src/core/client_config/initial_connect_string.c
+++ /dev/null
@@ -1,53 +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/client_config/initial_connect_string.h"
-
-#include <stddef.h>
-
-extern void grpc_set_default_initial_connect_string(struct sockaddr **addr,
-                                                    size_t *addr_len,
-                                                    gpr_slice *initial_str);
-
-static grpc_set_initial_connect_string_func g_set_initial_connect_string_func =
-    grpc_set_default_initial_connect_string;
-
-void grpc_test_set_initial_connect_string_function(
-    grpc_set_initial_connect_string_func func) {
-  g_set_initial_connect_string_func = func;
-}
-
-void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len,
-                                     gpr_slice *initial_str) {
-  g_set_initial_connect_string_func(addr, addr_len, initial_str);
-}
diff --git a/src/core/client_config/initial_connect_string.h b/src/core/client_config/initial_connect_string.h
deleted file mode 100644
index b6dca71..0000000
--- a/src/core/client_config/initial_connect_string.h
+++ /dev/null
@@ -1,50 +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_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H
-
-#include <grpc/support/slice.h>
-#include "src/core/iomgr/sockaddr.h"
-
-typedef void (*grpc_set_initial_connect_string_func)(struct sockaddr **addr,
-                                                     size_t *addr_len,
-                                                     gpr_slice *initial_str);
-void grpc_test_set_initial_connect_string_function(
-    grpc_set_initial_connect_string_func func);
-
-/** Set a string to be sent once connected. Optionally reset addr. */
-void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len,
-                                     gpr_slice *connect_string);
-
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H */
diff --git a/src/core/client_config/lb_policies/load_balancer_api.c b/src/core/client_config/lb_policies/load_balancer_api.c
deleted file mode 100644
index a6b5785..0000000
--- a/src/core/client_config/lb_policies/load_balancer_api.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- *
- * Copyright 2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/client_config/lb_policies/load_balancer_api.h"
-#include "third_party/nanopb/pb_decode.h"
-#include "third_party/nanopb/pb_encode.h"
-
-#include <grpc/support/alloc.h>
-
-typedef struct decode_serverlist_arg {
-  int first_pass;
-  int i;
-  size_t num_servers;
-  grpc_grpclb_server **servers;
-} decode_serverlist_arg;
-
-/* invoked once for every Server in ServerList */
-static bool decode_serverlist(pb_istream_t *stream, const pb_field_t *field,
-                              void **arg) {
-  decode_serverlist_arg *dec_arg = *arg;
-  if (dec_arg->first_pass != 0) { /* first pass */
-    grpc_grpclb_server server;
-    if (!pb_decode(stream, grpc_lb_v0_Server_fields, &server)) {
-      return false;
-    }
-    dec_arg->num_servers++;
-  } else { /* second pass */
-    grpc_grpclb_server *server = gpr_malloc(sizeof(grpc_grpclb_server));
-    GPR_ASSERT(dec_arg->num_servers > 0);
-    if (dec_arg->i == 0) { /* first iteration of second pass */
-      dec_arg->servers =
-          gpr_malloc(sizeof(grpc_grpclb_server *) * dec_arg->num_servers);
-    }
-    if (!pb_decode(stream, grpc_lb_v0_Server_fields, server)) {
-      return false;
-    }
-    dec_arg->servers[dec_arg->i++] = server;
-  }
-
-  return true;
-}
-
-grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name) {
-  grpc_grpclb_request *req = gpr_malloc(sizeof(grpc_grpclb_request));
-
-  req->has_client_stats = 0; /* TODO(dgq): add support for stats once defined */
-  req->has_initial_request = 1;
-  req->initial_request.has_name = 1;
-  strncpy(req->initial_request.name, lb_service_name,
-          GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH);
-  return req;
-}
-
-gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request) {
-  size_t encoded_length;
-  pb_ostream_t sizestream;
-  pb_ostream_t outputstream;
-  gpr_slice slice;
-  memset(&sizestream, 0, sizeof(pb_ostream_t));
-  pb_encode(&sizestream, grpc_lb_v0_LoadBalanceRequest_fields, request);
-  encoded_length = sizestream.bytes_written;
-
-  slice = gpr_slice_malloc(encoded_length);
-  outputstream =
-      pb_ostream_from_buffer(GPR_SLICE_START_PTR(slice), encoded_length);
-  GPR_ASSERT(pb_encode(&outputstream, grpc_lb_v0_LoadBalanceRequest_fields,
-                       request) != 0);
-  return slice;
-}
-
-void grpc_grpclb_request_destroy(grpc_grpclb_request *request) {
-  gpr_free(request);
-}
-
-grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response) {
-  bool status;
-  pb_istream_t stream =
-      pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response),
-                             GPR_SLICE_LENGTH(encoded_response));
-  grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response));
-  memset(res, 0, sizeof(*res));
-  status = pb_decode(&stream, grpc_lb_v0_LoadBalanceResponse_fields, res);
-  GPR_ASSERT(status == true);
-  return res;
-}
-
-grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
-    gpr_slice encoded_response) {
-  grpc_grpclb_serverlist *sl = gpr_malloc(sizeof(grpc_grpclb_serverlist));
-  bool status;
-  decode_serverlist_arg arg;
-  pb_istream_t stream =
-      pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response),
-                             GPR_SLICE_LENGTH(encoded_response));
-  pb_istream_t stream_at_start = stream;
-  grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response));
-  memset(res, 0, sizeof(*res));
-  memset(&arg, 0, sizeof(decode_serverlist_arg));
-
-  res->server_list.servers.funcs.decode = decode_serverlist;
-  res->server_list.servers.arg = &arg;
-  arg.first_pass = 1;
-  status = pb_decode(&stream, grpc_lb_v0_LoadBalanceResponse_fields, res);
-  GPR_ASSERT(status == true);
-  GPR_ASSERT(arg.num_servers > 0);
-
-  arg.first_pass = 0;
-  status =
-      pb_decode(&stream_at_start, grpc_lb_v0_LoadBalanceResponse_fields, res);
-  GPR_ASSERT(status == true);
-  GPR_ASSERT(arg.servers != NULL);
-
-  sl->num_servers = arg.num_servers;
-  sl->servers = arg.servers;
-  if (res->server_list.has_expiration_interval) {
-    sl->expiration_interval = res->server_list.expiration_interval;
-  }
-  grpc_grpclb_response_destroy(res);
-  return sl;
-}
-
-void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist) {
-  size_t i;
-  for (i = 0; i < serverlist->num_servers; i++) {
-    gpr_free(serverlist->servers[i]);
-  }
-  gpr_free(serverlist->servers);
-  gpr_free(serverlist);
-}
-
-void grpc_grpclb_response_destroy(grpc_grpclb_response *response) {
-  gpr_free(response);
-}
diff --git a/src/core/client_config/lb_policies/load_balancer_api.h b/src/core/client_config/lb_policies/load_balancer_api.h
deleted file mode 100644
index 4dbe1d6..0000000
--- a/src/core/client_config/lb_policies/load_balancer_api.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- *
- * Copyright 2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H
-
-#include <grpc/support/slice_buffer.h>
-
-#include "src/core/client_config/lb_policy_factory.h"
-#include "src/core/proto/grpc/lb/v0/load_balancer.pb.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128
-
-typedef grpc_lb_v0_LoadBalanceRequest grpc_grpclb_request;
-typedef grpc_lb_v0_LoadBalanceResponse grpc_grpclb_response;
-typedef grpc_lb_v0_Server grpc_grpclb_server;
-typedef grpc_lb_v0_Duration grpc_grpclb_duration;
-typedef struct grpc_grpclb_serverlist {
-  grpc_grpclb_server **servers;
-  size_t num_servers;
-  grpc_grpclb_duration expiration_interval;
-} grpc_grpclb_serverlist;
-
-/** Create a request for a gRPC LB service under \a lb_service_name */
-grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name);
-
-/** Protocol Buffers v3-encode \a request */
-gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request);
-
-/** Destroy \a request */
-void grpc_grpclb_request_destroy(grpc_grpclb_request *request);
-
-/** Parse (ie, decode) the bytes in \a encoded_response as a \a
- * grpc_grpclb_response */
-grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response);
-
-/** Destroy \a serverlist */
-void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist);
-
-/** Parse the list of servers from an encoded \a grpc_grpclb_response */
-grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
-    gpr_slice encoded_response);
-
-/** Destroy \a response */
-void grpc_grpclb_response_destroy(grpc_grpclb_response *response);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H */
diff --git a/src/core/client_config/lb_policies/pick_first.c b/src/core/client_config/lb_policies/pick_first.c
deleted file mode 100644
index 81167b3..0000000
--- a/src/core/client_config/lb_policies/pick_first.c
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/client_config/lb_policies/pick_first.h"
-#include "src/core/client_config/lb_policy_factory.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_connected_subchannel **target;
-  grpc_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_closure connectivity_changed;
-
-  /** the selected channel (a grpc_connected_subchannel) */
-  gpr_atm selected;
-
-  /** mutex protecting remaining members */
-  gpr_mu mu;
-  /** have we started picking? */
-  int started_picking;
-  /** are we shut down? */
-  int shutdown;
-  /** 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;
-
-#define GET_SELECTED(p) \
-  ((grpc_connected_subchannel *)gpr_atm_acq_load(&(p)->selected))
-
-void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
-  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
-  grpc_connected_subchannel *selected = GET_SELECTED(p);
-  size_t i;
-  GPR_ASSERT(p->pending_picks == NULL);
-  for (i = 0; i < p->num_subchannels; i++) {
-    GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first");
-  }
-  if (selected != NULL) {
-    GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, selected, "picked_first");
-  }
-  grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
-  gpr_free(p->subchannels);
-  gpr_mu_destroy(&p->mu);
-  gpr_free(p);
-}
-
-void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
-  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
-  pending_pick *pp;
-  grpc_connected_subchannel *selected;
-  gpr_mu_lock(&p->mu);
-  selected = GET_SELECTED(p);
-  p->shutdown = 1;
-  pp = p->pending_picks;
-  p->pending_picks = NULL;
-  grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                              GRPC_CHANNEL_FATAL_FAILURE, "shutdown");
-  /* cancel subscription */
-  if (selected != NULL) {
-    grpc_connected_subchannel_notify_on_state_change(
-        exec_ctx, selected, NULL, NULL, &p->connectivity_changed);
-  } else {
-    grpc_subchannel_notify_on_state_change(
-        exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL,
-        &p->connectivity_changed);
-  }
-  gpr_mu_unlock(&p->mu);
-  while (pp != NULL) {
-    pending_pick *next = pp->next;
-    *pp->target = NULL;
-    grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
-                                 pp->pollset);
-    grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
-    gpr_free(pp);
-    pp = next;
-  }
-}
-
-static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
-                           grpc_connected_subchannel **target) {
-  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
-  pending_pick *pp;
-  gpr_mu_lock(&p->mu);
-  pp = p->pending_picks;
-  p->pending_picks = NULL;
-  while (pp != NULL) {
-    pending_pick *next = pp->next;
-    if (pp->target == target) {
-      grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
-                                   pp->pollset);
-      *target = NULL;
-      grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
-      gpr_free(pp);
-    } else {
-      pp->next = p->pending_picks;
-      p->pending_picks = pp;
-    }
-    pp = next;
-  }
-  gpr_mu_unlock(&p->mu);
-}
-
-static void start_picking(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p) {
-  p->started_picking = 1;
-  p->checking_subchannel = 0;
-  p->checking_connectivity = GRPC_CHANNEL_IDLE;
-  GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity");
-  grpc_subchannel_notify_on_state_change(
-      exec_ctx, p->subchannels[p->checking_subchannel],
-      p->base.interested_parties, &p->checking_connectivity,
-      &p->connectivity_changed);
-}
-
-void pf_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
-  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
-  gpr_mu_lock(&p->mu);
-  if (!p->started_picking) {
-    start_picking(exec_ctx, p);
-  }
-  gpr_mu_unlock(&p->mu);
-}
-
-int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
-            grpc_metadata_batch *initial_metadata,
-            grpc_connected_subchannel **target, grpc_closure *on_complete) {
-  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
-  pending_pick *pp;
-
-  /* Check atomically for a selected channel */
-  grpc_connected_subchannel *selected = GET_SELECTED(p);
-  if (selected != NULL) {
-    *target = selected;
-    return 1;
-  }
-
-  /* No subchannel selected yet, so acquire lock and then attempt again */
-  gpr_mu_lock(&p->mu);
-  selected = GET_SELECTED(p);
-  if (selected) {
-    gpr_mu_unlock(&p->mu);
-    *target = selected;
-    return 1;
-  } else {
-    if (!p->started_picking) {
-      start_picking(exec_ctx, p);
-    }
-    grpc_pollset_set_add_pollset(exec_ctx, p->base.interested_parties, 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);
-    return 0;
-  }
-}
-
-static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
-                                bool iomgr_success) {
-  pick_first_lb_policy *p = arg;
-  size_t i;
-  size_t num_subchannels = p->num_subchannels;
-  grpc_subchannel **subchannels;
-
-  gpr_mu_lock(&p->mu);
-  subchannels = p->subchannels;
-  p->num_subchannels = 0;
-  p->subchannels = NULL;
-  gpr_mu_unlock(&p->mu);
-  GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels");
-
-  for (i = 0; i < num_subchannels; i++) {
-    GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first");
-  }
-
-  gpr_free(subchannels);
-}
-
-static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
-                                    bool iomgr_success) {
-  pick_first_lb_policy *p = arg;
-  grpc_subchannel *selected_subchannel;
-  pending_pick *pp;
-  grpc_connected_subchannel *selected;
-
-  gpr_mu_lock(&p->mu);
-
-  selected = GET_SELECTED(p);
-
-  if (p->shutdown) {
-    gpr_mu_unlock(&p->mu);
-    GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
-    return;
-  } else if (selected != NULL) {
-    if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
-      /* if the selected channel goes bad, we're done */
-      p->checking_connectivity = GRPC_CHANNEL_FATAL_FAILURE;
-    }
-    grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                                p->checking_connectivity, "selected_changed");
-    if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) {
-      grpc_connected_subchannel_notify_on_state_change(
-          exec_ctx, selected, p->base.interested_parties,
-          &p->checking_connectivity, &p->connectivity_changed);
-    } else {
-      GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
-    }
-  } else {
-  loop:
-    switch (p->checking_connectivity) {
-      case GRPC_CHANNEL_READY:
-        grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                                    GRPC_CHANNEL_READY, "connecting_ready");
-        selected_subchannel = p->subchannels[p->checking_subchannel];
-        selected =
-            grpc_subchannel_get_connected_subchannel(selected_subchannel);
-        GPR_ASSERT(selected != NULL);
-        GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked_first");
-        /* drop the pick list: we are connected now */
-        GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
-        gpr_atm_rel_store(&p->selected, (gpr_atm)selected);
-        grpc_exec_ctx_enqueue(
-            exec_ctx, grpc_closure_create(destroy_subchannels, p), true, NULL);
-        /* update any calls that were waiting for a pick */
-        while ((pp = p->pending_picks)) {
-          p->pending_picks = pp->next;
-          *pp->target = selected;
-          grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
-                                       pp->pollset);
-          grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
-          gpr_free(pp);
-        }
-        grpc_connected_subchannel_notify_on_state_change(
-            exec_ctx, selected, p->base.interested_parties,
-            &p->checking_connectivity, &p->connectivity_changed);
-        break;
-      case GRPC_CHANNEL_TRANSIENT_FAILURE:
-        grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                                    GRPC_CHANNEL_TRANSIENT_FAILURE,
-                                    "connecting_transient_failure");
-        p->checking_subchannel =
-            (p->checking_subchannel + 1) % p->num_subchannels;
-        p->checking_connectivity = grpc_subchannel_check_connectivity(
-            p->subchannels[p->checking_subchannel]);
-        if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
-          grpc_subchannel_notify_on_state_change(
-              exec_ctx, p->subchannels[p->checking_subchannel],
-              p->base.interested_parties, &p->checking_connectivity,
-              &p->connectivity_changed);
-        } else {
-          goto loop;
-        }
-        break;
-      case GRPC_CHANNEL_CONNECTING:
-      case GRPC_CHANNEL_IDLE:
-        grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                                    GRPC_CHANNEL_CONNECTING,
-                                    "connecting_changed");
-        grpc_subchannel_notify_on_state_change(
-            exec_ctx, p->subchannels[p->checking_subchannel],
-            p->base.interested_parties, &p->checking_connectivity,
-            &p->connectivity_changed);
-        break;
-      case GRPC_CHANNEL_FATAL_FAILURE:
-        p->num_subchannels--;
-        GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
-                 p->subchannels[p->num_subchannels]);
-        GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels],
-                              "pick_first");
-        if (p->num_subchannels == 0) {
-          grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                                      GRPC_CHANNEL_FATAL_FAILURE,
-                                      "no_more_channels");
-          while ((pp = p->pending_picks)) {
-            p->pending_picks = pp->next;
-            *pp->target = NULL;
-            grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
-            gpr_free(pp);
-          }
-          GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base,
-                                    "pick_first_connectivity");
-        } else {
-          grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                                      GRPC_CHANNEL_TRANSIENT_FAILURE,
-                                      "subchannel_failed");
-          p->checking_subchannel %= p->num_subchannels;
-          p->checking_connectivity = grpc_subchannel_check_connectivity(
-              p->subchannels[p->checking_subchannel]);
-          goto loop;
-        }
-    }
-  }
-
-  gpr_mu_unlock(&p->mu);
-}
-
-static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx,
-                                                     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;
-}
-
-void pf_notify_on_state_change(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
-                               grpc_connectivity_state *current,
-                               grpc_closure *notify) {
-  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
-  gpr_mu_lock(&p->mu);
-  grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker,
-                                                 current, notify);
-  gpr_mu_unlock(&p->mu);
-}
-
-void pf_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
-                 grpc_closure *closure) {
-  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
-  grpc_connected_subchannel *selected = GET_SELECTED(p);
-  if (selected) {
-    grpc_connected_subchannel_ping(exec_ctx, selected, closure);
-  } else {
-    grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
-  }
-}
-
-static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
-    pf_destroy, pf_shutdown, pf_pick, pf_cancel_pick, pf_ping_one, pf_exit_idle,
-    pf_check_connectivity, pf_notify_on_state_change};
-
-static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {}
-
-static void pick_first_factory_unref(grpc_lb_policy_factory *factory) {}
-
-static grpc_lb_policy *create_pick_first(grpc_lb_policy_factory *factory,
-                                         grpc_lb_policy_args *args) {
-  pick_first_lb_policy *p = gpr_malloc(sizeof(*p));
-  GPR_ASSERT(args->num_subchannels > 0);
-  memset(p, 0, sizeof(*p));
-  grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable);
-  p->subchannels =
-      gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels);
-  p->num_subchannels = args->num_subchannels;
-  grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
-                               "pick_first");
-  memcpy(p->subchannels, args->subchannels,
-         sizeof(grpc_subchannel *) * args->num_subchannels);
-  grpc_closure_init(&p->connectivity_changed, pf_connectivity_changed, p);
-  gpr_mu_init(&p->mu);
-  return &p->base;
-}
-
-static const grpc_lb_policy_factory_vtable pick_first_factory_vtable = {
-    pick_first_factory_ref, pick_first_factory_unref, create_pick_first,
-    "pick_first"};
-
-static grpc_lb_policy_factory pick_first_lb_policy_factory = {
-    &pick_first_factory_vtable};
-
-grpc_lb_policy_factory *grpc_pick_first_lb_factory_create() {
-  return &pick_first_lb_policy_factory;
-}
diff --git a/src/core/client_config/lb_policies/pick_first.h b/src/core/client_config/lb_policies/pick_first.h
deleted file mode 100644
index 3ca53ad..0000000
--- a/src/core/client_config/lb_policies/pick_first.h
+++ /dev/null
@@ -1,43 +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_CLIENT_CONFIG_PICK_FIRST_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_PICK_FIRST_H
-
-#include "src/core/client_config/lb_policy_factory.h"
-
-/** Returns a load balancing factory for the pick first policy, which picks up
- * the first subchannel from \a subchannels to succesfully connect */
-grpc_lb_policy_factory *grpc_pick_first_lb_factory_create();
-
-#endif
diff --git a/src/core/client_config/lb_policies/round_robin.c b/src/core/client_config/lb_policies/round_robin.c
deleted file mode 100644
index 98d9acc..0000000
--- a/src/core/client_config/lb_policies/round_robin.c
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/client_config/lb_policies/round_robin.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include "src/core/transport/connectivity_state.h"
-
-typedef struct round_robin_lb_policy round_robin_lb_policy;
-
-int grpc_lb_round_robin_trace = 0;
-
-/** List of entities waiting for a pick.
- *
- * Once a pick is available, \a target is updated and \a on_complete called. */
-typedef struct pending_pick {
-  struct pending_pick *next;
-  grpc_pollset *pollset;
-  grpc_connected_subchannel **target;
-  grpc_closure *on_complete;
-} pending_pick;
-
-/** List of subchannels in a connectivity READY state */
-typedef struct ready_list {
-  grpc_subchannel *subchannel;
-  struct ready_list *next;
-  struct ready_list *prev;
-} ready_list;
-
-typedef struct {
-  /** index within policy->subchannels */
-  size_t index;
-  /** backpointer to owning policy */
-  round_robin_lb_policy *policy;
-  /** subchannel itself */
-  grpc_subchannel *subchannel;
-  /** notification that connectivity has changed on subchannel */
-  grpc_closure connectivity_changed_closure;
-  /** this subchannels current position in subchannel->ready_list */
-  ready_list *ready_list_node;
-  /** last observed connectivity */
-  grpc_connectivity_state connectivity_state;
-} subchannel_data;
-
-struct round_robin_lb_policy {
-  /** base policy: must be first */
-  grpc_lb_policy base;
-
-  /** all our subchannels */
-  size_t num_subchannels;
-  subchannel_data **subchannels;
-
-  /** mutex protecting remaining members */
-  gpr_mu mu;
-  /** have we started picking? */
-  int started_picking;
-  /** are we shutting down? */
-  int shutdown;
-  /** List of picks that are waiting on connectivity */
-  pending_pick *pending_picks;
-
-  /** our connectivity state tracker */
-  grpc_connectivity_state_tracker state_tracker;
-
-  /** (Dummy) root of the doubly linked list containing READY subchannels */
-  ready_list ready_list;
-  /** Last pick from the ready list. */
-  ready_list *ready_list_last_pick;
-};
-
-/** Returns the next subchannel from the connected list or NULL if the list is
- * empty.
- *
- * Note that this function does *not* advance p->ready_list_last_pick. Use \a
- * advance_last_picked_locked() for that. */
-static ready_list *peek_next_connected_locked(const round_robin_lb_policy *p) {
-  ready_list *selected;
-  selected = p->ready_list_last_pick->next;
-
-  while (selected != NULL) {
-    if (selected == &p->ready_list) {
-      GPR_ASSERT(selected->subchannel == NULL);
-      /* skip dummy root */
-      selected = selected->next;
-    } else {
-      GPR_ASSERT(selected->subchannel != NULL);
-      return selected;
-    }
-  }
-  return NULL;
-}
-
-/** Advance the \a ready_list picking head. */
-static void advance_last_picked_locked(round_robin_lb_policy *p) {
-  if (p->ready_list_last_pick->next != NULL) { /* non-empty list */
-    p->ready_list_last_pick = p->ready_list_last_pick->next;
-    if (p->ready_list_last_pick == &p->ready_list) {
-      /* skip dummy root */
-      p->ready_list_last_pick = p->ready_list_last_pick->next;
-    }
-  } else { /* should be an empty list */
-    GPR_ASSERT(p->ready_list_last_pick == &p->ready_list);
-  }
-
-  if (grpc_lb_round_robin_trace) {
-    gpr_log(GPR_DEBUG, "[READYLIST] ADVANCED LAST PICK. NOW AT NODE %p (SC %p)",
-            p->ready_list_last_pick, p->ready_list_last_pick->subchannel);
-  }
-}
-
-/** Prepends (relative to the root at p->ready_list) the connected subchannel \a
- * csc to the list of ready subchannels. */
-static ready_list *add_connected_sc_locked(round_robin_lb_policy *p,
-                                           grpc_subchannel *sc) {
-  ready_list *new_elem = gpr_malloc(sizeof(ready_list));
-  new_elem->subchannel = sc;
-  if (p->ready_list.prev == NULL) {
-    /* first element */
-    new_elem->next = &p->ready_list;
-    new_elem->prev = &p->ready_list;
-    p->ready_list.next = new_elem;
-    p->ready_list.prev = new_elem;
-  } else {
-    new_elem->next = &p->ready_list;
-    new_elem->prev = p->ready_list.prev;
-    p->ready_list.prev->next = new_elem;
-    p->ready_list.prev = new_elem;
-  }
-  if (grpc_lb_round_robin_trace) {
-    gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (SC %p)", new_elem, sc);
-  }
-  return new_elem;
-}
-
-/** Removes \a node from the list of connected subchannels */
-static void remove_disconnected_sc_locked(round_robin_lb_policy *p,
-                                          ready_list *node) {
-  if (node == NULL) {
-    return;
-  }
-  if (node == p->ready_list_last_pick) {
-    /* If removing the lastly picked node, reset the last pick pointer to the
-     * dummy root of the list */
-    p->ready_list_last_pick = &p->ready_list;
-  }
-
-  /* removing last item */
-  if (node->next == &p->ready_list && node->prev == &p->ready_list) {
-    GPR_ASSERT(p->ready_list.next == node);
-    GPR_ASSERT(p->ready_list.prev == node);
-    p->ready_list.next = NULL;
-    p->ready_list.prev = NULL;
-  } else {
-    node->prev->next = node->next;
-    node->next->prev = node->prev;
-  }
-
-  if (grpc_lb_round_robin_trace) {
-    gpr_log(GPR_DEBUG, "[READYLIST] REMOVED NODE %p (SC %p)", node,
-            node->subchannel);
-  }
-
-  node->next = NULL;
-  node->prev = NULL;
-  node->subchannel = NULL;
-
-  gpr_free(node);
-}
-
-void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
-  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
-  size_t i;
-  ready_list *elem;
-  for (i = 0; i < p->num_subchannels; i++) {
-    subchannel_data *sd = p->subchannels[i];
-    GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin");
-    gpr_free(sd);
-  }
-
-  grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
-  gpr_free(p->subchannels);
-  gpr_mu_destroy(&p->mu);
-
-  elem = p->ready_list.next;
-  while (elem != NULL && elem != &p->ready_list) {
-    ready_list *tmp;
-    tmp = elem->next;
-    elem->next = NULL;
-    elem->prev = NULL;
-    elem->subchannel = NULL;
-    gpr_free(elem);
-    elem = tmp;
-  }
-  gpr_free(p);
-}
-
-void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
-  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
-  pending_pick *pp;
-  size_t i;
-
-  gpr_mu_lock(&p->mu);
-
-  p->shutdown = 1;
-  while ((pp = p->pending_picks)) {
-    p->pending_picks = pp->next;
-    *pp->target = NULL;
-    grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
-    gpr_free(pp);
-  }
-  grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                              GRPC_CHANNEL_FATAL_FAILURE, "shutdown");
-  for (i = 0; i < p->num_subchannels; i++) {
-    subchannel_data *sd = p->subchannels[i];
-    grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL,
-                                           &sd->connectivity_changed_closure);
-  }
-  gpr_mu_unlock(&p->mu);
-}
-
-static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
-                           grpc_connected_subchannel **target) {
-  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
-  pending_pick *pp;
-  gpr_mu_lock(&p->mu);
-  pp = p->pending_picks;
-  p->pending_picks = NULL;
-  while (pp != NULL) {
-    pending_pick *next = pp->next;
-    if (pp->target == target) {
-      grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
-                                   pp->pollset);
-      *target = NULL;
-      grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
-      gpr_free(pp);
-    } else {
-      pp->next = p->pending_picks;
-      p->pending_picks = pp;
-    }
-    pp = next;
-  }
-  gpr_mu_unlock(&p->mu);
-}
-
-static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) {
-  size_t i;
-  p->started_picking = 1;
-
-  gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%d", p,
-          p->num_subchannels);
-
-  for (i = 0; i < p->num_subchannels; i++) {
-    subchannel_data *sd = p->subchannels[i];
-    sd->connectivity_state = GRPC_CHANNEL_IDLE;
-    grpc_subchannel_notify_on_state_change(
-        exec_ctx, sd->subchannel, p->base.interested_parties,
-        &sd->connectivity_state, &sd->connectivity_changed_closure);
-    GRPC_LB_POLICY_WEAK_REF(&p->base, "round_robin_connectivity");
-  }
-}
-
-void rr_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
-  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
-  gpr_mu_lock(&p->mu);
-  if (!p->started_picking) {
-    start_picking(exec_ctx, p);
-  }
-  gpr_mu_unlock(&p->mu);
-}
-
-int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
-            grpc_metadata_batch *initial_metadata,
-            grpc_connected_subchannel **target, grpc_closure *on_complete) {
-  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
-  pending_pick *pp;
-  ready_list *selected;
-  gpr_mu_lock(&p->mu);
-  if ((selected = peek_next_connected_locked(p))) {
-    gpr_mu_unlock(&p->mu);
-    *target = grpc_subchannel_get_connected_subchannel(selected->subchannel);
-    if (grpc_lb_round_robin_trace) {
-      gpr_log(GPR_DEBUG,
-              "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)",
-              selected->subchannel, selected);
-    }
-    /* only advance the last picked pointer if the selection was used */
-    advance_last_picked_locked(p);
-    return 1;
-  } else {
-    if (!p->started_picking) {
-      start_picking(exec_ctx, p);
-    }
-    grpc_pollset_set_add_pollset(exec_ctx, p->base.interested_parties, 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);
-    return 0;
-  }
-}
-
-static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
-                                    bool iomgr_success) {
-  subchannel_data *sd = arg;
-  round_robin_lb_policy *p = sd->policy;
-  pending_pick *pp;
-  ready_list *selected;
-
-  int unref = 0;
-
-  gpr_mu_lock(&p->mu);
-
-  if (p->shutdown) {
-    unref = 1;
-  } else {
-    switch (sd->connectivity_state) {
-      case GRPC_CHANNEL_READY:
-        grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                                    GRPC_CHANNEL_READY, "connecting_ready");
-        /* add the newly connected subchannel to the list of connected ones.
-         * Note that it goes to the "end of the line". */
-        sd->ready_list_node = add_connected_sc_locked(p, sd->subchannel);
-        /* at this point we know there's at least one suitable subchannel. Go
-         * ahead and pick one and notify the pending suitors in
-         * p->pending_picks. This preemtively replicates rr_pick()'s actions. */
-        selected = peek_next_connected_locked(p);
-        if (p->pending_picks != NULL) {
-          /* if the selected subchannel is going to be used for the pending
-           * picks, update the last picked pointer */
-          advance_last_picked_locked(p);
-        }
-        while ((pp = p->pending_picks)) {
-          p->pending_picks = pp->next;
-          *pp->target =
-              grpc_subchannel_get_connected_subchannel(selected->subchannel);
-          if (grpc_lb_round_robin_trace) {
-            gpr_log(GPR_DEBUG,
-                    "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
-                    selected->subchannel, selected);
-          }
-          grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
-                                       pp->pollset);
-          grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
-          gpr_free(pp);
-        }
-        grpc_subchannel_notify_on_state_change(
-            exec_ctx, sd->subchannel, p->base.interested_parties,
-            &sd->connectivity_state, &sd->connectivity_changed_closure);
-        break;
-      case GRPC_CHANNEL_CONNECTING:
-      case GRPC_CHANNEL_IDLE:
-        grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                                    sd->connectivity_state,
-                                    "connecting_changed");
-        grpc_subchannel_notify_on_state_change(
-            exec_ctx, sd->subchannel, p->base.interested_parties,
-            &sd->connectivity_state, &sd->connectivity_changed_closure);
-        break;
-      case GRPC_CHANNEL_TRANSIENT_FAILURE:
-        /* renew state notification */
-        grpc_subchannel_notify_on_state_change(
-            exec_ctx, sd->subchannel, p->base.interested_parties,
-            &sd->connectivity_state, &sd->connectivity_changed_closure);
-
-        /* remove from ready list if still present */
-        if (sd->ready_list_node != NULL) {
-          remove_disconnected_sc_locked(p, sd->ready_list_node);
-          sd->ready_list_node = NULL;
-        }
-        grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                                    GRPC_CHANNEL_TRANSIENT_FAILURE,
-                                    "connecting_transient_failure");
-        break;
-      case GRPC_CHANNEL_FATAL_FAILURE:
-        if (sd->ready_list_node != NULL) {
-          remove_disconnected_sc_locked(p, sd->ready_list_node);
-          sd->ready_list_node = NULL;
-        }
-
-        p->num_subchannels--;
-        GPR_SWAP(subchannel_data *, p->subchannels[sd->index],
-                 p->subchannels[p->num_subchannels]);
-        GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin");
-        p->subchannels[sd->index]->index = sd->index;
-        gpr_free(sd);
-
-        unref = 1;
-        if (p->num_subchannels == 0) {
-          grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                                      GRPC_CHANNEL_FATAL_FAILURE,
-                                      "no_more_channels");
-          while ((pp = p->pending_picks)) {
-            p->pending_picks = pp->next;
-            *pp->target = NULL;
-            grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
-            gpr_free(pp);
-          }
-        } else {
-          grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
-                                      GRPC_CHANNEL_TRANSIENT_FAILURE,
-                                      "subchannel_failed");
-        }
-    } /* switch */
-  }   /* !unref */
-
-  gpr_mu_unlock(&p->mu);
-
-  if (unref) {
-    GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "round_robin_connectivity");
-  }
-}
-
-static grpc_connectivity_state rr_check_connectivity(grpc_exec_ctx *exec_ctx,
-                                                     grpc_lb_policy *pol) {
-  round_robin_lb_policy *p = (round_robin_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 rr_notify_on_state_change(grpc_exec_ctx *exec_ctx,
-                                      grpc_lb_policy *pol,
-                                      grpc_connectivity_state *current,
-                                      grpc_closure *notify) {
-  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
-  gpr_mu_lock(&p->mu);
-  grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker,
-                                                 current, notify);
-  gpr_mu_unlock(&p->mu);
-}
-
-static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
-                        grpc_closure *closure) {
-  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
-  ready_list *selected;
-  grpc_connected_subchannel *target;
-  gpr_mu_lock(&p->mu);
-  if ((selected = peek_next_connected_locked(p))) {
-    gpr_mu_unlock(&p->mu);
-    target = grpc_subchannel_get_connected_subchannel(selected->subchannel);
-    grpc_connected_subchannel_ping(exec_ctx, target, closure);
-  } else {
-    gpr_mu_unlock(&p->mu);
-    grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
-  }
-}
-
-static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = {
-    rr_destroy, rr_shutdown, rr_pick, rr_cancel_pick, rr_ping_one, rr_exit_idle,
-    rr_check_connectivity, rr_notify_on_state_change};
-
-static void round_robin_factory_ref(grpc_lb_policy_factory *factory) {}
-
-static void round_robin_factory_unref(grpc_lb_policy_factory *factory) {}
-
-static grpc_lb_policy *create_round_robin(grpc_lb_policy_factory *factory,
-                                          grpc_lb_policy_args *args) {
-  size_t i;
-  round_robin_lb_policy *p = gpr_malloc(sizeof(*p));
-  GPR_ASSERT(args->num_subchannels > 0);
-  memset(p, 0, sizeof(*p));
-  grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable);
-  p->num_subchannels = args->num_subchannels;
-  p->subchannels = gpr_malloc(sizeof(*p->subchannels) * p->num_subchannels);
-  memset(p->subchannels, 0, sizeof(*p->subchannels) * p->num_subchannels);
-  grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
-                               "round_robin");
-
-  gpr_mu_init(&p->mu);
-  for (i = 0; i < args->num_subchannels; i++) {
-    subchannel_data *sd = gpr_malloc(sizeof(*sd));
-    memset(sd, 0, sizeof(*sd));
-    p->subchannels[i] = sd;
-    sd->policy = p;
-    sd->index = i;
-    sd->subchannel = args->subchannels[i];
-    grpc_closure_init(&sd->connectivity_changed_closure,
-                      rr_connectivity_changed, sd);
-  }
-
-  /* The (dummy node) root of the ready list */
-  p->ready_list.subchannel = NULL;
-  p->ready_list.prev = NULL;
-  p->ready_list.next = NULL;
-  p->ready_list_last_pick = &p->ready_list;
-
-  return &p->base;
-}
-
-static const grpc_lb_policy_factory_vtable round_robin_factory_vtable = {
-    round_robin_factory_ref, round_robin_factory_unref, create_round_robin,
-    "round_robin"};
-
-static grpc_lb_policy_factory round_robin_lb_policy_factory = {
-    &round_robin_factory_vtable};
-
-grpc_lb_policy_factory *grpc_round_robin_lb_factory_create() {
-  return &round_robin_lb_policy_factory;
-}
diff --git a/src/core/client_config/lb_policies/round_robin.h b/src/core/client_config/lb_policies/round_robin.h
deleted file mode 100644
index cf1f69c..0000000
--- a/src/core/client_config/lb_policies/round_robin.h
+++ /dev/null
@@ -1,46 +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_CLIENT_CONFIG_ROUND_ROBIN_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_ROUND_ROBIN_H
-
-#include "src/core/client_config/lb_policy.h"
-
-extern int grpc_lb_round_robin_trace;
-
-#include "src/core/client_config/lb_policy_factory.h"
-
-/** Returns a load balancing factory for the round robin policy */
-grpc_lb_policy_factory *grpc_round_robin_lb_factory_create();
-
-#endif
diff --git a/src/core/client_config/lb_policy.c b/src/core/client_config/lb_policy.c
deleted file mode 100644
index 0d8b007..0000000
--- a/src/core/client_config/lb_policy.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/client_config/lb_policy.h"
-
-#define WEAK_REF_BITS 16
-
-void grpc_lb_policy_init(grpc_lb_policy *policy,
-                         const grpc_lb_policy_vtable *vtable) {
-  policy->vtable = vtable;
-  gpr_atm_no_barrier_store(&policy->ref_pair, 1 << WEAK_REF_BITS);
-  policy->interested_parties = grpc_pollset_set_create();
-}
-
-#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
-#define REF_FUNC_EXTRA_ARGS , const char *file, int line, const char *reason
-#define REF_MUTATE_EXTRA_ARGS REF_FUNC_EXTRA_ARGS, const char *purpose
-#define REF_FUNC_PASS_ARGS(new_reason) , file, line, new_reason
-#define REF_MUTATE_PASS_ARGS(purpose) , file, line, reason, purpose
-#else
-#define REF_FUNC_EXTRA_ARGS
-#define REF_MUTATE_EXTRA_ARGS
-#define REF_FUNC_PASS_ARGS(new_reason)
-#define REF_MUTATE_PASS_ARGS(x)
-#endif
-
-static gpr_atm ref_mutate(grpc_lb_policy *c, gpr_atm delta,
-                          int barrier REF_MUTATE_EXTRA_ARGS) {
-  gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta)
-                            : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
-#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-          "LB_POLICY: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val,
-          old_val + delta, reason);
-#endif
-  return old_val;
-}
-
-void grpc_lb_policy_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
-  ref_mutate(policy, 1 << WEAK_REF_BITS, 0 REF_MUTATE_PASS_ARGS("STRONG_REF"));
-}
-
-void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx,
-                          grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
-  gpr_atm old_val =
-      ref_mutate(policy, (gpr_atm)1 - (gpr_atm)(1 << WEAK_REF_BITS),
-                 1 REF_MUTATE_PASS_ARGS("STRONG_UNREF"));
-  gpr_atm mask = ~(gpr_atm)((1 << WEAK_REF_BITS) - 1);
-  gpr_atm check = 1 << WEAK_REF_BITS;
-  if ((old_val & mask) == check) {
-    policy->vtable->shutdown(exec_ctx, policy);
-  }
-  grpc_lb_policy_weak_unref(exec_ctx,
-                            policy REF_FUNC_PASS_ARGS("strong-unref"));
-}
-
-void grpc_lb_policy_weak_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
-  ref_mutate(policy, 1, 0 REF_MUTATE_PASS_ARGS("WEAK_REF"));
-}
-
-void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx,
-                               grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
-  gpr_atm old_val =
-      ref_mutate(policy, -(gpr_atm)1, 1 REF_MUTATE_PASS_ARGS("WEAK_UNREF"));
-  if (old_val == 1) {
-    grpc_pollset_set_destroy(policy->interested_parties);
-    policy->vtable->destroy(exec_ctx, policy);
-  }
-}
-
-int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
-                        grpc_pollset *pollset,
-                        grpc_metadata_batch *initial_metadata,
-                        grpc_connected_subchannel **target,
-                        grpc_closure *on_complete) {
-  return policy->vtable->pick(exec_ctx, policy, pollset, initial_metadata,
-                              target, on_complete);
-}
-
-void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
-                                grpc_connected_subchannel **target) {
-  policy->vtable->cancel_pick(exec_ctx, policy, target);
-}
-
-void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) {
-  policy->vtable->exit_idle(exec_ctx, policy);
-}
-
-void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
-                             grpc_closure *closure) {
-  policy->vtable->ping_one(exec_ctx, policy, closure);
-}
-
-void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx,
-                                           grpc_lb_policy *policy,
-                                           grpc_connectivity_state *state,
-                                           grpc_closure *closure) {
-  policy->vtable->notify_on_state_change(exec_ctx, policy, state, closure);
-}
-
-grpc_connectivity_state grpc_lb_policy_check_connectivity(
-    grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) {
-  return policy->vtable->check_connectivity(exec_ctx, policy);
-}
diff --git a/src/core/client_config/lb_policy.h b/src/core/client_config/lb_policy.h
deleted file mode 100644
index 3457390..0000000
--- a/src/core/client_config/lb_policy.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICY_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICY_H
-
-#include "src/core/client_config/subchannel.h"
-#include "src/core/transport/connectivity_state.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_atm ref_pair;
-  /* owned pointer to interested parties in load balancing decisions */
-  grpc_pollset_set *interested_parties;
-};
-
-struct grpc_lb_policy_vtable {
-  void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
-
-  void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
-
-  /** implement grpc_lb_policy_pick */
-  int (*pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
-              grpc_pollset *pollset, grpc_metadata_batch *initial_metadata,
-              grpc_connected_subchannel **target, grpc_closure *on_complete);
-  void (*cancel_pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
-                      grpc_connected_subchannel **target);
-
-  void (*ping_one)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
-                   grpc_closure *closure);
-
-  /** try to enter a READY connectivity state */
-  void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
-
-  /** check the current connectivity of the lb_policy */
-  grpc_connectivity_state (*check_connectivity)(grpc_exec_ctx *exec_ctx,
-                                                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_exec_ctx *exec_ctx,
-                                 grpc_lb_policy *policy,
-                                 grpc_connectivity_state *state,
-                                 grpc_closure *closure);
-};
-
-/*#define GRPC_LB_POLICY_REFCOUNT_DEBUG*/
-#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(exec_ctx, p, r) \
-  grpc_lb_policy_unref((exec_ctx), (p), __FILE__, __LINE__, (r))
-#define GRPC_LB_POLICY_WEAK_REF(p, r) \
-  grpc_lb_policy_weak_ref((p), __FILE__, __LINE__, (r))
-#define GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, p, r) \
-  grpc_lb_policy_weak_unref((exec_ctx), (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_exec_ctx *exec_ctx, grpc_lb_policy *policy,
-                          const char *file, int line, const char *reason);
-void grpc_lb_policy_weak_ref(grpc_lb_policy *policy, const char *file, int line,
-                             const char *reason);
-void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, 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(cl, p, r) grpc_lb_policy_unref((cl), (p))
-#define GRPC_LB_POLICY_WEAK_REF(p, r) grpc_lb_policy_weak_ref((p))
-#define GRPC_LB_POLICY_WEAK_UNREF(cl, p, r) grpc_lb_policy_weak_unref((cl), (p))
-void grpc_lb_policy_ref(grpc_lb_policy *policy);
-void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
-void grpc_lb_policy_weak_ref(grpc_lb_policy *policy);
-void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, 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);
-
-/** 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. */
-int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
-                        grpc_pollset *pollset,
-                        grpc_metadata_batch *initial_metadata,
-                        grpc_connected_subchannel **target,
-                        grpc_closure *on_complete);
-
-void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
-                             grpc_closure *closure);
-
-void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
-                                grpc_connected_subchannel **target);
-
-void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
-
-void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx,
-                                           grpc_lb_policy *policy,
-                                           grpc_connectivity_state *state,
-                                           grpc_closure *closure);
-
-grpc_connectivity_state grpc_lb_policy_check_connectivity(
-    grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
-
-#endif /* GRPC_INTERNAL_CORE_CONFIG_LB_POLICY_H */
diff --git a/src/core/client_config/lb_policy_factory.c b/src/core/client_config/lb_policy_factory.c
deleted file mode 100644
index e49de54..0000000
--- a/src/core/client_config/lb_policy_factory.c
+++ /dev/null
@@ -1,48 +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/client_config/lb_policy_factory.h"
-
-void grpc_lb_policy_factory_ref(grpc_lb_policy_factory* factory) {
-  factory->vtable->ref(factory);
-}
-
-void grpc_lb_policy_factory_unref(grpc_lb_policy_factory* factory) {
-  factory->vtable->unref(factory);
-}
-
-grpc_lb_policy* grpc_lb_policy_factory_create_lb_policy(
-    grpc_lb_policy_factory* factory, grpc_lb_policy_args* args) {
-  if (factory == NULL) return NULL;
-  return factory->vtable->create_lb_policy(factory, args);
-}
diff --git a/src/core/client_config/lb_policy_factory.h b/src/core/client_config/lb_policy_factory.h
deleted file mode 100644
index 0461031..0000000
--- a/src/core/client_config/lb_policy_factory.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_CLIENT_CONFIG_LB_POLICY_FACTORY_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICY_FACTORY_H
-
-#include "src/core/client_config/lb_policy.h"
-#include "src/core/client_config/subchannel.h"
-
-typedef struct grpc_lb_policy_factory grpc_lb_policy_factory;
-typedef struct grpc_lb_policy_factory_vtable grpc_lb_policy_factory_vtable;
-
-/** grpc_lb_policy provides grpc_client_config objects to grpc_channel
-    objects */
-struct grpc_lb_policy_factory {
-  const grpc_lb_policy_factory_vtable *vtable;
-};
-
-typedef struct grpc_lb_policy_args {
-  grpc_subchannel **subchannels;
-  size_t num_subchannels;
-} grpc_lb_policy_args;
-
-struct grpc_lb_policy_factory_vtable {
-  void (*ref)(grpc_lb_policy_factory *factory);
-  void (*unref)(grpc_lb_policy_factory *factory);
-
-  /** Implementation of grpc_lb_policy_factory_create_lb_policy */
-  grpc_lb_policy *(*create_lb_policy)(grpc_lb_policy_factory *factory,
-                                      grpc_lb_policy_args *args);
-
-  /** Name for the LB policy this factory implements */
-  const char *name;
-};
-
-void grpc_lb_policy_factory_ref(grpc_lb_policy_factory *factory);
-void grpc_lb_policy_factory_unref(grpc_lb_policy_factory *factory);
-
-/** Create a lb_policy instance. */
-grpc_lb_policy *grpc_lb_policy_factory_create_lb_policy(
-    grpc_lb_policy_factory *factory, grpc_lb_policy_args *args);
-
-#endif /* GRPC_INTERNAL_CORE_CONFIG_LB_POLICY_FACTORY_H */
diff --git a/src/core/client_config/lb_policy_registry.c b/src/core/client_config/lb_policy_registry.c
deleted file mode 100644
index fc302e8..0000000
--- a/src/core/client_config/lb_policy_registry.c
+++ /dev/null
@@ -1,88 +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/client_config/lb_policy_registry.h"
-
-#include <string.h>
-
-#define MAX_POLICIES 10
-
-static grpc_lb_policy_factory *g_all_of_the_lb_policies[MAX_POLICIES];
-static int g_number_of_lb_policies = 0;
-
-static grpc_lb_policy_factory *g_default_lb_policy_factory;
-
-void grpc_lb_policy_registry_init(grpc_lb_policy_factory *default_factory) {
-  g_number_of_lb_policies = 0;
-  g_default_lb_policy_factory = default_factory;
-}
-
-void grpc_lb_policy_registry_shutdown(void) {
-  int i;
-  for (i = 0; i < g_number_of_lb_policies; i++) {
-    grpc_lb_policy_factory_unref(g_all_of_the_lb_policies[i]);
-  }
-}
-
-void grpc_register_lb_policy(grpc_lb_policy_factory *factory) {
-  int i;
-  for (i = 0; i < g_number_of_lb_policies; i++) {
-    GPR_ASSERT(0 != strcmp(factory->vtable->name,
-                           g_all_of_the_lb_policies[i]->vtable->name));
-  }
-  GPR_ASSERT(g_number_of_lb_policies != MAX_POLICIES);
-  grpc_lb_policy_factory_ref(factory);
-  g_all_of_the_lb_policies[g_number_of_lb_policies++] = factory;
-}
-
-static grpc_lb_policy_factory *lookup_factory(const char *name) {
-  int i;
-
-  if (name == NULL) return NULL;
-
-  for (i = 0; i < g_number_of_lb_policies; i++) {
-    if (0 == strcmp(name, g_all_of_the_lb_policies[i]->vtable->name)) {
-      return g_all_of_the_lb_policies[i];
-    }
-  }
-
-  return NULL;
-}
-
-grpc_lb_policy *grpc_lb_policy_create(const char *name,
-                                      grpc_lb_policy_args *args) {
-  grpc_lb_policy_factory *factory = lookup_factory(name);
-  grpc_lb_policy *lb_policy =
-      grpc_lb_policy_factory_create_lb_policy(factory, args);
-  return lb_policy;
-}
diff --git a/src/core/client_config/lb_policy_registry.h b/src/core/client_config/lb_policy_registry.h
deleted file mode 100644
index 96fc2a1..0000000
--- a/src/core/client_config/lb_policy_registry.h
+++ /dev/null
@@ -1,54 +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_CLIENT_CONFIG_LB_POLICY_REGISTRY_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICY_REGISTRY_H
-
-#include "src/core/client_config/lb_policy_factory.h"
-
-/** Initialize the registry and set \a default_factory as the factory to be
- * returned when no name is provided in a lookup */
-void grpc_lb_policy_registry_init(grpc_lb_policy_factory *default_factory);
-void grpc_lb_policy_registry_shutdown(void);
-
-/** Register a LB policy factory. */
-void grpc_register_lb_policy(grpc_lb_policy_factory *factory);
-
-/** Create a \a grpc_lb_policy instance.
- *
- * If \a name is NULL, the default factory from \a grpc_lb_policy_registry_init
- * will be returned. */
-grpc_lb_policy *grpc_lb_policy_create(const char *name,
-                                      grpc_lb_policy_args *args);
-
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_LB_POLICY_REGISTRY_H */
diff --git a/src/core/client_config/resolver.c b/src/core/client_config/resolver.c
deleted file mode 100644
index eda01e7..0000000
--- a/src/core/client_config/resolver.c
+++ /dev/null
@@ -1,82 +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/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, grpc_closure_list *closure_list,
-                       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,
-                         grpc_closure_list *closure_list, 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_exec_ctx *exec_ctx, grpc_resolver *resolver) {
-#endif
-  if (gpr_unref(&resolver->refs)) {
-    resolver->vtable->destroy(exec_ctx, resolver);
-  }
-}
-
-void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) {
-  resolver->vtable->shutdown(exec_ctx, resolver);
-}
-
-void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx,
-                                     grpc_resolver *resolver) {
-  resolver->vtable->channel_saw_error(exec_ctx, resolver);
-}
-
-void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
-                        grpc_client_config **target_config,
-                        grpc_closure *on_complete) {
-  resolver->vtable->next(exec_ctx, resolver, target_config, on_complete);
-}
diff --git a/src/core/client_config/resolver.h b/src/core/client_config/resolver.h
deleted file mode 100644
index e612eaf..0000000
--- a/src/core/client_config/resolver.h
+++ /dev/null
@@ -1,94 +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_CLIENT_CONFIG_RESOLVER_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_H
-
-#include "src/core/client_config/client_config.h"
-#include "src/core/client_config/subchannel.h"
-#include "src/core/iomgr/iomgr.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_exec_ctx *exec_ctx, grpc_resolver *resolver);
-  void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
-  void (*channel_saw_error)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
-  void (*next)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
-               grpc_client_config **target_config, grpc_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(cl, p, r) \
-  grpc_resolver_unref((cl), (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, grpc_closure_list *closure_list,
-                         const char *file, int line, const char *reason);
-#else
-#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p))
-#define GRPC_RESOLVER_UNREF(cl, p, r) grpc_resolver_unref((cl), (p))
-void grpc_resolver_ref(grpc_resolver *policy);
-void grpc_resolver_unref(grpc_exec_ctx *exec_ctx, grpc_resolver *policy);
-#endif
-
-void grpc_resolver_init(grpc_resolver *resolver,
-                        const grpc_resolver_vtable *vtable);
-
-void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx,
-                                     grpc_resolver *resolver);
-
-/** 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_exec_ctx *exec_ctx, grpc_resolver *resolver,
-                        grpc_client_config **target_config,
-                        grpc_closure *on_complete);
-
-#endif /* GRPC_INTERNAL_CORE_CONFIG_RESOLVER_H */
diff --git a/src/core/client_config/resolver_factory.c b/src/core/client_config/resolver_factory.c
deleted file mode 100644
index e7e9196..0000000
--- a/src/core/client_config/resolver_factory.c
+++ /dev/null
@@ -1,55 +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/client_config/resolver_factory.h"
-
-void grpc_resolver_factory_ref(grpc_resolver_factory* factory) {
-  factory->vtable->ref(factory);
-}
-
-void grpc_resolver_factory_unref(grpc_resolver_factory* factory) {
-  factory->vtable->unref(factory);
-}
-
-/** Create a resolver instance for a name */
-grpc_resolver* grpc_resolver_factory_create_resolver(
-    grpc_resolver_factory* factory, grpc_resolver_args* args) {
-  if (factory == NULL) return NULL;
-  return factory->vtable->create_resolver(factory, args);
-}
-
-char* grpc_resolver_factory_get_default_authority(
-    grpc_resolver_factory* factory, grpc_uri* uri) {
-  if (factory == NULL) return NULL;
-  return factory->vtable->get_default_authority(factory, uri);
-}
diff --git a/src/core/client_config/resolver_factory.h b/src/core/client_config/resolver_factory.h
deleted file mode 100644
index 4c4df35..0000000
--- a/src/core/client_config/resolver_factory.h
+++ /dev/null
@@ -1,82 +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_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;
-};
-
-typedef struct grpc_resolver_args {
-  grpc_uri *uri;
-  grpc_subchannel_factory *subchannel_factory;
-} grpc_resolver_args;
-
-struct grpc_resolver_factory_vtable {
-  void (*ref)(grpc_resolver_factory *factory);
-  void (*unref)(grpc_resolver_factory *factory);
-
-  /** Implementation of grpc_resolver_factory_create_resolver */
-  grpc_resolver *(*create_resolver)(grpc_resolver_factory *factory,
-                                    grpc_resolver_args *args);
-
-  /** Implementation of grpc_resolver_factory_get_default_authority */
-  char *(*get_default_authority)(grpc_resolver_factory *factory, grpc_uri *uri);
-
-  /** URI scheme that this factory implements */
-  const char *scheme;
-};
-
-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_resolver_args *args);
-
-/** Return a (freshly allocated with gpr_malloc) string representing
-    the default authority to use for this scheme. */
-char *grpc_resolver_factory_get_default_authority(
-    grpc_resolver_factory *factory, grpc_uri *uri);
-
-#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
deleted file mode 100644
index 89a945c..0000000
--- a/src/core/client_config/resolver_registry.c
+++ /dev/null
@@ -1,137 +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/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
-
-static grpc_resolver_factory *g_all_of_the_resolvers[MAX_RESOLVERS];
-static int g_number_of_resolvers = 0;
-
-static char *g_default_resolver_prefix;
-
-void grpc_resolver_registry_init(const char *default_resolver_prefix) {
-  g_number_of_resolvers = 0;
-  g_default_resolver_prefix = gpr_strdup(default_resolver_prefix);
-}
-
-void grpc_resolver_registry_shutdown(void) {
-  int i;
-  for (i = 0; i < g_number_of_resolvers; i++) {
-    grpc_resolver_factory_unref(g_all_of_the_resolvers[i]);
-  }
-  gpr_free(g_default_resolver_prefix);
-}
-
-void grpc_register_resolver_type(grpc_resolver_factory *factory) {
-  int i;
-  for (i = 0; i < g_number_of_resolvers; i++) {
-    GPR_ASSERT(0 != strcmp(factory->vtable->scheme,
-                           g_all_of_the_resolvers[i]->vtable->scheme));
-  }
-  GPR_ASSERT(g_number_of_resolvers != MAX_RESOLVERS);
-  grpc_resolver_factory_ref(factory);
-  g_all_of_the_resolvers[g_number_of_resolvers++] = factory;
-}
-
-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]->vtable->scheme)) {
-      return g_all_of_the_resolvers[i];
-    }
-  }
-
-  return NULL;
-}
-
-static grpc_resolver_factory *resolve_factory(const char *target,
-                                              grpc_uri **uri) {
-  char *tmp;
-  grpc_resolver_factory *factory = NULL;
-
-  GPR_ASSERT(uri != NULL);
-  *uri = grpc_uri_parse(target, 1);
-  factory = lookup_factory(*uri);
-  if (factory == NULL) {
-    if (g_default_resolver_prefix != NULL) {
-      grpc_uri_destroy(*uri);
-      gpr_asprintf(&tmp, "%s%s", g_default_resolver_prefix, target);
-      *uri = grpc_uri_parse(tmp, 1);
-      factory = lookup_factory(*uri);
-      if (factory == NULL) {
-        grpc_uri_destroy(grpc_uri_parse(target, 0));
-        grpc_uri_destroy(grpc_uri_parse(tmp, 0));
-        gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target,
-                tmp);
-      }
-      gpr_free(tmp);
-    } else {
-      grpc_uri_destroy(grpc_uri_parse(target, 0));
-      gpr_log(GPR_ERROR, "don't know how to resolve '%s'", target);
-    }
-  }
-  return factory;
-}
-
-grpc_resolver *grpc_resolver_create(
-    const char *target, grpc_subchannel_factory *subchannel_factory) {
-  grpc_uri *uri = NULL;
-  grpc_resolver_factory *factory = resolve_factory(target, &uri);
-  grpc_resolver *resolver;
-  grpc_resolver_args args;
-  memset(&args, 0, sizeof(args));
-  args.uri = uri;
-  args.subchannel_factory = subchannel_factory;
-  resolver = grpc_resolver_factory_create_resolver(factory, &args);
-  grpc_uri_destroy(uri);
-  return resolver;
-}
-
-char *grpc_get_default_authority(const char *target) {
-  grpc_uri *uri = NULL;
-  grpc_resolver_factory *factory = resolve_factory(target, &uri);
-  char *authority = grpc_resolver_factory_get_default_authority(factory, uri);
-  grpc_uri_destroy(uri);
-  return authority;
-}
diff --git a/src/core/client_config/resolver_registry.h b/src/core/client_config/resolver_registry.h
deleted file mode 100644
index 5a7193b..0000000
--- a/src/core/client_config/resolver_registry.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_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(grpc_resolver_factory *factory);
-
-/** Create a resolver given \a target.
-    First tries to parse \a target 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 target, 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 *target, grpc_subchannel_factory *subchannel_factory);
-
-/** Given a target, return a (freshly allocated with gpr_malloc) string
-    representing the default authority to pass from a client. */
-char *grpc_get_default_authority(const char *target);
-
-#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
deleted file mode 100644
index 376b6b3..0000000
--- a/src/core/client_config/resolvers/dns_resolver.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/client_config/resolvers/dns_resolver.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/client_config/lb_policy_registry.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 name */
-  char *lb_policy_name;
-
-  /** 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_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_exec_ctx *exec_ctx, grpc_resolver *r);
-
-static void dns_start_resolving_locked(dns_resolver *r);
-static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
-                                         dns_resolver *r);
-
-static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
-static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
-static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
-                     grpc_client_config **target_config,
-                     grpc_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_exec_ctx *exec_ctx, grpc_resolver *resolver) {
-  dns_resolver *r = (dns_resolver *)resolver;
-  gpr_mu_lock(&r->mu);
-  if (r->next_completion != NULL) {
-    *r->target_config = NULL;
-    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
-    r->next_completion = NULL;
-  }
-  gpr_mu_unlock(&r->mu);
-}
-
-static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx,
-                                  grpc_resolver *resolver) {
-  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_exec_ctx *exec_ctx, grpc_resolver *resolver,
-                     grpc_client_config **target_config,
-                     grpc_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(exec_ctx, r);
-  }
-  gpr_mu_unlock(&r->mu);
-}
-
-static void dns_on_resolved(grpc_exec_ctx *exec_ctx, 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) {
-    grpc_lb_policy_args lb_policy_args;
-    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 = (size_t)addresses->addrs[i].len;
-      subchannels[i] = grpc_subchannel_factory_create_subchannel(
-          exec_ctx, r->subchannel_factory, &args);
-    }
-    memset(&lb_policy_args, 0, sizeof(lb_policy_args));
-    lb_policy_args.subchannels = subchannels;
-    lb_policy_args.num_subchannels = addresses->naddrs;
-    lb_policy = grpc_lb_policy_create(r->lb_policy_name, &lb_policy_args);
-    grpc_client_config_set_lb_policy(config, lb_policy);
-    GRPC_LB_POLICY_UNREF(exec_ctx, 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(exec_ctx, r->resolved_config);
-  }
-  r->resolved_config = config;
-  r->resolved_version++;
-  dns_maybe_finish_next_locked(exec_ctx, r);
-  gpr_mu_unlock(&r->mu);
-
-  GRPC_RESOLVER_UNREF(exec_ctx, &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(grpc_exec_ctx *exec_ctx,
-                                         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_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
-    r->next_completion = NULL;
-    r->published_version = r->resolved_version;
-  }
-}
-
-static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
-  dns_resolver *r = (dns_resolver *)gr;
-  gpr_mu_destroy(&r->mu);
-  if (r->resolved_config) {
-    grpc_client_config_unref(exec_ctx, r->resolved_config);
-  }
-  grpc_subchannel_factory_unref(exec_ctx, r->subchannel_factory);
-  gpr_free(r->name);
-  gpr_free(r->default_port);
-  gpr_free(r->lb_policy_name);
-  gpr_free(r);
-}
-
-static grpc_resolver *dns_create(grpc_resolver_args *args,
-                                 const char *default_port,
-                                 const char *lb_policy_name) {
-  dns_resolver *r;
-  const char *path = args->uri->path;
-
-  if (0 != strcmp(args->uri->authority, "")) {
-    gpr_log(GPR_ERROR, "authority based dns 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 = args->subchannel_factory;
-  grpc_subchannel_factory_ref(r->subchannel_factory);
-  r->lb_policy_name = gpr_strdup(lb_policy_name);
-  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_resolver_args *args) {
-  return dns_create(args, "https", "pick_first");
-}
-
-char *dns_factory_get_default_host_name(grpc_resolver_factory *factory,
-                                        grpc_uri *uri) {
-  const char *path = uri->path;
-  if (path[0] == '/') ++path;
-  return gpr_strdup(path);
-}
-
-static const grpc_resolver_factory_vtable dns_factory_vtable = {
-    dns_factory_ref, dns_factory_unref, dns_factory_create_resolver,
-    dns_factory_get_default_host_name, "dns"};
-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/client_config/resolvers/dns_resolver.h b/src/core/client_config/resolvers/dns_resolver.h
deleted file mode 100644
index a3ef316..0000000
--- a/src/core/client_config/resolvers/dns_resolver.h
+++ /dev/null
@@ -1,42 +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_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H
-
-#include "src/core/client_config/resolver_factory.h"
-
-/** Create a dns resolver factory */
-grpc_resolver_factory *grpc_dns_resolver_factory_create(void);
-
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H */
diff --git a/src/core/client_config/resolvers/sockaddr_resolver.c b/src/core/client_config/resolvers/sockaddr_resolver.c
deleted file mode 100644
index 68910ad..0000000
--- a/src/core/client_config/resolvers/sockaddr_resolver.c
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/client_config/resolvers/sockaddr_resolver.h"
-
-#include <stdio.h>
-#include <string.h>
-#ifdef GPR_POSIX_SOCKET
-#include <sys/un.h>
-#endif
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/client_config/lb_policy_registry.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 name */
-  char *lb_policy_name;
-
-  /** the addresses that we've 'resolved' */
-  struct sockaddr_storage *addrs;
-  /** the corresponding length of the addresses */
-  size_t *addrs_len;
-  /** how many elements in \a addrs */
-  size_t num_addrs;
-
-  /** mutex guarding the rest of the state */
-  gpr_mu mu;
-  /** have we published? */
-  int published;
-  /** pending next completion, or NULL */
-  grpc_closure *next_completion;
-  /** target config address for next completion */
-  grpc_client_config **target_config;
-} sockaddr_resolver;
-
-static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
-
-static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
-                                              sockaddr_resolver *r);
-
-static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
-static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx,
-                                       grpc_resolver *r);
-static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
-                          grpc_client_config **target_config,
-                          grpc_closure *on_complete);
-
-static const grpc_resolver_vtable sockaddr_resolver_vtable = {
-    sockaddr_destroy, sockaddr_shutdown, sockaddr_channel_saw_error,
-    sockaddr_next};
-
-static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx,
-                              grpc_resolver *resolver) {
-  sockaddr_resolver *r = (sockaddr_resolver *)resolver;
-  gpr_mu_lock(&r->mu);
-  if (r->next_completion != NULL) {
-    *r->target_config = NULL;
-    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
-    r->next_completion = NULL;
-  }
-  gpr_mu_unlock(&r->mu);
-}
-
-static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx,
-                                       grpc_resolver *resolver) {
-  sockaddr_resolver *r = (sockaddr_resolver *)resolver;
-  gpr_mu_lock(&r->mu);
-  r->published = 0;
-  sockaddr_maybe_finish_next_locked(exec_ctx, r);
-  gpr_mu_unlock(&r->mu);
-}
-
-static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
-                          grpc_client_config **target_config,
-                          grpc_closure *on_complete) {
-  sockaddr_resolver *r = (sockaddr_resolver *)resolver;
-  gpr_mu_lock(&r->mu);
-  GPR_ASSERT(!r->next_completion);
-  r->next_completion = on_complete;
-  r->target_config = target_config;
-  sockaddr_maybe_finish_next_locked(exec_ctx, r);
-  gpr_mu_unlock(&r->mu);
-}
-
-static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
-                                              sockaddr_resolver *r) {
-  grpc_client_config *cfg;
-  grpc_lb_policy *lb_policy;
-  grpc_lb_policy_args lb_policy_args;
-  grpc_subchannel **subchannels;
-  grpc_subchannel_args args;
-
-  if (r->next_completion != NULL && !r->published) {
-    size_t i;
-    cfg = grpc_client_config_create();
-    subchannels = gpr_malloc(sizeof(grpc_subchannel *) * r->num_addrs);
-    for (i = 0; i < r->num_addrs; i++) {
-      memset(&args, 0, sizeof(args));
-      args.addr = (struct sockaddr *)&r->addrs[i];
-      args.addr_len = r->addrs_len[i];
-      subchannels[i] = grpc_subchannel_factory_create_subchannel(
-          exec_ctx, r->subchannel_factory, &args);
-    }
-    memset(&lb_policy_args, 0, sizeof(lb_policy_args));
-    lb_policy_args.subchannels = subchannels;
-    lb_policy_args.num_subchannels = r->num_addrs;
-    lb_policy = grpc_lb_policy_create(r->lb_policy_name, &lb_policy_args);
-    gpr_free(subchannels);
-    grpc_client_config_set_lb_policy(cfg, lb_policy);
-    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "sockaddr");
-    r->published = 1;
-    *r->target_config = cfg;
-    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
-    r->next_completion = NULL;
-  }
-}
-
-static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
-  sockaddr_resolver *r = (sockaddr_resolver *)gr;
-  gpr_mu_destroy(&r->mu);
-  grpc_subchannel_factory_unref(exec_ctx, r->subchannel_factory);
-  gpr_free(r->addrs);
-  gpr_free(r->addrs_len);
-  gpr_free(r->lb_policy_name);
-  gpr_free(r);
-}
-
-#ifdef GPR_POSIX_SOCKET
-static int parse_unix(grpc_uri *uri, struct sockaddr_storage *addr,
-                      size_t *len) {
-  struct sockaddr_un *un = (struct sockaddr_un *)addr;
-
-  un->sun_family = AF_UNIX;
-  strcpy(un->sun_path, uri->path);
-  *len = strlen(un->sun_path) + sizeof(un->sun_family) + 1;
-
-  return 1;
-}
-
-static char *unix_get_default_authority(grpc_resolver_factory *factory,
-                                        grpc_uri *uri) {
-  return gpr_strdup("localhost");
-}
-#endif
-
-static char *ip_get_default_authority(grpc_uri *uri) {
-  const char *path = uri->path;
-  if (path[0] == '/') ++path;
-  return gpr_strdup(path);
-}
-
-static char *ipv4_get_default_authority(grpc_resolver_factory *factory,
-                                        grpc_uri *uri) {
-  return ip_get_default_authority(uri);
-}
-
-static char *ipv6_get_default_authority(grpc_resolver_factory *factory,
-                                        grpc_uri *uri) {
-  return ip_get_default_authority(uri);
-}
-
-static int parse_ipv4(grpc_uri *uri, struct sockaddr_storage *addr,
-                      size_t *len) {
-  const char *host_port = uri->path;
-  char *host;
-  char *port;
-  int port_num;
-  int result = 0;
-  struct sockaddr_in *in = (struct sockaddr_in *)addr;
-
-  if (*host_port == '/') ++host_port;
-  if (!gpr_split_host_port(host_port, &host, &port)) {
-    return 0;
-  }
-
-  memset(in, 0, sizeof(*in));
-  *len = sizeof(*in);
-  in->sin_family = AF_INET;
-  if (inet_pton(AF_INET, host, &in->sin_addr) == 0) {
-    gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host);
-    goto done;
-  }
-
-  if (port != NULL) {
-    if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 ||
-        port_num > 65535) {
-      gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port);
-      goto done;
-    }
-    in->sin_port = htons((uint16_t)port_num);
-  } else {
-    gpr_log(GPR_ERROR, "no port given for ipv4 scheme");
-    goto done;
-  }
-
-  result = 1;
-done:
-  gpr_free(host);
-  gpr_free(port);
-  return result;
-}
-
-static int parse_ipv6(grpc_uri *uri, struct sockaddr_storage *addr,
-                      size_t *len) {
-  const char *host_port = uri->path;
-  char *host;
-  char *port;
-  int port_num;
-  int result = 0;
-  struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
-
-  if (*host_port == '/') ++host_port;
-  if (!gpr_split_host_port(host_port, &host, &port)) {
-    return 0;
-  }
-
-  memset(in6, 0, sizeof(*in6));
-  *len = sizeof(*in6);
-  in6->sin6_family = AF_INET6;
-  if (inet_pton(AF_INET6, host, &in6->sin6_addr) == 0) {
-    gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host);
-    goto done;
-  }
-
-  if (port != NULL) {
-    if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 ||
-        port_num > 65535) {
-      gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port);
-      goto done;
-    }
-    in6->sin6_port = htons((uint16_t)port_num);
-  } else {
-    gpr_log(GPR_ERROR, "no port given for ipv6 scheme");
-    goto done;
-  }
-
-  result = 1;
-done:
-  gpr_free(host);
-  gpr_free(port);
-  return result;
-}
-
-static void do_nothing(void *ignored) {}
-
-static grpc_resolver *sockaddr_create(
-    grpc_resolver_args *args, const char *default_lb_policy_name,
-    int parse(grpc_uri *uri, struct sockaddr_storage *dst, size_t *len)) {
-  size_t i;
-  int errors_found = 0; /* GPR_FALSE */
-  sockaddr_resolver *r;
-  gpr_slice path_slice;
-  gpr_slice_buffer path_parts;
-
-  if (0 != strcmp(args->uri->authority, "")) {
-    gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme",
-            args->uri->scheme);
-    return NULL;
-  }
-
-  r = gpr_malloc(sizeof(sockaddr_resolver));
-  memset(r, 0, sizeof(*r));
-
-  r->lb_policy_name = NULL;
-  if (0 != strcmp(args->uri->query, "")) {
-    gpr_slice query_slice;
-    gpr_slice_buffer query_parts;
-
-    query_slice =
-        gpr_slice_new(args->uri->query, strlen(args->uri->query), do_nothing);
-    gpr_slice_buffer_init(&query_parts);
-    gpr_slice_split(query_slice, "=", &query_parts);
-    GPR_ASSERT(query_parts.count == 2);
-    if (0 == gpr_slice_str_cmp(query_parts.slices[0], "lb_policy")) {
-      r->lb_policy_name = gpr_dump_slice(query_parts.slices[1], GPR_DUMP_ASCII);
-    }
-    gpr_slice_buffer_destroy(&query_parts);
-    gpr_slice_unref(query_slice);
-  }
-  if (r->lb_policy_name == NULL) {
-    r->lb_policy_name = gpr_strdup(default_lb_policy_name);
-  }
-
-  path_slice =
-      gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing);
-  gpr_slice_buffer_init(&path_parts);
-
-  gpr_slice_split(path_slice, ",", &path_parts);
-  r->num_addrs = path_parts.count;
-  r->addrs = gpr_malloc(sizeof(struct sockaddr_storage) * r->num_addrs);
-  r->addrs_len = gpr_malloc(sizeof(*r->addrs_len) * r->num_addrs);
-
-  for (i = 0; i < r->num_addrs; i++) {
-    grpc_uri ith_uri = *args->uri;
-    char *part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII);
-    ith_uri.path = part_str;
-    if (!parse(&ith_uri, &r->addrs[i], &r->addrs_len[i])) {
-      errors_found = 1; /* GPR_TRUE */
-    }
-    gpr_free(part_str);
-    if (errors_found) break;
-  }
-
-  gpr_slice_buffer_destroy(&path_parts);
-  gpr_slice_unref(path_slice);
-  if (errors_found) {
-    gpr_free(r->lb_policy_name);
-    gpr_free(r->addrs);
-    gpr_free(r->addrs_len);
-    gpr_free(r);
-    return NULL;
-  }
-
-  gpr_ref_init(&r->refs, 1);
-  gpr_mu_init(&r->mu);
-  grpc_resolver_init(&r->base, &sockaddr_resolver_vtable);
-  r->subchannel_factory = args->subchannel_factory;
-  grpc_subchannel_factory_ref(r->subchannel_factory);
-
-  return &r->base;
-}
-
-/*
- * FACTORY
- */
-
-static void sockaddr_factory_ref(grpc_resolver_factory *factory) {}
-
-static void sockaddr_factory_unref(grpc_resolver_factory *factory) {}
-
-#define DECL_FACTORY(name)                                                  \
-  static grpc_resolver *name##_factory_create_resolver(                     \
-      grpc_resolver_factory *factory, grpc_resolver_args *args) {           \
-    return sockaddr_create(args, "pick_first", parse_##name);               \
-  }                                                                         \
-  static const grpc_resolver_factory_vtable name##_factory_vtable = {       \
-      sockaddr_factory_ref, sockaddr_factory_unref,                         \
-      name##_factory_create_resolver, name##_get_default_authority, #name}; \
-  static grpc_resolver_factory name##_resolver_factory = {                  \
-      &name##_factory_vtable};                                              \
-  grpc_resolver_factory *grpc_##name##_resolver_factory_create() {          \
-    return &name##_resolver_factory;                                        \
-  }
-
-#ifdef GPR_POSIX_SOCKET
-DECL_FACTORY(unix)
-#endif
-DECL_FACTORY(ipv4) DECL_FACTORY(ipv6)
diff --git a/src/core/client_config/resolvers/sockaddr_resolver.h b/src/core/client_config/resolvers/sockaddr_resolver.h
deleted file mode 100644
index 1b7a18f..0000000
--- a/src/core/client_config/resolvers/sockaddr_resolver.h
+++ /dev/null
@@ -1,50 +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_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/client_config/resolver_factory.h"
-
-grpc_resolver_factory *grpc_ipv4_resolver_factory_create(void);
-
-grpc_resolver_factory *grpc_ipv6_resolver_factory_create(void);
-
-#ifdef GPR_POSIX_SOCKET
-/** Create a unix resolver factory */
-grpc_resolver_factory *grpc_unix_resolver_factory_create(void);
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_UNIX_RESOLVER_H */
diff --git a/src/core/client_config/resolvers/zookeeper_resolver.c b/src/core/client_config/resolvers/zookeeper_resolver.c
deleted file mode 100644
index 166738e..0000000
--- a/src/core/client_config/resolvers/zookeeper_resolver.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/client_config/resolvers/zookeeper_resolver.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/string_util.h>
-
-#include <grpc/grpc_zookeeper.h>
-#include <zookeeper/zookeeper.h>
-
-#include "src/core/client_config/lb_policy_registry.h"
-#include "src/core/client_config/resolver_registry.h"
-#include "src/core/iomgr/resolve_address.h"
-#include "src/core/support/string.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/json/json.h"
-
-/** Zookeeper session expiration time in milliseconds */
-#define GRPC_ZOOKEEPER_SESSION_TIMEOUT 15000
-
-typedef struct {
-  /** base class: must be first */
-  grpc_resolver base;
-  /** refcount */
-  gpr_refcount refs;
-  /** name to resolve */
-  char *name;
-  /** subchannel factory */
-  grpc_subchannel_factory *subchannel_factory;
-  /** load balancing policy name */
-  char *lb_policy_name;
-
-  /** 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_closure *next_completion;
-  /** target config address for next completion */
-  grpc_client_config **target_config;
-  /** current (fully resolved) config */
-  grpc_client_config *resolved_config;
-
-  /** zookeeper handle */
-  zhandle_t *zookeeper_handle;
-  /** zookeeper resolved addresses */
-  grpc_resolved_addresses *resolved_addrs;
-  /** total number of addresses to be resolved */
-  int resolved_total;
-  /** number of addresses resolved */
-  int resolved_num;
-} zookeeper_resolver;
-
-static void zookeeper_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
-
-static void zookeeper_start_resolving_locked(zookeeper_resolver *r);
-static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
-                                               zookeeper_resolver *r);
-
-static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
-static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx,
-                                        grpc_resolver *r);
-static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
-                           grpc_client_config **target_config,
-                           grpc_closure *on_complete);
-
-static const grpc_resolver_vtable zookeeper_resolver_vtable = {
-    zookeeper_destroy, zookeeper_shutdown, zookeeper_channel_saw_error,
-    zookeeper_next};
-
-static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx,
-                               grpc_resolver *resolver) {
-  zookeeper_resolver *r = (zookeeper_resolver *)resolver;
-  grpc_closure *call = NULL;
-  gpr_mu_lock(&r->mu);
-  if (r->next_completion != NULL) {
-    *r->target_config = NULL;
-    call = r->next_completion;
-    r->next_completion = NULL;
-  }
-  zookeeper_close(r->zookeeper_handle);
-  gpr_mu_unlock(&r->mu);
-  if (call != NULL) {
-    call->cb(exec_ctx, call->cb_arg, 1);
-  }
-}
-
-static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx,
-                                        grpc_resolver *resolver) {
-  zookeeper_resolver *r = (zookeeper_resolver *)resolver;
-  gpr_mu_lock(&r->mu);
-  if (r->resolving == 0) {
-    zookeeper_start_resolving_locked(r);
-  }
-  gpr_mu_unlock(&r->mu);
-}
-
-static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
-                           grpc_client_config **target_config,
-                           grpc_closure *on_complete) {
-  zookeeper_resolver *r = (zookeeper_resolver *)resolver;
-  gpr_mu_lock(&r->mu);
-  GPR_ASSERT(r->next_completion == NULL);
-  r->next_completion = on_complete;
-  r->target_config = target_config;
-  if (r->resolved_version == 0 && r->resolving == 0) {
-    zookeeper_start_resolving_locked(r);
-  } else {
-    zookeeper_maybe_finish_next_locked(exec_ctx, r);
-  }
-  gpr_mu_unlock(&r->mu);
-}
-
-/** Zookeeper global watcher for connection management
-    TODO: better connection management besides logs */
-static void zookeeper_global_watcher(zhandle_t *zookeeper_handle, int type,
-                                     int state, const char *path,
-                                     void *watcher_ctx) {
-  if (type == ZOO_SESSION_EVENT) {
-    if (state == ZOO_EXPIRED_SESSION_STATE) {
-      gpr_log(GPR_ERROR, "Zookeeper session expired");
-    } else if (state == ZOO_AUTH_FAILED_STATE) {
-      gpr_log(GPR_ERROR, "Zookeeper authentication failed");
-    }
-  }
-}
-
-/** Zookeeper watcher triggered by changes to watched nodes
-    Once triggered, it tries to resolve again to get updated addresses */
-static void zookeeper_watcher(zhandle_t *zookeeper_handle, int type, int state,
-                              const char *path, void *watcher_ctx) {
-  if (watcher_ctx != NULL) {
-    zookeeper_resolver *r = (zookeeper_resolver *)watcher_ctx;
-    if (state == ZOO_CONNECTED_STATE) {
-      gpr_mu_lock(&r->mu);
-      if (r->resolving == 0) {
-        zookeeper_start_resolving_locked(r);
-      }
-      gpr_mu_unlock(&r->mu);
-    }
-  }
-}
-
-/** Callback function after getting all resolved addresses
-    Creates a subchannel for each address */
-static void zookeeper_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
-                                  grpc_resolved_addresses *addresses) {
-  zookeeper_resolver *r = arg;
-  grpc_client_config *config = NULL;
-  grpc_subchannel **subchannels;
-  grpc_subchannel_args args;
-  grpc_lb_policy *lb_policy;
-  size_t i;
-  if (addresses != NULL) {
-    grpc_lb_policy_args lb_policy_args;
-    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(
-          exec_ctx, r->subchannel_factory, &args);
-    }
-    lb_policy_args.subchannels = subchannels;
-    lb_policy_args.num_subchannels = addresses->naddrs;
-    lb_policy = grpc_lb_policy_create(r->lb_policy_name, &lb_policy_args);
-    grpc_client_config_set_lb_policy(config, lb_policy);
-    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction");
-    grpc_resolved_addresses_destroy(addresses);
-    gpr_free(subchannels);
-  }
-  gpr_mu_lock(&r->mu);
-  GPR_ASSERT(r->resolving == 1);
-  r->resolving = 0;
-  if (r->resolved_config != NULL) {
-    grpc_client_config_unref(exec_ctx, r->resolved_config);
-  }
-  r->resolved_config = config;
-  r->resolved_version++;
-  zookeeper_maybe_finish_next_locked(exec_ctx, r);
-  gpr_mu_unlock(&r->mu);
-
-  GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "zookeeper-resolving");
-}
-
-/** Callback function for each DNS resolved address */
-static void zookeeper_dns_resolved(grpc_exec_ctx *exec_ctx, void *arg,
-                                   grpc_resolved_addresses *addresses) {
-  size_t i;
-  zookeeper_resolver *r = arg;
-  int resolve_done = 0;
-
-  gpr_mu_lock(&r->mu);
-  r->resolved_num++;
-  r->resolved_addrs->addrs =
-      gpr_realloc(r->resolved_addrs->addrs,
-                  sizeof(grpc_resolved_address) *
-                      (r->resolved_addrs->naddrs + addresses->naddrs));
-  for (i = 0; i < addresses->naddrs; i++) {
-    memcpy(r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].addr,
-           addresses->addrs[i].addr, addresses->addrs[i].len);
-    r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].len =
-        addresses->addrs[i].len;
-  }
-
-  r->resolved_addrs->naddrs += addresses->naddrs;
-  grpc_resolved_addresses_destroy(addresses);
-
-  /** Wait for all addresses to be resolved */
-  resolve_done = (r->resolved_num == r->resolved_total);
-  gpr_mu_unlock(&r->mu);
-  if (resolve_done) {
-    zookeeper_on_resolved(exec_ctx, r, r->resolved_addrs);
-  }
-}
-
-/** Parses JSON format address of a zookeeper node */
-static char *zookeeper_parse_address(const char *value, size_t value_len) {
-  grpc_json *json;
-  grpc_json *cur;
-  const char *host;
-  const char *port;
-  char *buffer;
-  char *address = NULL;
-
-  buffer = gpr_malloc(value_len);
-  memcpy(buffer, value, value_len);
-  json = grpc_json_parse_string_with_len(buffer, value_len);
-  if (json != NULL) {
-    host = NULL;
-    port = NULL;
-    for (cur = json->child; cur != NULL; cur = cur->next) {
-      if (!strcmp(cur->key, "host")) {
-        host = cur->value;
-        if (port != NULL) {
-          break;
-        }
-      } else if (!strcmp(cur->key, "port")) {
-        port = cur->value;
-        if (host != NULL) {
-          break;
-        }
-      }
-    }
-    if (host != NULL && port != NULL) {
-      gpr_asprintf(&address, "%s:%s", host, port);
-    }
-    grpc_json_destroy(json);
-  }
-  gpr_free(buffer);
-
-  return address;
-}
-
-static void zookeeper_get_children_node_completion(int rc, const char *value,
-                                                   int value_len,
-                                                   const struct Stat *stat,
-                                                   const void *arg) {
-  char *address = NULL;
-  zookeeper_resolver *r = (zookeeper_resolver *)arg;
-  int resolve_done = 0;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  if (rc != 0) {
-    gpr_log(GPR_ERROR, "Error in getting a child node of %s", r->name);
-    grpc_exec_ctx_finish(&exec_ctx);
-    return;
-  }
-
-  address = zookeeper_parse_address(value, (size_t)value_len);
-  if (address != NULL) {
-    /** Further resolves address by DNS */
-    grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r);
-    gpr_free(address);
-  } else {
-    gpr_log(GPR_ERROR, "Error in resolving a child node of %s", r->name);
-    gpr_mu_lock(&r->mu);
-    r->resolved_total--;
-    resolve_done = (r->resolved_num == r->resolved_total);
-    gpr_mu_unlock(&r->mu);
-    if (resolve_done) {
-      zookeeper_on_resolved(&exec_ctx, r, r->resolved_addrs);
-    }
-  }
-
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-static void zookeeper_get_children_completion(
-    int rc, const struct String_vector *children, const void *arg) {
-  char *path;
-  int status;
-  int i;
-  zookeeper_resolver *r = (zookeeper_resolver *)arg;
-
-  if (rc != 0) {
-    gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name);
-    return;
-  }
-
-  if (children->count == 0) {
-    gpr_log(GPR_ERROR, "Error in resolving zookeeper address %s", r->name);
-    return;
-  }
-
-  r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
-  r->resolved_addrs->addrs = NULL;
-  r->resolved_addrs->naddrs = 0;
-  r->resolved_total = children->count;
-
-  /** TODO: Replace expensive heap allocation with stack
-      if we can get maximum length of zookeeper path */
-  for (i = 0; i < children->count; i++) {
-    gpr_asprintf(&path, "%s/%s", r->name, children->data[i]);
-    status = zoo_awget(r->zookeeper_handle, path, zookeeper_watcher, r,
-                       zookeeper_get_children_node_completion, r);
-    gpr_free(path);
-    if (status != 0) {
-      gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", path);
-    }
-  }
-}
-
-static void zookeeper_get_node_completion(int rc, const char *value,
-                                          int value_len,
-                                          const struct Stat *stat,
-                                          const void *arg) {
-  int status;
-  char *address = NULL;
-  zookeeper_resolver *r = (zookeeper_resolver *)arg;
-  r->resolved_addrs = NULL;
-  r->resolved_total = 0;
-  r->resolved_num = 0;
-
-  if (rc != 0) {
-    gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name);
-    return;
-  }
-
-  /** If zookeeper node of path r->name does not have address
-      (i.e. service node), get its children */
-  address = zookeeper_parse_address(value, (size_t)value_len);
-  if (address != NULL) {
-    r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
-    r->resolved_addrs->addrs = NULL;
-    r->resolved_addrs->naddrs = 0;
-    r->resolved_total = 1;
-    /** Further resolves address by DNS */
-    grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r);
-    gpr_free(address);
-    return;
-  }
-
-  status = zoo_awget_children(r->zookeeper_handle, r->name, zookeeper_watcher,
-                              r, zookeeper_get_children_completion, r);
-  if (status != 0) {
-    gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name);
-  }
-}
-
-static void zookeeper_resolve_address(zookeeper_resolver *r) {
-  int status;
-  status = zoo_awget(r->zookeeper_handle, r->name, zookeeper_watcher, r,
-                     zookeeper_get_node_completion, r);
-  if (status != 0) {
-    gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name);
-  }
-}
-
-static void zookeeper_start_resolving_locked(zookeeper_resolver *r) {
-  GRPC_RESOLVER_REF(&r->base, "zookeeper-resolving");
-  GPR_ASSERT(r->resolving == 0);
-  r->resolving = 1;
-  zookeeper_resolve_address(r);
-}
-
-static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
-                                               zookeeper_resolver *r) {
-  if (r->next_completion != NULL &&
-      r->resolved_version != r->published_version) {
-    *r->target_config = r->resolved_config;
-    if (r->resolved_config != NULL) {
-      grpc_client_config_ref(r->resolved_config);
-    }
-    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
-    r->next_completion = NULL;
-    r->published_version = r->resolved_version;
-  }
-}
-
-static void zookeeper_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
-  zookeeper_resolver *r = (zookeeper_resolver *)gr;
-  gpr_mu_destroy(&r->mu);
-  if (r->resolved_config != NULL) {
-    grpc_client_config_unref(exec_ctx, r->resolved_config);
-  }
-  grpc_subchannel_factory_unref(exec_ctx, r->subchannel_factory);
-  gpr_free(r->name);
-  gpr_free(r->lb_policy_name);
-  gpr_free(r);
-}
-
-static grpc_resolver *zookeeper_create(grpc_resolver_args *args,
-                                       const char *lb_policy_name) {
-  zookeeper_resolver *r;
-  size_t length;
-  char *path = args->uri->path;
-
-  if (0 == strcmp(args->uri->authority, "")) {
-    gpr_log(GPR_ERROR, "No authority specified in zookeeper uri");
-    return NULL;
-  }
-
-  /** Removes the trailing slash if exists */
-  length = strlen(path);
-  if (length > 1 && path[length - 1] == '/') {
-    path[length - 1] = 0;
-  }
-
-  r = gpr_malloc(sizeof(zookeeper_resolver));
-  memset(r, 0, sizeof(*r));
-  gpr_ref_init(&r->refs, 1);
-  gpr_mu_init(&r->mu);
-  grpc_resolver_init(&r->base, &zookeeper_resolver_vtable);
-  r->name = gpr_strdup(path);
-
-  r->subchannel_factory = args->subchannel_factory;
-  grpc_subchannel_factory_ref(r->subchannel_factory);
-
-  r->lb_policy_name = gpr_strdup(lb_policy_name);
-
-  /** Initializes zookeeper client */
-  zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
-  r->zookeeper_handle =
-      zookeeper_init(args->uri->authority, zookeeper_global_watcher,
-                     GRPC_ZOOKEEPER_SESSION_TIMEOUT, 0, 0, 0);
-  if (r->zookeeper_handle == NULL) {
-    gpr_log(GPR_ERROR, "Unable to connect to zookeeper server");
-    return NULL;
-  }
-
-  return &r->base;
-}
-
-static void zookeeper_plugin_init() {
-  grpc_register_resolver_type(grpc_zookeeper_resolver_factory_create());
-}
-
-void grpc_zookeeper_register() {
-  GRPC_API_TRACE("grpc_zookeeper_register(void)", 0, ());
-  grpc_register_plugin(zookeeper_plugin_init, NULL);
-}
-
-/*
- * FACTORY
- */
-
-static void zookeeper_factory_ref(grpc_resolver_factory *factory) {}
-
-static void zookeeper_factory_unref(grpc_resolver_factory *factory) {}
-
-static char *zookeeper_factory_get_default_hostname(
-    grpc_resolver_factory *factory, grpc_uri *uri) {
-  return NULL;
-}
-
-static grpc_resolver *zookeeper_factory_create_resolver(
-    grpc_resolver_factory *factory, grpc_resolver_args *args) {
-  return zookeeper_create(args, "pick_first");
-}
-
-static const grpc_resolver_factory_vtable zookeeper_factory_vtable = {
-    zookeeper_factory_ref, zookeeper_factory_unref,
-    zookeeper_factory_create_resolver, zookeeper_factory_get_default_hostname,
-    "zookeeper"};
-
-static grpc_resolver_factory zookeeper_resolver_factory = {
-    &zookeeper_factory_vtable};
-
-grpc_resolver_factory *grpc_zookeeper_resolver_factory_create() {
-  return &zookeeper_resolver_factory;
-}
diff --git a/src/core/client_config/resolvers/zookeeper_resolver.h b/src/core/client_config/resolvers/zookeeper_resolver.h
deleted file mode 100644
index a6f002d..0000000
--- a/src/core/client_config/resolvers/zookeeper_resolver.h
+++ /dev/null
@@ -1,42 +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_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H
-
-#include "src/core/client_config/resolver_factory.h"
-
-/** Create a zookeeper resolver factory */
-grpc_resolver_factory *grpc_zookeeper_resolver_factory_create(void);
-
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H */
diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c
deleted file mode 100644
index d91dd11..0000000
--- a/src/core/client_config/subchannel.c
+++ /dev/null
@@ -1,738 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/client_config/subchannel.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/avl.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/client_config/initial_connect_string.h"
-#include "src/core/client_config/subchannel_index.h"
-#include "src/core/iomgr/timer.h"
-#include "src/core/profiling/timers.h"
-#include "src/core/surface/channel.h"
-#include "src/core/transport/connectivity_state.h"
-
-#define INTERNAL_REF_BITS 16
-#define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1))
-
-#define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20
-#define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1
-#define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6
-#define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120
-#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2
-
-#define GET_CONNECTED_SUBCHANNEL(subchannel, barrier)      \
-  ((grpc_connected_subchannel *)(gpr_atm_##barrier##_load( \
-      &(subchannel)->connected_subchannel)))
-
-typedef struct {
-  grpc_closure closure;
-  grpc_subchannel *subchannel;
-  grpc_connectivity_state connectivity_state;
-} state_watcher;
-
-typedef struct external_state_watcher {
-  grpc_subchannel *subchannel;
-  grpc_pollset_set *pollset_set;
-  grpc_closure *notify;
-  grpc_closure closure;
-  struct external_state_watcher *next;
-  struct external_state_watcher *prev;
-} external_state_watcher;
-
-struct grpc_subchannel {
-  grpc_connector *connector;
-
-  /** refcount
-      - lower INTERNAL_REF_BITS bits are for internal references:
-        these do not keep the subchannel open.
-      - upper remaining bits are for public references: these do
-        keep the subchannel open */
-  gpr_atm ref_pair;
-
-  /** 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;
-
-  grpc_subchannel_key *key;
-
-  /** initial string to send to peer */
-  gpr_slice initial_connect_string;
-
-  /** set during connection */
-  grpc_connect_out_args connecting_result;
-
-  /** callback for connection finishing */
-  grpc_closure connected;
-
-  /** pollset_set tracking who's interested in a connection
-      being setup */
-  grpc_pollset_set *pollset_set;
-
-  /** active connection, or null; of type grpc_connected_subchannel */
-  gpr_atm connected_subchannel;
-
-  /** mutex protecting remaining elements */
-  gpr_mu mu;
-
-  /** have we seen a disconnection? */
-  int disconnected;
-  /** are we connecting */
-  int connecting;
-  /** connectivity state tracking */
-  grpc_connectivity_state_tracker state_tracker;
-
-  external_state_watcher root_external_state_watcher;
-
-  /** 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_timer alarm;
-  /** current random value */
-  uint32_t random;
-};
-
-struct grpc_subchannel_call {
-  grpc_connected_subchannel *connection;
-};
-
-#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1))
-#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)(con))
-#define CALLSTACK_TO_SUBCHANNEL_CALL(callstack) \
-  (((grpc_subchannel_call *)(callstack)) - 1)
-
-static gpr_timespec compute_connect_deadline(grpc_subchannel *c);
-static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel,
-                                 bool iomgr_success);
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-#define REF_REASON reason
-#define REF_LOG(name, p)                                                  \
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p   ref %d -> %d %s", \
-          (name), (p), (p)->refs.count, (p)->refs.count + 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.count, (p)->refs.count - 1, reason)
-#define REF_MUTATE_EXTRA_ARGS \
-  GRPC_SUBCHANNEL_REF_EXTRA_ARGS, const char *purpose
-#define REF_MUTATE_PURPOSE(x) , file, line, reason, x
-#else
-#define REF_REASON ""
-#define REF_LOG(name, p) \
-  do {                   \
-  } while (0)
-#define UNREF_LOG(name, p) \
-  do {                     \
-  } while (0)
-#define REF_MUTATE_EXTRA_ARGS
-#define REF_MUTATE_PURPOSE(x)
-#endif
-
-/*
- * connection implementation
- */
-
-static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg,
-                               bool success) {
-  grpc_connected_subchannel *c = arg;
-  grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c));
-  gpr_free(c);
-}
-
-void grpc_connected_subchannel_ref(grpc_connected_subchannel *c
-                                       GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON);
-}
-
-void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
-                                     grpc_connected_subchannel *c
-                                         GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c),
-                           REF_REASON);
-}
-
-/*
- * grpc_subchannel implementation
- */
-
-static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg,
-                               bool success) {
-  grpc_subchannel *c = arg;
-  gpr_free((void *)c->filters);
-  grpc_channel_args_destroy(c->args);
-  gpr_free(c->addr);
-  gpr_slice_unref(c->initial_connect_string);
-  grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
-  grpc_connector_unref(exec_ctx, c->connector);
-  grpc_pollset_set_destroy(c->pollset_set);
-  grpc_subchannel_key_destroy(exec_ctx, c->key);
-  gpr_free(c);
-}
-
-static gpr_atm ref_mutate(grpc_subchannel *c, gpr_atm delta,
-                          int barrier REF_MUTATE_EXTRA_ARGS) {
-  gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta)
-                            : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-          "SUBCHANNEL: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val,
-          old_val + delta, reason);
-#endif
-  return old_val;
-}
-
-grpc_subchannel *grpc_subchannel_ref(grpc_subchannel *c
-                                         GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  gpr_atm old_refs;
-  old_refs = ref_mutate(c, (1 << INTERNAL_REF_BITS),
-                        0 REF_MUTATE_PURPOSE("STRONG_REF"));
-  GPR_ASSERT((old_refs & STRONG_REF_MASK) != 0);
-  return c;
-}
-
-grpc_subchannel *grpc_subchannel_weak_ref(grpc_subchannel *c
-                                              GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  gpr_atm old_refs;
-  old_refs = ref_mutate(c, 1, 0 REF_MUTATE_PURPOSE("WEAK_REF"));
-  GPR_ASSERT(old_refs != 0);
-  return c;
-}
-
-grpc_subchannel *grpc_subchannel_ref_from_weak_ref(
-    grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  if (!c) return NULL;
-  for (;;) {
-    gpr_atm old_refs = gpr_atm_acq_load(&c->ref_pair);
-    if (old_refs >= (1 << INTERNAL_REF_BITS)) {
-      gpr_atm new_refs = old_refs + (1 << INTERNAL_REF_BITS);
-      if (gpr_atm_rel_cas(&c->ref_pair, old_refs, new_refs)) {
-        return c;
-      }
-    } else {
-      return NULL;
-    }
-  }
-}
-
-static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
-  grpc_connected_subchannel *con;
-  grpc_subchannel_index_unregister(exec_ctx, c->key, c);
-  gpr_mu_lock(&c->mu);
-  GPR_ASSERT(!c->disconnected);
-  c->disconnected = 1;
-  grpc_connector_shutdown(exec_ctx, c->connector);
-  con = GET_CONNECTED_SUBCHANNEL(c, no_barrier);
-  if (con != NULL) {
-    GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection");
-    gpr_atm_no_barrier_store(&c->connected_subchannel, 0xdeadbeef);
-  }
-  gpr_mu_unlock(&c->mu);
-}
-
-void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx,
-                           grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  gpr_atm old_refs;
-  old_refs = ref_mutate(c, (gpr_atm)1 - (gpr_atm)(1 << INTERNAL_REF_BITS),
-                        1 REF_MUTATE_PURPOSE("STRONG_UNREF"));
-  if ((old_refs & STRONG_REF_MASK) == (1 << INTERNAL_REF_BITS)) {
-    disconnect(exec_ctx, c);
-  }
-  GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "strong-unref");
-}
-
-void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
-                                grpc_subchannel *c
-                                    GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  gpr_atm old_refs;
-  old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF"));
-  if (old_refs == 1) {
-    grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(subchannel_destroy, c),
-                          true, NULL);
-  }
-}
-
-static uint32_t random_seed() {
-  return (uint32_t)(gpr_time_to_millis(gpr_now(GPR_CLOCK_MONOTONIC)));
-}
-
-grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
-                                        grpc_connector *connector,
-                                        grpc_subchannel_args *args) {
-  grpc_subchannel_key *key = grpc_subchannel_key_create(connector, args);
-  grpc_subchannel *c = grpc_subchannel_index_find(exec_ctx, key);
-  if (c) {
-    grpc_subchannel_key_destroy(exec_ctx, key);
-    return c;
-  }
-
-  c = gpr_malloc(sizeof(*c));
-  memset(c, 0, sizeof(*c));
-  c->key = key;
-  gpr_atm_no_barrier_store(&c->ref_pair, 1 << INTERNAL_REF_BITS);
-  c->connector = connector;
-  grpc_connector_ref(c->connector);
-  c->num_filters = args->filter_count;
-  if (c->num_filters > 0) {
-    c->filters = gpr_malloc(sizeof(grpc_channel_filter *) * c->num_filters);
-    memcpy((void *)c->filters, args->filters,
-           sizeof(grpc_channel_filter *) * c->num_filters);
-  } else {
-    c->filters = NULL;
-  }
-  c->addr = gpr_malloc(args->addr_len);
-  memcpy(c->addr, args->addr, args->addr_len);
-  c->pollset_set = grpc_pollset_set_create();
-  c->addr_len = args->addr_len;
-  grpc_set_initial_connect_string(&c->addr, &c->addr_len,
-                                  &c->initial_connect_string);
-  c->args = grpc_channel_args_copy(args->args);
-  c->random = random_seed();
-  c->root_external_state_watcher.next = c->root_external_state_watcher.prev =
-      &c->root_external_state_watcher;
-  grpc_closure_init(&c->connected, subchannel_connected, c);
-  grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE,
-                               "subchannel");
-  gpr_mu_init(&c->mu);
-
-  return grpc_subchannel_index_register(exec_ctx, key, c);
-}
-
-static void continue_connect(grpc_exec_ctx *exec_ctx, 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.initial_connect_string = c->initial_connect_string;
-
-  grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
-                              GRPC_CHANNEL_CONNECTING, "state_change");
-  grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result,
-                         &c->connected);
-}
-
-static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
-  c->backoff_delta = gpr_time_from_seconds(
-      GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS, GPR_TIMESPAN);
-  c->next_attempt =
-      gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), c->backoff_delta);
-  continue_connect(exec_ctx, c);
-}
-
-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;
-}
-
-static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg,
-                                           bool success) {
-  external_state_watcher *w = arg;
-  grpc_closure *follow_up = w->notify;
-  if (w->pollset_set != NULL) {
-    grpc_pollset_set_del_pollset_set(exec_ctx, w->subchannel->pollset_set,
-                                     w->pollset_set);
-  }
-  gpr_mu_lock(&w->subchannel->mu);
-  w->next->prev = w->prev;
-  w->prev->next = w->next;
-  gpr_mu_unlock(&w->subchannel->mu);
-  GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, w->subchannel, "external_state_watcher");
-  gpr_free(w);
-  follow_up->cb(exec_ctx, follow_up->cb_arg, success);
-}
-
-void grpc_subchannel_notify_on_state_change(
-    grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
-    grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
-    grpc_closure *notify) {
-  external_state_watcher *w;
-
-  if (state == NULL) {
-    gpr_mu_lock(&c->mu);
-    for (w = c->root_external_state_watcher.next;
-         w != &c->root_external_state_watcher; w = w->next) {
-      if (w->notify == notify) {
-        grpc_connectivity_state_notify_on_state_change(
-            exec_ctx, &c->state_tracker, NULL, &w->closure);
-      }
-    }
-    gpr_mu_unlock(&c->mu);
-  } else {
-    w = gpr_malloc(sizeof(*w));
-    w->subchannel = c;
-    w->pollset_set = interested_parties;
-    w->notify = notify;
-    grpc_closure_init(&w->closure, on_external_state_watcher_done, w);
-    if (interested_parties != NULL) {
-      grpc_pollset_set_add_pollset_set(exec_ctx, c->pollset_set,
-                                       interested_parties);
-    }
-    GRPC_SUBCHANNEL_WEAK_REF(c, "external_state_watcher");
-    gpr_mu_lock(&c->mu);
-    w->next = &c->root_external_state_watcher;
-    w->prev = w->next->prev;
-    w->next->prev = w->prev->next = w;
-    if (grpc_connectivity_state_notify_on_state_change(
-            exec_ctx, &c->state_tracker, state, &w->closure)) {
-      c->connecting = 1;
-      /* released by connection */
-      GRPC_SUBCHANNEL_WEAK_REF(c, "connecting");
-      start_connect(exec_ctx, c);
-    }
-    gpr_mu_unlock(&c->mu);
-  }
-}
-
-void grpc_connected_subchannel_process_transport_op(
-    grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
-    grpc_transport_op *op) {
-  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(exec_ctx, top_elem, op);
-}
-
-static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p,
-                                              bool iomgr_success) {
-  state_watcher *sw = p;
-  grpc_subchannel *c = sw->subchannel;
-  gpr_mu *mu = &c->mu;
-
-  gpr_mu_lock(mu);
-
-  /* if we failed just leave this closure */
-  if (iomgr_success) {
-    if (sw->connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
-      /* any errors on a subchannel ==> we're done, create a new one */
-      sw->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE;
-    }
-    grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
-                                sw->connectivity_state, "reflect_child");
-    if (sw->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) {
-      grpc_connected_subchannel_notify_on_state_change(
-          exec_ctx, GET_CONNECTED_SUBCHANNEL(c, no_barrier), NULL,
-          &sw->connectivity_state, &sw->closure);
-      GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
-      sw = NULL;
-    }
-  }
-
-  gpr_mu_unlock(mu);
-  GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "state_watcher");
-  gpr_free(sw);
-}
-
-static void connected_subchannel_state_op(grpc_exec_ctx *exec_ctx,
-                                          grpc_connected_subchannel *con,
-                                          grpc_pollset_set *interested_parties,
-                                          grpc_connectivity_state *state,
-                                          grpc_closure *closure) {
-  grpc_transport_op op;
-  grpc_channel_element *elem;
-  memset(&op, 0, sizeof(op));
-  op.connectivity_state = state;
-  op.on_connectivity_state_change = closure;
-  op.bind_pollset_set = interested_parties;
-  elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
-  elem->filter->start_transport_op(exec_ctx, elem, &op);
-}
-
-void grpc_connected_subchannel_notify_on_state_change(
-    grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
-    grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
-    grpc_closure *closure) {
-  connected_subchannel_state_op(exec_ctx, con, interested_parties, state,
-                                closure);
-}
-
-void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx,
-                                    grpc_connected_subchannel *con,
-                                    grpc_closure *closure) {
-  grpc_transport_op op;
-  grpc_channel_element *elem;
-  memset(&op, 0, sizeof(op));
-  op.send_ping = closure;
-  elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
-  elem->filter->start_transport_op(exec_ctx, elem, &op);
-}
-
-static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
-  size_t channel_stack_size;
-  grpc_connected_subchannel *con;
-  grpc_channel_stack *stk;
-  size_t num_filters;
-  const grpc_channel_filter **filters;
-  state_watcher *sw_subchannel;
-
-  /* build final filter list */
-  num_filters = c->num_filters + c->connecting_result.num_filters + 1;
-  filters = gpr_malloc(sizeof(*filters) * num_filters);
-  if (c->num_filters > 0) {
-    memcpy((void *)filters, c->filters, sizeof(*filters) * c->num_filters);
-  }
-  memcpy((void *)(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(channel_stack_size);
-  stk = CHANNEL_STACK_FROM_CONNECTION(con);
-  grpc_channel_stack_init(exec_ctx, 1, connection_destroy, con, filters,
-                          num_filters, c->connecting_result.channel_args,
-                          "CONNECTED_SUBCHANNEL", stk);
-  grpc_connected_channel_bind_transport(stk, c->connecting_result.transport);
-  gpr_free((void *)c->connecting_result.filters);
-  memset(&c->connecting_result, 0, sizeof(c->connecting_result));
-
-  /* initialize state watcher */
-  sw_subchannel = gpr_malloc(sizeof(*sw_subchannel));
-  sw_subchannel->subchannel = c;
-  sw_subchannel->connectivity_state = GRPC_CHANNEL_READY;
-  grpc_closure_init(&sw_subchannel->closure, subchannel_on_child_state_changed,
-                    sw_subchannel);
-
-  gpr_mu_lock(&c->mu);
-
-  if (c->disconnected) {
-    gpr_mu_unlock(&c->mu);
-    gpr_free(sw_subchannel);
-    gpr_free((void *)filters);
-    grpc_channel_stack_destroy(exec_ctx, stk);
-    gpr_free(con);
-    GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
-    return;
-  }
-
-  /* publish */
-  /* TODO(ctiller): this full barrier seems to clear up a TSAN failure.
-                    I'd have expected the rel_cas below to be enough, but
-                    seemingly it's not.
-                    Re-evaluate if we really need this. */
-  gpr_atm_full_barrier();
-  GPR_ASSERT(gpr_atm_rel_cas(&c->connected_subchannel, 0, (gpr_atm)con));
-  c->connecting = 0;
-
-  /* setup subchannel watching connected subchannel for changes; subchannel ref
-     for connecting is donated
-     to the state watcher */
-  GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
-  GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
-  grpc_connected_subchannel_notify_on_state_change(
-      exec_ctx, con, c->pollset_set, &sw_subchannel->connectivity_state,
-      &sw_subchannel->closure);
-
-  /* signal completion */
-  grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY,
-                              "connected");
-
-  gpr_mu_unlock(&c->mu);
-  gpr_free((void *)filters);
-}
-
-/* Generate a random number between 0 and 1. */
-static double generate_uniform_random_number(grpc_subchannel *c) {
-  c->random = (1103515245 * c->random + 12345) % ((uint32_t)1 << 31);
-  return c->random / (double)((uint32_t)1 << 31);
-}
-
-/* Update backoff_delta and next_attempt in subchannel */
-static void update_reconnect_parameters(grpc_subchannel *c) {
-  size_t i;
-  int32_t backoff_delta_millis, jitter;
-  int32_t max_backoff_millis =
-      GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS * 1000;
-  double jitter_range;
-
-  if (c->args) {
-    for (i = 0; i < c->args->num_args; i++) {
-      if (0 == strcmp(c->args->args[i].key,
-                      "grpc.testing.fixed_reconnect_backoff")) {
-        GPR_ASSERT(c->args->args[i].type == GRPC_ARG_INTEGER);
-        c->next_attempt = gpr_time_add(
-            gpr_now(GPR_CLOCK_MONOTONIC),
-            gpr_time_from_millis(c->args->args[i].value.integer, GPR_TIMESPAN));
-        return;
-      }
-    }
-  }
-
-  backoff_delta_millis =
-      (int32_t)(gpr_time_to_millis(c->backoff_delta) *
-                GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER);
-  if (backoff_delta_millis > max_backoff_millis) {
-    backoff_delta_millis = max_backoff_millis;
-  }
-  c->backoff_delta = gpr_time_from_millis(backoff_delta_millis, GPR_TIMESPAN);
-  c->next_attempt =
-      gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), c->backoff_delta);
-
-  jitter_range = GRPC_SUBCHANNEL_RECONNECT_JITTER * backoff_delta_millis;
-  jitter =
-      (int32_t)((2 * generate_uniform_random_number(c) - 1) * jitter_range);
-  c->next_attempt =
-      gpr_time_add(c->next_attempt, gpr_time_from_millis(jitter, GPR_TIMESPAN));
-}
-
-static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) {
-  grpc_subchannel *c = arg;
-  gpr_mu_lock(&c->mu);
-  c->have_alarm = 0;
-  if (c->disconnected) {
-    iomgr_success = 0;
-  }
-  if (iomgr_success) {
-    update_reconnect_parameters(c);
-    continue_connect(exec_ctx, c);
-    gpr_mu_unlock(&c->mu);
-  } else {
-    gpr_mu_unlock(&c->mu);
-    GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
-  }
-}
-
-static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
-                                 bool iomgr_success) {
-  grpc_subchannel *c = arg;
-
-  if (c->connecting_result.transport != NULL) {
-    publish_transport(exec_ctx, c);
-  } else if (c->disconnected) {
-    GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
-  } else {
-    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
-    gpr_mu_lock(&c->mu);
-    GPR_ASSERT(!c->have_alarm);
-    c->have_alarm = 1;
-    grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
-                                GRPC_CHANNEL_TRANSIENT_FAILURE,
-                                "connect_failed");
-    grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now);
-    gpr_mu_unlock(&c->mu);
-  }
-}
-
-static gpr_timespec compute_connect_deadline(grpc_subchannel *c) {
-  gpr_timespec current_deadline =
-      gpr_time_add(c->next_attempt, c->backoff_delta);
-  gpr_timespec min_deadline = gpr_time_add(
-      gpr_now(GPR_CLOCK_MONOTONIC),
-      gpr_time_from_seconds(GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS,
-                            GPR_TIMESPAN));
-  return gpr_time_cmp(current_deadline, min_deadline) > 0 ? current_deadline
-                                                          : min_deadline;
-}
-
-/*
- * grpc_subchannel_call implementation
- */
-
-static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call,
-                                    bool success) {
-  grpc_subchannel_call *c = call;
-  GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
-  grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c));
-  GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, c->connection, "subchannel_call");
-  gpr_free(c);
-  GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0);
-}
-
-void grpc_subchannel_call_ref(grpc_subchannel_call *c
-                                  GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
-}
-
-void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
-                                grpc_subchannel_call *c
-                                    GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-  GRPC_CALL_STACK_UNREF(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
-}
-
-char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx,
-                                    grpc_subchannel_call *call) {
-  grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call);
-  grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0);
-  return top_elem->filter->get_peer(exec_ctx, top_elem);
-}
-
-void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx,
-                                     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(exec_ctx, top_elem, op);
-}
-
-grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
-    grpc_subchannel *c) {
-  return GET_CONNECTED_SUBCHANNEL(c, acq);
-}
-
-grpc_subchannel_call *grpc_connected_subchannel_create_call(
-    grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
-    grpc_pollset *pollset) {
-  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;
-  GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
-  grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, call,
-                       NULL, NULL, callstk);
-  grpc_call_stack_set_pollset(exec_ctx, callstk, pollset);
-  return call;
-}
-
-grpc_call_stack *grpc_subchannel_call_get_call_stack(
-    grpc_subchannel_call *subchannel_call) {
-  return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call);
-}
diff --git a/src/core/client_config/subchannel.h b/src/core/client_config/subchannel.h
deleted file mode 100644
index 313e63c..0000000
--- a/src/core/client_config/subchannel.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_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"
-#include "src/core/transport/connectivity_state.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_connected_subchannel grpc_connected_subchannel;
-typedef struct grpc_subchannel_call grpc_subchannel_call;
-typedef struct grpc_subchannel_args grpc_subchannel_args;
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-#define GRPC_SUBCHANNEL_REF(p, r) \
-  grpc_subchannel_ref((p), __FILE__, __LINE__, (r))
-#define GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(p, r) \
-  grpc_subchannel_ref_from_weak_ref((p), __FILE__, __LINE__, (r))
-#define GRPC_SUBCHANNEL_UNREF(cl, p, r) \
-  grpc_subchannel_unref((cl), (p), __FILE__, __LINE__, (r))
-#define GRPC_SUBCHANNEL_WEAK_REF(p, r) \
-  grpc_subchannel_weak_ref((p), __FILE__, __LINE__, (r))
-#define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \
-  grpc_subchannel_weak_unref((cl), (p), __FILE__, __LINE__, (r))
-#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) \
-  grpc_connected_subchannel_ref((p), __FILE__, __LINE__, (r))
-#define GRPC_CONNECTED_SUBCHANNEL_UNREF(cl, p, r) \
-  grpc_connected_subchannel_unref((cl), (p), __FILE__, __LINE__, (r))
-#define GRPC_SUBCHANNEL_CALL_REF(p, r) \
-  grpc_subchannel_call_ref((p), __FILE__, __LINE__, (r))
-#define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \
-  grpc_subchannel_call_unref((cl), (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_REF_FROM_WEAK_REF(p, r) \
-  grpc_subchannel_ref_from_weak_ref((p))
-#define GRPC_SUBCHANNEL_UNREF(cl, p, r) grpc_subchannel_unref((cl), (p))
-#define GRPC_SUBCHANNEL_WEAK_REF(p, r) grpc_subchannel_weak_ref((p))
-#define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \
-  grpc_subchannel_weak_unref((cl), (p))
-#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) grpc_connected_subchannel_ref((p))
-#define GRPC_CONNECTED_SUBCHANNEL_UNREF(cl, p, r) \
-  grpc_connected_subchannel_unref((cl), (p))
-#define GRPC_SUBCHANNEL_CALL_REF(p, r) grpc_subchannel_call_ref((p))
-#define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \
-  grpc_subchannel_call_unref((cl), (p))
-#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS
-#endif
-
-grpc_subchannel *grpc_subchannel_ref(grpc_subchannel *channel
-                                         GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-grpc_subchannel *grpc_subchannel_ref_from_weak_ref(
-    grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx,
-                           grpc_subchannel *channel
-                               GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-grpc_subchannel *grpc_subchannel_weak_ref(grpc_subchannel *channel
-                                              GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
-                                grpc_subchannel *channel
-                                    GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-void grpc_connected_subchannel_ref(grpc_connected_subchannel *channel
-                                       GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
-                                     grpc_connected_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_exec_ctx *exec_ctx,
-                                grpc_subchannel_call *call
-                                    GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-
-/** construct a subchannel call */
-grpc_subchannel_call *grpc_connected_subchannel_create_call(
-    grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel,
-    grpc_pollset *pollset);
-
-/** process a transport level op */
-void grpc_connected_subchannel_process_transport_op(
-    grpc_exec_ctx *exec_ctx, grpc_connected_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_exec_ctx *exec_ctx, grpc_subchannel *channel,
-    grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
-    grpc_closure *notify);
-void grpc_connected_subchannel_notify_on_state_change(
-    grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *channel,
-    grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
-    grpc_closure *notify);
-void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx,
-                                    grpc_connected_subchannel *channel,
-                                    grpc_closure *notify);
-
-/** retrieve the grpc_connected_subchannel - or NULL if called before
-    the subchannel becomes connected */
-grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
-    grpc_subchannel *subchannel);
-
-/** continue processing a transport op */
-void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx,
-                                     grpc_subchannel_call *subchannel_call,
-                                     grpc_transport_stream_op *op);
-
-/** continue querying for peer */
-char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx,
-                                    grpc_subchannel_call *subchannel_call);
-
-grpc_call_stack *grpc_subchannel_call_get_call_stack(
-    grpc_subchannel_call *subchannel_call);
-
-struct grpc_subchannel_args {
-  /* When updating this struct, also update subchannel_index.c */
-
-  /** 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;
-};
-
-/** create a subchannel given a connector */
-grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
-                                        grpc_connector *connector,
-                                        grpc_subchannel_args *args);
-
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H */
diff --git a/src/core/client_config/subchannel_factory.c b/src/core/client_config/subchannel_factory.c
deleted file mode 100644
index 2c64219..0000000
--- a/src/core/client_config/subchannel_factory.c
+++ /dev/null
@@ -1,49 +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/client_config/subchannel_factory.h"
-
-void grpc_subchannel_factory_ref(grpc_subchannel_factory* factory) {
-  factory->vtable->ref(factory);
-}
-
-void grpc_subchannel_factory_unref(grpc_exec_ctx* exec_ctx,
-                                   grpc_subchannel_factory* factory) {
-  factory->vtable->unref(exec_ctx, factory);
-}
-
-grpc_subchannel* grpc_subchannel_factory_create_subchannel(
-    grpc_exec_ctx* exec_ctx, grpc_subchannel_factory* factory,
-    grpc_subchannel_args* args) {
-  return factory->vtable->create_subchannel(exec_ctx, factory, args);
-}
diff --git a/src/core/client_config/subchannel_factory.h b/src/core/client_config/subchannel_factory.h
deleted file mode 100644
index c6d8cc9..0000000
--- a/src/core/client_config/subchannel_factory.h
+++ /dev/null
@@ -1,66 +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_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_exec_ctx *exec_ctx, grpc_subchannel_factory *factory);
-  grpc_subchannel *(*create_subchannel)(grpc_exec_ctx *exec_ctx,
-                                        grpc_subchannel_factory *factory,
-                                        grpc_subchannel_args *args);
-};
-
-void grpc_subchannel_factory_ref(grpc_subchannel_factory *factory);
-void grpc_subchannel_factory_unref(grpc_exec_ctx *exec_ctx,
-                                   grpc_subchannel_factory *factory);
-
-/** Create a new grpc_subchannel */
-grpc_subchannel *grpc_subchannel_factory_create_subchannel(
-    grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *factory,
-    grpc_subchannel_args *args);
-
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H */
diff --git a/src/core/client_config/subchannel_index.c b/src/core/client_config/subchannel_index.c
deleted file mode 100644
index 3f94899..0000000
--- a/src/core/client_config/subchannel_index.c
+++ /dev/null
@@ -1,261 +0,0 @@
-//
-//
-// Copyright 2016, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-//
-
-#include "src/core/client_config/subchannel_index.h"
-
-#include <stdbool.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/avl.h>
-#include <grpc/support/tls.h>
-
-#include "src/core/channel/channel_args.h"
-
-// a map of subchannel_key --> subchannel, used for detecting connections
-// to the same destination in order to share them
-static gpr_avl g_subchannel_index;
-
-static gpr_mu g_mu;
-
-struct grpc_subchannel_key {
-  grpc_connector *connector;
-  grpc_subchannel_args args;
-};
-
-GPR_TLS_DECL(subchannel_index_exec_ctx);
-
-static void enter_ctx(grpc_exec_ctx *exec_ctx) {
-  GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == 0);
-  gpr_tls_set(&subchannel_index_exec_ctx, (intptr_t)exec_ctx);
-}
-
-static void leave_ctx(grpc_exec_ctx *exec_ctx) {
-  GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == (intptr_t)exec_ctx);
-  gpr_tls_set(&subchannel_index_exec_ctx, 0);
-}
-
-static grpc_exec_ctx *current_ctx() {
-  grpc_exec_ctx *c = (grpc_exec_ctx *)gpr_tls_get(&subchannel_index_exec_ctx);
-  GPR_ASSERT(c != NULL);
-  return c;
-}
-
-static grpc_subchannel_key *create_key(
-    grpc_connector *connector, grpc_subchannel_args *args,
-    grpc_channel_args *(*copy_channel_args)(const grpc_channel_args *args)) {
-  grpc_subchannel_key *k = gpr_malloc(sizeof(*k));
-  k->connector = grpc_connector_ref(connector);
-  k->args.filter_count = args->filter_count;
-  k->args.filters = gpr_malloc(sizeof(*k->args.filters) * k->args.filter_count);
-  memcpy((grpc_channel_filter *)k->args.filters, args->filters,
-         sizeof(*k->args.filters) * k->args.filter_count);
-  k->args.addr_len = args->addr_len;
-  k->args.addr = gpr_malloc(args->addr_len);
-  memcpy(k->args.addr, args->addr, k->args.addr_len);
-  k->args.args = copy_channel_args(args->args);
-  return k;
-}
-
-grpc_subchannel_key *grpc_subchannel_key_create(grpc_connector *connector,
-                                                grpc_subchannel_args *args) {
-  return create_key(connector, args, grpc_channel_args_normalize);
-}
-
-static grpc_subchannel_key *subchannel_key_copy(grpc_subchannel_key *k) {
-  return create_key(k->connector, &k->args, grpc_channel_args_copy);
-}
-
-static int subchannel_key_compare(grpc_subchannel_key *a,
-                                  grpc_subchannel_key *b) {
-  int c = GPR_ICMP(a->connector, b->connector);
-  if (c != 0) return c;
-  c = GPR_ICMP(a->args.addr_len, b->args.addr_len);
-  if (c != 0) return c;
-  c = GPR_ICMP(a->args.filter_count, b->args.filter_count);
-  if (c != 0) return c;
-  c = memcmp(a->args.addr, b->args.addr, a->args.addr_len);
-  if (c != 0) return c;
-  c = memcmp(a->args.filters, b->args.filters,
-             a->args.filter_count * sizeof(*a->args.filters));
-  return grpc_channel_args_compare(a->args.args, b->args.args);
-}
-
-void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx,
-                                 grpc_subchannel_key *k) {
-  grpc_connector_unref(exec_ctx, k->connector);
-  gpr_free(k->args.addr);
-  gpr_free((grpc_channel_args *)k->args.filters);
-  grpc_channel_args_destroy((grpc_channel_args *)k->args.args);
-  gpr_free(k);
-}
-
-static void sck_avl_destroy(void *p) {
-  grpc_subchannel_key_destroy(current_ctx(), p);
-}
-
-static void *sck_avl_copy(void *p) { return subchannel_key_copy(p); }
-
-static long sck_avl_compare(void *a, void *b) {
-  return subchannel_key_compare(a, b);
-}
-
-static void scv_avl_destroy(void *p) {
-  GRPC_SUBCHANNEL_WEAK_UNREF(current_ctx(), p, "subchannel_index");
-}
-
-static void *scv_avl_copy(void *p) {
-  GRPC_SUBCHANNEL_WEAK_REF(p, "subchannel_index");
-  return p;
-}
-
-static const gpr_avl_vtable subchannel_avl_vtable = {
-    .destroy_key = sck_avl_destroy,
-    .copy_key = sck_avl_copy,
-    .compare_keys = sck_avl_compare,
-    .destroy_value = scv_avl_destroy,
-    .copy_value = scv_avl_copy};
-
-void grpc_subchannel_index_init(void) {
-  g_subchannel_index = gpr_avl_create(&subchannel_avl_vtable);
-  gpr_mu_init(&g_mu);
-  gpr_tls_init(&subchannel_index_exec_ctx);
-}
-
-void grpc_subchannel_index_shutdown(void) {
-  gpr_mu_destroy(&g_mu);
-  gpr_avl_unref(g_subchannel_index);
-  gpr_tls_destroy(&subchannel_index_exec_ctx);
-}
-
-grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx,
-                                            grpc_subchannel_key *key) {
-  enter_ctx(exec_ctx);
-
-  // Lock, and take a reference to the subchannel index.
-  // We don't need to do the search under a lock as avl's are immutable.
-  gpr_mu_lock(&g_mu);
-  gpr_avl index = gpr_avl_ref(g_subchannel_index);
-  gpr_mu_unlock(&g_mu);
-
-  grpc_subchannel *c =
-      GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(gpr_avl_get(index, key), "index_find");
-  gpr_avl_unref(index);
-
-  leave_ctx(exec_ctx);
-  return c;
-}
-
-grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx,
-                                                grpc_subchannel_key *key,
-                                                grpc_subchannel *constructed) {
-  enter_ctx(exec_ctx);
-
-  grpc_subchannel *c = NULL;
-
-  while (c == NULL) {
-    // Compare and swap loop:
-    // - take a reference to the current index
-    gpr_mu_lock(&g_mu);
-    gpr_avl index = gpr_avl_ref(g_subchannel_index);
-    gpr_mu_unlock(&g_mu);
-
-    // - Check to see if a subchannel already exists
-    c = gpr_avl_get(index, key);
-    if (c != NULL) {
-      // yes -> we're done
-      GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, constructed, "index_register");
-    } else {
-      // no -> update the avl and compare/swap
-      gpr_avl updated =
-          gpr_avl_add(gpr_avl_ref(index), subchannel_key_copy(key),
-                      GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"));
-
-      // it may happen (but it's expected to be unlikely)
-      // that some other thread has changed the index:
-      // compare/swap here to check that, and retry as necessary
-      gpr_mu_lock(&g_mu);
-      if (index.root == g_subchannel_index.root) {
-        GPR_SWAP(gpr_avl, updated, g_subchannel_index);
-        c = constructed;
-      }
-      gpr_mu_unlock(&g_mu);
-
-      gpr_avl_unref(updated);
-    }
-    gpr_avl_unref(index);
-  }
-
-  leave_ctx(exec_ctx);
-
-  return c;
-}
-
-void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx,
-                                      grpc_subchannel_key *key,
-                                      grpc_subchannel *constructed) {
-  enter_ctx(exec_ctx);
-
-  bool done = false;
-  while (!done) {
-    // Compare and swap loop:
-    // - take a reference to the current index
-    gpr_mu_lock(&g_mu);
-    gpr_avl index = gpr_avl_ref(g_subchannel_index);
-    gpr_mu_unlock(&g_mu);
-
-    // Check to see if this key still refers to the previously
-    // registered subchannel
-    grpc_subchannel *c = gpr_avl_get(index, key);
-    if (c != constructed) {
-      gpr_avl_unref(index);
-      break;
-    }
-
-    // compare and swap the update (some other thread may have
-    // mutated the index behind us)
-    gpr_avl updated = gpr_avl_remove(gpr_avl_ref(index), key);
-
-    gpr_mu_lock(&g_mu);
-    if (index.root == g_subchannel_index.root) {
-      GPR_SWAP(gpr_avl, updated, g_subchannel_index);
-      done = true;
-    }
-    gpr_mu_unlock(&g_mu);
-
-    gpr_avl_unref(updated);
-    gpr_avl_unref(index);
-  }
-
-  leave_ctx(exec_ctx);
-}
diff --git a/src/core/client_config/subchannel_index.h b/src/core/client_config/subchannel_index.h
deleted file mode 100644
index 095ef17..0000000
--- a/src/core/client_config/subchannel_index.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *
- * Copyright 2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_INDEX_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_INDEX_H
-
-#include "src/core/client_config/connector.h"
-#include "src/core/client_config/subchannel.h"
-
-/** \file Provides an index of active subchannels so that they can be
-    shared amongst channels */
-
-typedef struct grpc_subchannel_key grpc_subchannel_key;
-
-/** Create a key that can be used to uniquely identify a subchannel */
-grpc_subchannel_key *grpc_subchannel_key_create(grpc_connector *con,
-                                                grpc_subchannel_args *args);
-
-/** Destroy a subchannel key */
-void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx,
-                                 grpc_subchannel_key *key);
-
-/** Given a subchannel key, find the subchannel registered for it.
-    Returns NULL if no such channel exists.
-    Thread-safe. */
-grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx,
-                                            grpc_subchannel_key *key);
-
-/** Register a subchannel against a key.
-    Takes ownership of \a constructed.
-    Returns the registered subchannel. This may be different from
-    \a constructed in the case of a registration race. */
-grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx,
-                                                grpc_subchannel_key *key,
-                                                grpc_subchannel *constructed);
-
-/** Remove \a constructed as the registered subchannel for \a key. */
-void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx,
-                                      grpc_subchannel_key *key,
-                                      grpc_subchannel *constructed);
-
-/** Initialize the subchannel index (global) */
-void grpc_subchannel_index_init(void);
-/** Shutdown the subchannel index (global) */
-void grpc_subchannel_index_shutdown(void);
-
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_INDEX_H */
diff --git a/src/core/client_config/uri_parser.c b/src/core/client_config/uri_parser.c
deleted file mode 100644
index cbdfffc..0000000
--- a/src/core/client_config/uri_parser.c
+++ /dev/null
@@ -1,242 +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/client_config/uri_parser.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/string_util.h>
-
-/** a size_t default value... maps to all 1's */
-#define NOT_SET (~(size_t)0)
-
-static grpc_uri *bad_uri(const char *uri_text, size_t pos, const char *section,
-                         int suppress_errors) {
-  char *line_prefix;
-  size_t 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;
-}
-
-/** Returns a copy of \a src[begin, end) */
-static char *copy_component(const char *src, size_t begin, size_t end) {
-  char *out = gpr_malloc(end - begin + 1);
-  memcpy(out, src + begin, end - begin);
-  out[end - begin] = 0;
-  return out;
-}
-
-/** Returns how many chars to advance if \a uri_text[i] begins a valid \a pchar
- * production. If \a uri_text[i] introduces an invalid \a pchar (such as percent
- * sign not followed by two hex digits), NOT_SET is returned. */
-static size_t parse_pchar(const char *uri_text, size_t i) {
-  /* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
-   * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
-   * pct-encoded = "%" HEXDIG HEXDIG
-   * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
-   / "*" / "+" / "," / ";" / "=" */
-  char c = uri_text[i];
-  if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
-      ((c >= '0') && (c <= '9')) ||
-      (c == '-' || c == '.' || c == '_' || c == '~') || /* unreserved */
-      (c == '!' || c == '$' || c == '&' || c == '\'' || c == '$' || c == '&' ||
-       c == '(' || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' ||
-       c == '=') /* sub-delims */) {
-    return 1;
-  }
-  if (c == '%') { /* pct-encoded */
-    size_t j;
-    if (uri_text[i + 1] == 0 || uri_text[i + 2] == 0) {
-      return NOT_SET;
-    }
-    for (j = i + 1; j < 2; j++) {
-      c = uri_text[j];
-      if (!(((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) ||
-            ((c >= 'A') && (c <= 'F')))) {
-        return NOT_SET;
-      }
-    }
-    return 2;
-  }
-  return 0;
-}
-
-/* *( pchar / "?" / "/" ) */
-static int parse_fragment_or_query(const char *uri_text, size_t *i) {
-  char c;
-  while ((c = uri_text[*i]) != 0) {
-    const size_t advance = parse_pchar(uri_text, *i); /* pchar */
-    switch (advance) {
-      case 0: /* uri_text[i] isn't in pchar */
-        /* maybe it's ? or / */
-        if (uri_text[*i] == '?' || uri_text[*i] == '/') {
-          (*i)++;
-          break;
-        } else {
-          return 1;
-        }
-        GPR_UNREACHABLE_CODE(return 0);
-      default:
-        (*i) += advance;
-        break;
-      case NOT_SET: /* uri_text[i] introduces an invalid URI */
-        return 0;
-    }
-  }
-  /* *i is the first uri_text position past the \a query production, maybe \0 */
-  return 1;
-}
-
-grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
-  grpc_uri *uri;
-  size_t scheme_begin = 0;
-  size_t scheme_end = NOT_SET;
-  size_t authority_begin = NOT_SET;
-  size_t authority_end = NOT_SET;
-  size_t path_begin = NOT_SET;
-  size_t path_end = NOT_SET;
-  size_t query_begin = NOT_SET;
-  size_t query_end = NOT_SET;
-  size_t fragment_begin = NOT_SET;
-  size_t fragment_end = NOT_SET;
-  size_t 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 == NOT_SET) {
-    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 == NOT_SET;
-         i++) {
-      if (uri_text[i] == '/' || uri_text[i] == '?' || uri_text[i] == '#') {
-        authority_end = i;
-      }
-    }
-    if (authority_end == NOT_SET && uri_text[i] == 0) {
-      authority_end = i;
-    }
-    if (authority_end == NOT_SET) {
-      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] == '?' || uri_text[i] == '#') {
-      path_end = i;
-      break;
-    }
-  }
-  if (path_end == NOT_SET && uri_text[i] == 0) {
-    path_end = i;
-  }
-  if (path_end == NOT_SET) {
-    return bad_uri(uri_text, i, "path", suppress_errors);
-  }
-
-  if (uri_text[i] == '?') {
-    query_begin = ++i;
-    if (!parse_fragment_or_query(uri_text, &i)) {
-      return bad_uri(uri_text, i, "query", suppress_errors);
-    } else if (uri_text[i] != 0 && uri_text[i] != '#') {
-      /* We must be at the end or at the beginning of a fragment */
-      return bad_uri(uri_text, i, "query", suppress_errors);
-    }
-    query_end = i;
-  }
-  if (uri_text[i] == '#') {
-    fragment_begin = ++i;
-    if (!parse_fragment_or_query(uri_text, &i)) {
-      return bad_uri(uri_text, i - fragment_end, "fragment", suppress_errors);
-    } else if (uri_text[i] != 0) {
-      /* We must be at the end */
-      return bad_uri(uri_text, i, "fragment", suppress_errors);
-    }
-    fragment_end = i;
-  }
-
-  uri = gpr_malloc(sizeof(*uri));
-  memset(uri, 0, sizeof(*uri));
-  uri->scheme = copy_component(uri_text, scheme_begin, scheme_end);
-  uri->authority = copy_component(uri_text, authority_begin, authority_end);
-  uri->path = copy_component(uri_text, path_begin, path_end);
-  uri->query = copy_component(uri_text, query_begin, query_end);
-  uri->fragment = copy_component(uri_text, fragment_begin, fragment_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->query);
-  gpr_free(uri->fragment);
-  gpr_free(uri);
-}
diff --git a/src/core/client_config/uri_parser.h b/src/core/client_config/uri_parser.h
deleted file mode 100644
index b8daa13..0000000
--- a/src/core/client_config/uri_parser.h
+++ /dev/null
@@ -1,51 +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_CLIENT_CONFIG_URI_PARSER_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_URI_PARSER_H
-
-typedef struct {
-  char *scheme;
-  char *authority;
-  char *path;
-  char *query;
-  char *fragment;
-} grpc_uri;
-
-/** parse a uri, return NULL on failure */
-grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors);
-
-/** destroy a uri */
-void grpc_uri_destroy(grpc_uri *uri);
-
-#endif
diff --git a/src/core/compression/algorithm_metadata.h b/src/core/compression/algorithm_metadata.h
deleted file mode 100644
index 882633c..0000000
--- a/src/core/compression/algorithm_metadata.h
+++ /dev/null
@@ -1,53 +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_COMPRESSION_ALGORITHM_METADATA_H
-#define GRPC_INTERNAL_CORE_COMPRESSION_ALGORITHM_METADATA_H
-
-#include <grpc/compression.h>
-#include "src/core/transport/metadata.h"
-
-/** Return compression algorithm based metadata value */
-grpc_mdstr *grpc_compression_algorithm_mdstr(
-    grpc_compression_algorithm algorithm);
-
-/** Return compression algorithm based metadata element (grpc-encoding: xxx) */
-grpc_mdelem *grpc_compression_encoding_mdelem(
-    grpc_compression_algorithm algorithm);
-
-/** Find compression algorithm based on passed in mdstr - returns
- * GRPC_COMPRESS_ALGORITHM_COUNT on failure */
-grpc_compression_algorithm grpc_compression_algorithm_from_mdstr(
-    grpc_mdstr *str);
-
-#endif /* GRPC_INTERNAL_CORE_COMPRESSION_ALGORITHM_METADATA_H */
diff --git a/src/core/compression/compression_algorithm.c b/src/core/compression/compression_algorithm.c
deleted file mode 100644
index 6f3a8eb..0000000
--- a/src/core/compression/compression_algorithm.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <grpc/compression.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/compression/algorithm_metadata.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/transport/static_metadata.h"
-
-int grpc_compression_algorithm_parse(const char *name, size_t name_length,
-                                     grpc_compression_algorithm *algorithm) {
-  /* we use strncmp not only because it's safer (even though in this case it
-   * doesn't matter, given that we are comparing against string literals, but
-   * because this way we needn't have "name" nil-terminated (useful for slice
-   * data, for example) */
-  GRPC_API_TRACE(
-      "grpc_compression_algorithm_parse("
-      "name=%*.*s, name_length=%lu, algorithm=%p)",
-      5, ((int)name_length, (int)name_length, name, (unsigned long)name_length,
-          algorithm));
-  if (name_length == 0) {
-    return 0;
-  }
-  if (strncmp(name, "identity", name_length) == 0) {
-    *algorithm = GRPC_COMPRESS_NONE;
-  } else if (strncmp(name, "gzip", name_length) == 0) {
-    *algorithm = GRPC_COMPRESS_GZIP;
-  } else if (strncmp(name, "deflate", name_length) == 0) {
-    *algorithm = GRPC_COMPRESS_DEFLATE;
-  } else {
-    return 0;
-  }
-  return 1;
-}
-
-int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm,
-                                    char **name) {
-  GRPC_API_TRACE("grpc_compression_algorithm_parse(algorithm=%d, name=%p)", 2,
-                 ((int)algorithm, name));
-  switch (algorithm) {
-    case GRPC_COMPRESS_NONE:
-      *name = "identity";
-      return 1;
-    case GRPC_COMPRESS_DEFLATE:
-      *name = "deflate";
-      return 1;
-    case GRPC_COMPRESS_GZIP:
-      *name = "gzip";
-      return 1;
-    case GRPC_COMPRESS_ALGORITHMS_COUNT:
-      return 0;
-  }
-  return 0;
-}
-
-grpc_compression_algorithm grpc_compression_algorithm_from_mdstr(
-    grpc_mdstr *str) {
-  if (str == GRPC_MDSTR_IDENTITY) return GRPC_COMPRESS_NONE;
-  if (str == GRPC_MDSTR_DEFLATE) return GRPC_COMPRESS_DEFLATE;
-  if (str == GRPC_MDSTR_GZIP) return GRPC_COMPRESS_GZIP;
-  return GRPC_COMPRESS_ALGORITHMS_COUNT;
-}
-
-grpc_mdstr *grpc_compression_algorithm_mdstr(
-    grpc_compression_algorithm algorithm) {
-  switch (algorithm) {
-    case GRPC_COMPRESS_NONE:
-      return GRPC_MDSTR_IDENTITY;
-    case GRPC_COMPRESS_DEFLATE:
-      return GRPC_MDSTR_DEFLATE;
-    case GRPC_COMPRESS_GZIP:
-      return GRPC_MDSTR_GZIP;
-    case GRPC_COMPRESS_ALGORITHMS_COUNT:
-      return NULL;
-  }
-  return NULL;
-}
-
-grpc_mdelem *grpc_compression_encoding_mdelem(
-    grpc_compression_algorithm algorithm) {
-  switch (algorithm) {
-    case GRPC_COMPRESS_NONE:
-      return GRPC_MDELEM_GRPC_ENCODING_IDENTITY;
-    case GRPC_COMPRESS_DEFLATE:
-      return GRPC_MDELEM_GRPC_ENCODING_DEFLATE;
-    case GRPC_COMPRESS_GZIP:
-      return GRPC_MDELEM_GRPC_ENCODING_GZIP;
-    default:
-      break;
-  }
-  return NULL;
-}
-
-/* TODO(dgq): Add the ability to specify parameters to the individual
- * compression algorithms */
-grpc_compression_algorithm grpc_compression_algorithm_for_level(
-    grpc_compression_level level) {
-  GRPC_API_TRACE("grpc_compression_algorithm_for_level(level=%d)", 1,
-                 ((int)level));
-  switch (level) {
-    case GRPC_COMPRESS_LEVEL_NONE:
-      return GRPC_COMPRESS_NONE;
-    case GRPC_COMPRESS_LEVEL_LOW:
-    case GRPC_COMPRESS_LEVEL_MED:
-    case GRPC_COMPRESS_LEVEL_HIGH:
-      return GRPC_COMPRESS_DEFLATE;
-    default:
-      gpr_log(GPR_ERROR, "Unknown compression level %d.", (int)level);
-      abort();
-  }
-}
-
-void grpc_compression_options_init(grpc_compression_options *opts) {
-  opts->enabled_algorithms_bitset = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
-  opts->default_compression_algorithm = GRPC_COMPRESS_NONE;
-}
-
-void grpc_compression_options_enable_algorithm(
-    grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
-  GPR_BITSET(&opts->enabled_algorithms_bitset, algorithm);
-}
-
-void grpc_compression_options_disable_algorithm(
-    grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
-  GPR_BITCLEAR(&opts->enabled_algorithms_bitset, algorithm);
-}
-
-int grpc_compression_options_is_algorithm_enabled(
-    const grpc_compression_options *opts,
-    grpc_compression_algorithm algorithm) {
-  return GPR_BITGET(opts->enabled_algorithms_bitset, algorithm);
-}
diff --git a/src/core/compression/message_compress.c b/src/core/compression/message_compress.c
deleted file mode 100644
index edc21a9..0000000
--- a/src/core/compression/message_compress.c
+++ /dev/null
@@ -1,198 +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/compression/message_compress.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include <zlib.h>
-
-#define OUTPUT_BLOCK_SIZE 1024
-
-static int zlib_body(z_stream* zs, gpr_slice_buffer* input,
-                     gpr_slice_buffer* output,
-                     int (*flate)(z_stream* zs, int flush)) {
-  int r;
-  int flush;
-  size_t i;
-  gpr_slice outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
-  const uInt uint_max = ~(uInt)0;
-
-  GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max);
-  zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf);
-  zs->next_out = GPR_SLICE_START_PTR(outbuf);
-  flush = Z_NO_FLUSH;
-  for (i = 0; i < input->count; i++) {
-    if (i == input->count - 1) flush = Z_FINISH;
-    GPR_ASSERT(GPR_SLICE_LENGTH(input->slices[i]) <= uint_max);
-    zs->avail_in = (uInt)GPR_SLICE_LENGTH(input->slices[i]);
-    zs->next_in = GPR_SLICE_START_PTR(input->slices[i]);
-    do {
-      if (zs->avail_out == 0) {
-        gpr_slice_buffer_add_indexed(output, outbuf);
-        outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
-        GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max);
-        zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf);
-        zs->next_out = GPR_SLICE_START_PTR(outbuf);
-      }
-      r = flate(zs, flush);
-      if (r < 0 && r != Z_BUF_ERROR /* not fatal */) {
-        gpr_log(GPR_INFO, "zlib error (%d)", r);
-        goto error;
-      }
-    } while (zs->avail_out == 0);
-    if (zs->avail_in) {
-      gpr_log(GPR_INFO, "zlib: not all input consumed");
-      goto error;
-    }
-  }
-
-  GPR_ASSERT(outbuf.refcount);
-  outbuf.data.refcounted.length -= zs->avail_out;
-  gpr_slice_buffer_add_indexed(output, outbuf);
-
-  return 1;
-
-error:
-  gpr_slice_unref(outbuf);
-  return 0;
-}
-
-static void* zalloc_gpr(void* opaque, unsigned int items, unsigned int size) {
-  return gpr_malloc(items * size);
-}
-
-static void zfree_gpr(void* opaque, void* address) { gpr_free(address); }
-
-static int zlib_compress(gpr_slice_buffer* input, gpr_slice_buffer* output,
-                         int gzip) {
-  z_stream zs;
-  int r;
-  size_t i;
-  size_t count_before = output->count;
-  size_t length_before = output->length;
-  memset(&zs, 0, sizeof(zs));
-  zs.zalloc = zalloc_gpr;
-  zs.zfree = zfree_gpr;
-  r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0),
-                   8, Z_DEFAULT_STRATEGY);
-  GPR_ASSERT(r == Z_OK);
-  r = zlib_body(&zs, input, output, deflate) && output->length < input->length;
-  if (!r) {
-    for (i = count_before; i < output->count; i++) {
-      gpr_slice_unref(output->slices[i]);
-    }
-    output->count = count_before;
-    output->length = length_before;
-  }
-  deflateEnd(&zs);
-  return r;
-}
-
-static int zlib_decompress(gpr_slice_buffer* input, gpr_slice_buffer* output,
-                           int gzip) {
-  z_stream zs;
-  int r;
-  size_t i;
-  size_t count_before = output->count;
-  size_t length_before = output->length;
-  memset(&zs, 0, sizeof(zs));
-  zs.zalloc = zalloc_gpr;
-  zs.zfree = zfree_gpr;
-  r = inflateInit2(&zs, 15 | (gzip ? 16 : 0));
-  GPR_ASSERT(r == Z_OK);
-  r = zlib_body(&zs, input, output, inflate);
-  if (!r) {
-    for (i = count_before; i < output->count; i++) {
-      gpr_slice_unref(output->slices[i]);
-    }
-    output->count = count_before;
-    output->length = length_before;
-  }
-  inflateEnd(&zs);
-  return r;
-}
-
-static int copy(gpr_slice_buffer* input, gpr_slice_buffer* output) {
-  size_t i;
-  for (i = 0; i < input->count; i++) {
-    gpr_slice_buffer_add(output, gpr_slice_ref(input->slices[i]));
-  }
-  return 1;
-}
-
-static int compress_inner(grpc_compression_algorithm algorithm,
-                          gpr_slice_buffer* input, gpr_slice_buffer* output) {
-  switch (algorithm) {
-    case GRPC_COMPRESS_NONE:
-      /* the fallback path always needs to be send uncompressed: we simply
-         rely on that here */
-      return 0;
-    case GRPC_COMPRESS_DEFLATE:
-      return zlib_compress(input, output, 0);
-    case GRPC_COMPRESS_GZIP:
-      return zlib_compress(input, output, 1);
-    case GRPC_COMPRESS_ALGORITHMS_COUNT:
-      break;
-  }
-  gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
-  return 0;
-}
-
-int grpc_msg_compress(grpc_compression_algorithm algorithm,
-                      gpr_slice_buffer* input, gpr_slice_buffer* output) {
-  if (!compress_inner(algorithm, input, output)) {
-    copy(input, output);
-    return 0;
-  }
-  return 1;
-}
-
-int grpc_msg_decompress(grpc_compression_algorithm algorithm,
-                        gpr_slice_buffer* input, gpr_slice_buffer* output) {
-  switch (algorithm) {
-    case GRPC_COMPRESS_NONE:
-      return copy(input, output);
-    case GRPC_COMPRESS_DEFLATE:
-      return zlib_decompress(input, output, 0);
-    case GRPC_COMPRESS_GZIP:
-      return zlib_decompress(input, output, 1);
-    case GRPC_COMPRESS_ALGORITHMS_COUNT:
-      break;
-  }
-  gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
-  return 0;
-}
diff --git a/src/core/compression/message_compress.h b/src/core/compression/message_compress.h
deleted file mode 100644
index 1465200..0000000
--- a/src/core/compression/message_compress.h
+++ /dev/null
@@ -1,52 +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_COMPRESSION_MESSAGE_COMPRESS_H
-#define GRPC_INTERNAL_CORE_COMPRESSION_MESSAGE_COMPRESS_H
-
-#include <grpc/compression.h>
-#include <grpc/support/slice_buffer.h>
-
-/* compress 'input' to 'output' using 'algorithm'.
-   On success, appends compressed slices to output and returns 1.
-   On failure, appends uncompressed slices to output and returns 0. */
-int grpc_msg_compress(grpc_compression_algorithm algorithm,
-                      gpr_slice_buffer* input, gpr_slice_buffer* output);
-
-/* decompress 'input' to 'output' using 'algorithm'.
-   On success, appends slices to output and returns 1.
-   On failure, output is unchanged, and returns 0. */
-int grpc_msg_decompress(grpc_compression_algorithm algorithm,
-                        gpr_slice_buffer* input, gpr_slice_buffer* output);
-
-#endif /* GRPC_INTERNAL_CORE_COMPRESSION_MESSAGE_COMPRESS_H */
diff --git a/src/core/debug/trace.c b/src/core/debug/trace.c
deleted file mode 100644
index 3b35d81..0000000
--- a/src/core/debug/trace.c
+++ /dev/null
@@ -1,136 +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/debug/trace.h"
-
-#include <string.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include "src/core/support/env.h"
-
-typedef struct tracer {
-  const char *name;
-  int *flag;
-  struct tracer *next;
-} tracer;
-static tracer *tracers;
-
-void grpc_register_tracer(const char *name, int *flag) {
-  tracer *t = gpr_malloc(sizeof(*t));
-  t->name = name;
-  t->flag = flag;
-  t->next = tracers;
-  *flag = 0;
-  tracers = t;
-}
-
-static void add(const char *beg, const char *end, char ***ss, size_t *ns) {
-  size_t n = *ns;
-  size_t np = n + 1;
-  char *s;
-  size_t len;
-  GPR_ASSERT(end >= beg);
-  len = (size_t)(end - beg);
-  s = gpr_malloc(len + 1);
-  memcpy(s, beg, len);
-  s[len] = 0;
-  *ss = gpr_realloc(*ss, sizeof(char **) * np);
-  (*ss)[n] = s;
-  *ns = np;
-}
-
-static void split(const char *s, char ***ss, size_t *ns) {
-  const char *c = strchr(s, ',');
-  if (c == NULL) {
-    add(s, s + strlen(s), ss, ns);
-  } else {
-    add(s, c, ss, ns);
-    split(c + 1, ss, ns);
-  }
-}
-
-static void parse(const char *s) {
-  char **strings = NULL;
-  size_t nstrings = 0;
-  size_t i;
-  split(s, &strings, &nstrings);
-
-  for (i = 0; i < nstrings; i++) {
-    grpc_tracer_set_enabled(strings[i], 1);
-  }
-
-  for (i = 0; i < nstrings; i++) {
-    gpr_free(strings[i]);
-  }
-  gpr_free(strings);
-}
-
-void grpc_tracer_init(const char *env_var) {
-  char *e = gpr_getenv(env_var);
-  if (e != NULL) {
-    parse(e);
-    gpr_free(e);
-  }
-}
-
-void grpc_tracer_shutdown(void) {
-  while (tracers) {
-    tracer *t = tracers;
-    tracers = t->next;
-    gpr_free(t);
-  }
-}
-
-int grpc_tracer_set_enabled(const char *name, int enabled) {
-  tracer *t;
-  if (0 == strcmp(name, "all")) {
-    for (t = tracers; t; t = t->next) {
-      *t->flag = 1;
-    }
-  } else {
-    int found = 0;
-    for (t = tracers; t; t = t->next) {
-      if (0 == strcmp(name, t->name)) {
-        *t->flag = enabled;
-        found = 1;
-      }
-    }
-    if (!found) {
-      gpr_log(GPR_ERROR, "Unknown trace var: '%s'", name);
-      return 0; /* early return */
-    }
-  }
-  return 1;
-}
diff --git a/src/core/debug/trace.h b/src/core/debug/trace.h
deleted file mode 100644
index dc58759..0000000
--- a/src/core/debug/trace.h
+++ /dev/null
@@ -1,43 +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_DEBUG_TRACE_H
-#define GRPC_INTERNAL_CORE_DEBUG_TRACE_H
-
-#include <grpc/support/port_platform.h>
-
-void grpc_register_tracer(const char *name, int *flag);
-void grpc_tracer_init(const char *env_var_name);
-void grpc_tracer_shutdown(void);
-
-#endif /* GRPC_INTERNAL_CORE_DEBUG_TRACE_H */
diff --git a/src/core/ext/transport/chttp2/client/insecure/README.md b/src/core/ext/transport/chttp2/client/insecure/README.md
new file mode 100644
index 0000000..fa11463
--- /dev/null
+++ b/src/core/ext/transport/chttp2/client/insecure/README.md
@@ -0,0 +1 @@
+Plugin for creating insecure channels using chttp2
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create.c b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
new file mode 100644
index 0000000..cf987a0
--- /dev/null
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
@@ -0,0 +1,223 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/census/grpc_filter.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/compress_filter.h"
+#include "src/core/lib/channel/http_client_filter.h"
+#include "src/core/lib/client_config/resolver_registry.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/channel.h"
+
+typedef struct {
+  grpc_connector base;
+  gpr_refcount refs;
+
+  grpc_closure *notify;
+  grpc_connect_in_args args;
+  grpc_connect_out_args *result;
+  grpc_closure initial_string_sent;
+  gpr_slice_buffer initial_string_buffer;
+
+  grpc_endpoint *tcp;
+
+  grpc_closure connected;
+} connector;
+
+static void connector_ref(grpc_connector *con) {
+  connector *c = (connector *)con;
+  gpr_ref(&c->refs);
+}
+
+static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
+  connector *c = (connector *)con;
+  if (gpr_unref(&c->refs)) {
+    /* c->initial_string_buffer does not need to be destroyed */
+    gpr_free(c);
+  }
+}
+
+static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
+                                           bool success) {
+  connector_unref(exec_ctx, arg);
+}
+
+static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  connector *c = arg;
+  grpc_closure *notify;
+  grpc_endpoint *tcp = c->tcp;
+  if (tcp != NULL) {
+    if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
+      grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
+                        c);
+      gpr_slice_buffer_init(&c->initial_string_buffer);
+      gpr_slice_buffer_add(&c->initial_string_buffer,
+                           c->args.initial_connect_string);
+      connector_ref(arg);
+      grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
+                          &c->initial_string_sent);
+    }
+    c->result->transport =
+        grpc_create_chttp2_transport(exec_ctx, c->args.channel_args, tcp, 1);
+    grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
+                                        0);
+    GPR_ASSERT(c->result->transport);
+    c->result->channel_args = c->args.channel_args;
+  } else {
+    memset(c->result, 0, sizeof(*c->result));
+  }
+  notify = c->notify;
+  c->notify = NULL;
+  notify->cb(exec_ctx, notify->cb_arg, 1);
+}
+
+static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {}
+
+static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
+                              const grpc_connect_in_args *args,
+                              grpc_connect_out_args *result,
+                              grpc_closure *notify) {
+  connector *c = (connector *)con;
+  GPR_ASSERT(c->notify == NULL);
+  GPR_ASSERT(notify->cb);
+  c->notify = notify;
+  c->args = *args;
+  c->result = result;
+  c->tcp = NULL;
+  grpc_closure_init(&c->connected, connected, c);
+  grpc_tcp_client_connect(exec_ctx, &c->connected, &c->tcp,
+                          args->interested_parties, args->addr, args->addr_len,
+                          args->deadline);
+}
+
+static const grpc_connector_vtable connector_vtable = {
+    connector_ref, connector_unref, connector_shutdown, connector_connect};
+
+typedef struct {
+  grpc_subchannel_factory base;
+  gpr_refcount refs;
+  grpc_channel_args *merge_args;
+  grpc_channel *master;
+} 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_exec_ctx *exec_ctx,
+                                     grpc_subchannel_factory *scf) {
+  subchannel_factory *f = (subchannel_factory *)scf;
+  if (gpr_unref(&f->refs)) {
+    GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory");
+    grpc_channel_args_destroy(f->merge_args);
+    gpr_free(f);
+  }
+}
+
+static grpc_subchannel *subchannel_factory_create_subchannel(
+    grpc_exec_ctx *exec_ctx, 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->args = final_args;
+  s = grpc_subchannel_create(exec_ctx, &c->base, args);
+  grpc_connector_unref(exec_ctx, &c->base);
+  grpc_channel_args_destroy(final_args);
+  return s;
+}
+
+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
+                   - connect to it (trying alternatives as presented)
+                   - perform handshakes */
+grpc_channel *grpc_insecure_channel_create(const char *target,
+                                           const grpc_channel_args *args,
+                                           void *reserved) {
+  grpc_channel *channel = NULL;
+  grpc_resolver *resolver;
+  subchannel_factory *f;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  GRPC_API_TRACE(
+      "grpc_insecure_channel_create(target=%p, args=%p, reserved=%p)", 3,
+      (target, args, reserved));
+  GPR_ASSERT(!reserved);
+
+  channel =
+      grpc_channel_create(&exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL);
+
+  f = gpr_malloc(sizeof(*f));
+  f->base.vtable = &subchannel_factory_vtable;
+  gpr_ref_init(&f->refs, 1);
+  f->merge_args = grpc_channel_args_copy(args);
+  f->master = channel;
+  GRPC_CHANNEL_INTERNAL_REF(f->master, "subchannel_factory");
+  resolver = grpc_resolver_create(target, &f->base);
+  if (!resolver) {
+    GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, f->master, "subchannel_factory");
+    grpc_subchannel_factory_unref(&exec_ctx, &f->base);
+    grpc_exec_ctx_finish(&exec_ctx);
+    return NULL;
+  }
+
+  grpc_client_channel_set_resolver(
+      &exec_ctx, grpc_channel_get_channel_stack(channel), resolver);
+  GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "create");
+  grpc_subchannel_factory_unref(&exec_ctx, &f->base);
+
+  grpc_exec_ctx_finish(&exec_ctx);
+
+  return channel;
+}
diff --git a/src/core/ext/transport/chttp2/client/secure/README.md b/src/core/ext/transport/chttp2/client/secure/README.md
new file mode 100644
index 0000000..405a86e
--- /dev/null
+++ b/src/core/ext/transport/chttp2/client/secure/README.md
@@ -0,0 +1 @@
+Plugin for creating secure channels using chttp2
diff --git a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
new file mode 100644
index 0000000..203475b
--- /dev/null
+++ b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
@@ -0,0 +1,318 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/client_config/resolver_registry.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/security/auth_filters.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/security/security_context.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/tsi/transport_security_interface.h"
+
+typedef struct {
+  grpc_connector base;
+  gpr_refcount refs;
+
+  grpc_channel_security_connector *security_connector;
+
+  grpc_closure *notify;
+  grpc_connect_in_args args;
+  grpc_connect_out_args *result;
+  grpc_closure initial_string_sent;
+  gpr_slice_buffer initial_string_buffer;
+
+  gpr_mu mu;
+  grpc_endpoint *connecting_endpoint;
+  grpc_endpoint *newly_connecting_endpoint;
+
+  grpc_closure connected_closure;
+} connector;
+
+static void connector_ref(grpc_connector *con) {
+  connector *c = (connector *)con;
+  gpr_ref(&c->refs);
+}
+
+static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
+  connector *c = (connector *)con;
+  if (gpr_unref(&c->refs)) {
+    /* c->initial_string_buffer does not need to be destroyed */
+    gpr_free(c);
+  }
+}
+
+static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
+                                     grpc_security_status status,
+                                     grpc_endpoint *secure_endpoint,
+                                     grpc_auth_context *auth_context) {
+  connector *c = arg;
+  grpc_closure *notify;
+  grpc_channel_args *args_copy = NULL;
+  gpr_mu_lock(&c->mu);
+  if (c->connecting_endpoint == NULL) {
+    memset(c->result, 0, sizeof(*c->result));
+    gpr_mu_unlock(&c->mu);
+  } else if (status != GRPC_SECURITY_OK) {
+    gpr_log(GPR_ERROR, "Secure handshake failed with error %d.", status);
+    memset(c->result, 0, sizeof(*c->result));
+    c->connecting_endpoint = NULL;
+    gpr_mu_unlock(&c->mu);
+  } else {
+    grpc_arg auth_context_arg;
+    c->connecting_endpoint = NULL;
+    gpr_mu_unlock(&c->mu);
+    c->result->transport = grpc_create_chttp2_transport(
+        exec_ctx, c->args.channel_args, secure_endpoint, 1);
+    grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
+                                        0);
+    auth_context_arg = grpc_auth_context_to_arg(auth_context);
+    args_copy = grpc_channel_args_copy_and_add(c->args.channel_args,
+                                               &auth_context_arg, 1);
+    c->result->channel_args = args_copy;
+  }
+  notify = c->notify;
+  c->notify = NULL;
+  /* look at c->args which are connector args. */
+  notify->cb(exec_ctx, notify->cb_arg, 1);
+  if (args_copy != NULL) grpc_channel_args_destroy(args_copy);
+}
+
+static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
+                                           bool success) {
+  connector *c = arg;
+  grpc_channel_security_connector_do_handshake(exec_ctx, c->security_connector,
+                                               c->connecting_endpoint,
+                                               on_secure_handshake_done, c);
+}
+
+static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  connector *c = arg;
+  grpc_closure *notify;
+  grpc_endpoint *tcp = c->newly_connecting_endpoint;
+  if (tcp != NULL) {
+    gpr_mu_lock(&c->mu);
+    GPR_ASSERT(c->connecting_endpoint == NULL);
+    c->connecting_endpoint = tcp;
+    gpr_mu_unlock(&c->mu);
+    if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
+      grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
+                        c);
+      gpr_slice_buffer_init(&c->initial_string_buffer);
+      gpr_slice_buffer_add(&c->initial_string_buffer,
+                           c->args.initial_connect_string);
+      grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
+                          &c->initial_string_sent);
+    } else {
+      grpc_channel_security_connector_do_handshake(
+          exec_ctx, c->security_connector, tcp, on_secure_handshake_done, c);
+    }
+  } else {
+    memset(c->result, 0, sizeof(*c->result));
+    notify = c->notify;
+    c->notify = NULL;
+    notify->cb(exec_ctx, notify->cb_arg, 1);
+  }
+}
+
+static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
+  connector *c = (connector *)con;
+  grpc_endpoint *ep;
+  gpr_mu_lock(&c->mu);
+  ep = c->connecting_endpoint;
+  c->connecting_endpoint = NULL;
+  gpr_mu_unlock(&c->mu);
+  if (ep) {
+    grpc_endpoint_shutdown(exec_ctx, ep);
+  }
+}
+
+static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
+                              const grpc_connect_in_args *args,
+                              grpc_connect_out_args *result,
+                              grpc_closure *notify) {
+  connector *c = (connector *)con;
+  GPR_ASSERT(c->notify == NULL);
+  GPR_ASSERT(notify->cb);
+  c->notify = notify;
+  c->args = *args;
+  c->result = result;
+  gpr_mu_lock(&c->mu);
+  GPR_ASSERT(c->connecting_endpoint == NULL);
+  gpr_mu_unlock(&c->mu);
+  grpc_closure_init(&c->connected_closure, connected, c);
+  grpc_tcp_client_connect(
+      exec_ctx, &c->connected_closure, &c->newly_connecting_endpoint,
+      args->interested_parties, args->addr, args->addr_len, args->deadline);
+}
+
+static const grpc_connector_vtable connector_vtable = {
+    connector_ref, connector_unref, connector_shutdown, connector_connect};
+
+typedef struct {
+  grpc_subchannel_factory base;
+  gpr_refcount refs;
+  grpc_channel_args *merge_args;
+  grpc_channel_security_connector *security_connector;
+  grpc_channel *master;
+} 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_exec_ctx *exec_ctx,
+                                     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_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory");
+    grpc_channel_args_destroy(f->merge_args);
+    gpr_free(f);
+  }
+}
+
+static grpc_subchannel *subchannel_factory_create_subchannel(
+    grpc_exec_ctx *exec_ctx, 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_mu_init(&c->mu);
+  gpr_ref_init(&c->refs, 1);
+  args->args = final_args;
+  s = grpc_subchannel_create(exec_ctx, &c->base, args);
+  grpc_connector_unref(exec_ctx, &c->base);
+  grpc_channel_args_destroy(final_args);
+  return s;
+}
+
+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
+                   - connect to it (trying alternatives as presented)
+                   - perform handshakes */
+grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
+                                         const char *target,
+                                         const grpc_channel_args *args,
+                                         void *reserved) {
+  grpc_channel *channel;
+  grpc_arg connector_arg;
+  grpc_channel_args *args_copy;
+  grpc_channel_args *new_args_from_connector;
+  grpc_channel_security_connector *security_connector;
+  grpc_resolver *resolver;
+  subchannel_factory *f;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  GRPC_API_TRACE(
+      "grpc_secure_channel_create(creds=%p, target=%s, args=%p, "
+      "reserved=%p)",
+      4, (creds, target, args, reserved));
+  GPR_ASSERT(reserved == NULL);
+
+  if (grpc_find_security_connector_in_args(args) != NULL) {
+    gpr_log(GPR_ERROR, "Cannot set security context in channel args.");
+    grpc_exec_ctx_finish(&exec_ctx);
+    return grpc_lame_client_channel_create(
+        target, GRPC_STATUS_INTERNAL,
+        "Security connector exists in channel args.");
+  }
+
+  if (grpc_channel_credentials_create_security_connector(
+          creds, target, args, &security_connector, &new_args_from_connector) !=
+      GRPC_SECURITY_OK) {
+    grpc_exec_ctx_finish(&exec_ctx);
+    return grpc_lame_client_channel_create(
+        target, GRPC_STATUS_INTERNAL, "Failed to create security connector.");
+  }
+
+  connector_arg = grpc_security_connector_to_arg(&security_connector->base);
+  args_copy = grpc_channel_args_copy_and_add(
+      new_args_from_connector != NULL ? new_args_from_connector : args,
+      &connector_arg, 1);
+
+  channel = grpc_channel_create(&exec_ctx, target, args_copy,
+                                GRPC_CLIENT_CHANNEL, NULL);
+
+  f = gpr_malloc(sizeof(*f));
+  f->base.vtable = &subchannel_factory_vtable;
+  gpr_ref_init(&f->refs, 1);
+  GRPC_SECURITY_CONNECTOR_REF(&security_connector->base, "subchannel_factory");
+  f->security_connector = security_connector;
+  f->merge_args = grpc_channel_args_copy(args_copy);
+  f->master = channel;
+  GRPC_CHANNEL_INTERNAL_REF(channel, "subchannel_factory");
+  resolver = grpc_resolver_create(target, &f->base);
+  if (resolver) {
+    grpc_client_channel_set_resolver(
+        &exec_ctx, grpc_channel_get_channel_stack(channel), resolver);
+    GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "create");
+  }
+  grpc_subchannel_factory_unref(&exec_ctx, &f->base);
+  GRPC_SECURITY_CONNECTOR_UNREF(&security_connector->base, "channel_create");
+  grpc_channel_args_destroy(args_copy);
+  if (new_args_from_connector != NULL) {
+    grpc_channel_args_destroy(new_args_from_connector);
+  }
+
+  if (!resolver) {
+    GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, channel, "subchannel_factory");
+    channel = NULL;
+  }
+  grpc_exec_ctx_finish(&exec_ctx);
+
+  return channel;
+}
diff --git a/src/core/ext/transport/chttp2/server/insecure/README.md b/src/core/ext/transport/chttp2/server/insecure/README.md
new file mode 100644
index 0000000..fc0bc14
--- /dev/null
+++ b/src/core/ext/transport/chttp2/server/insecure/README.md
@@ -0,0 +1 @@
+Plugin for creating insecure servers using chttp2
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
new file mode 100644
index 0000000..c1ccfbf
--- /dev/null
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@@ -0,0 +1,146 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/server.h"
+
+static void setup_transport(grpc_exec_ctx *exec_ctx, void *server,
+                            grpc_transport *transport) {
+  grpc_server_setup_transport(exec_ctx, server, transport,
+                              grpc_server_get_channel_args(server));
+}
+
+static void new_transport(grpc_exec_ctx *exec_ctx, void *server,
+                          grpc_endpoint *tcp,
+                          grpc_tcp_server_acceptor *acceptor) {
+  /*
+   * Beware that the call to grpc_create_chttp2_transport() has to happen before
+   * grpc_tcp_server_destroy(). This is fine here, but similar code
+   * asynchronously doing a handshake instead of calling grpc_tcp_server_start()
+   * (as in server_secure_chttp2.c) needs to add synchronization to avoid this
+   * case.
+   */
+  grpc_transport *transport = grpc_create_chttp2_transport(
+      exec_ctx, grpc_server_get_channel_args(server), tcp, 0);
+  setup_transport(exec_ctx, server, transport);
+  grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
+}
+
+/* Server callback: start listening on our ports */
+static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
+                  grpc_pollset **pollsets, size_t pollset_count) {
+  grpc_tcp_server *tcp = tcpp;
+  grpc_tcp_server_start(exec_ctx, tcp, pollsets, pollset_count, new_transport,
+                        server);
+}
+
+/* Server callback: destroy the tcp listener (so we don't generate further
+   callbacks) */
+static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
+                    grpc_closure *destroy_done) {
+  grpc_tcp_server *tcp = tcpp;
+  grpc_tcp_server_unref(exec_ctx, tcp);
+  grpc_exec_ctx_enqueue(exec_ctx, destroy_done, true, NULL);
+}
+
+int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
+  grpc_resolved_addresses *resolved = NULL;
+  grpc_tcp_server *tcp = NULL;
+  size_t i;
+  unsigned count = 0;
+  int port_num = -1;
+  int port_temp;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2,
+                 (server, addr));
+
+  resolved = grpc_blocking_resolve_address(addr, "http");
+  if (!resolved) {
+    goto error;
+  }
+
+  tcp = grpc_tcp_server_create(NULL);
+  GPR_ASSERT(tcp);
+
+  for (i = 0; i < resolved->naddrs; i++) {
+    port_temp = grpc_tcp_server_add_port(
+        tcp, (struct sockaddr *)&resolved->addrs[i].addr,
+        resolved->addrs[i].len);
+    if (port_temp > 0) {
+      if (port_num == -1) {
+        port_num = port_temp;
+      } else {
+        GPR_ASSERT(port_num == port_temp);
+      }
+      count++;
+    }
+  }
+  if (count == 0) {
+    gpr_log(GPR_ERROR, "No address added out of total %d resolved",
+            resolved->naddrs);
+    goto error;
+  }
+  if (count != resolved->naddrs) {
+    gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
+            count, resolved->naddrs);
+  }
+  grpc_resolved_addresses_destroy(resolved);
+
+  /* Register with the server only upon success */
+  grpc_server_add_listener(&exec_ctx, server, tcp, start, destroy);
+  goto done;
+
+/* Error path: cleanup and return */
+error:
+  if (resolved) {
+    grpc_resolved_addresses_destroy(resolved);
+  }
+  if (tcp) {
+    grpc_tcp_server_unref(&exec_ctx, tcp);
+  }
+  port_num = 0;
+
+done:
+  grpc_exec_ctx_finish(&exec_ctx);
+  return port_num;
+}
diff --git a/src/core/ext/transport/chttp2/server/secure/README.md b/src/core/ext/transport/chttp2/server/secure/README.md
new file mode 100644
index 0000000..6bda696
--- /dev/null
+++ b/src/core/ext/transport/chttp2/server/secure/README.md
@@ -0,0 +1 @@
+Plugin for creating secure servers using chttp2
diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
new file mode 100644
index 0000000..80834f4
--- /dev/null
+++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
@@ -0,0 +1,264 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/useful.h>
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/security/auth_filters.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/security/security_connector.h"
+#include "src/core/lib/security/security_context.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/server.h"
+
+typedef struct grpc_server_secure_state {
+  grpc_server *server;
+  grpc_tcp_server *tcp;
+  grpc_server_security_connector *sc;
+  grpc_server_credentials *creds;
+  int is_shutdown;
+  gpr_mu mu;
+  gpr_refcount refcount;
+  grpc_closure destroy_closure;
+  grpc_closure *destroy_callback;
+} grpc_server_secure_state;
+
+static void state_ref(grpc_server_secure_state *state) {
+  gpr_ref(&state->refcount);
+}
+
+static void state_unref(grpc_server_secure_state *state) {
+  if (gpr_unref(&state->refcount)) {
+    /* ensure all threads have unlocked */
+    gpr_mu_lock(&state->mu);
+    gpr_mu_unlock(&state->mu);
+    /* clean up */
+    GRPC_SECURITY_CONNECTOR_UNREF(&state->sc->base, "server");
+    grpc_server_credentials_unref(state->creds);
+    gpr_free(state);
+  }
+}
+
+static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep,
+                            grpc_transport *transport,
+                            grpc_auth_context *auth_context) {
+  grpc_server_secure_state *state = statep;
+  grpc_channel_args *args_copy;
+  grpc_arg args_to_add[2];
+  args_to_add[0] = grpc_server_credentials_to_arg(state->creds);
+  args_to_add[1] = grpc_auth_context_to_arg(auth_context);
+  args_copy = grpc_channel_args_copy_and_add(
+      grpc_server_get_channel_args(state->server), args_to_add,
+      GPR_ARRAY_SIZE(args_to_add));
+  grpc_server_setup_transport(exec_ctx, state->server, transport, args_copy);
+  grpc_channel_args_destroy(args_copy);
+}
+
+static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep,
+                                     grpc_security_status status,
+                                     grpc_endpoint *secure_endpoint,
+                                     grpc_auth_context *auth_context) {
+  grpc_server_secure_state *state = statep;
+  grpc_transport *transport;
+  if (status == GRPC_SECURITY_OK) {
+    if (secure_endpoint) {
+      gpr_mu_lock(&state->mu);
+      if (!state->is_shutdown) {
+        transport = grpc_create_chttp2_transport(
+            exec_ctx, grpc_server_get_channel_args(state->server),
+            secure_endpoint, 0);
+        setup_transport(exec_ctx, state, transport, auth_context);
+        grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
+      } else {
+        /* We need to consume this here, because the server may already have
+         * gone away. */
+        grpc_endpoint_destroy(exec_ctx, secure_endpoint);
+      }
+      gpr_mu_unlock(&state->mu);
+    }
+  } else {
+    gpr_log(GPR_ERROR, "Secure transport failed with error %d", status);
+  }
+  state_unref(state);
+}
+
+static void on_accept(grpc_exec_ctx *exec_ctx, void *statep, grpc_endpoint *tcp,
+                      grpc_tcp_server_acceptor *acceptor) {
+  grpc_server_secure_state *state = statep;
+  state_ref(state);
+  grpc_server_security_connector_do_handshake(
+      exec_ctx, state->sc, acceptor, tcp, on_secure_handshake_done, state);
+}
+
+/* Server callback: start listening on our ports */
+static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
+                  grpc_pollset **pollsets, size_t pollset_count) {
+  grpc_server_secure_state *state = statep;
+  grpc_tcp_server_start(exec_ctx, state->tcp, pollsets, pollset_count,
+                        on_accept, state);
+}
+
+static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, bool success) {
+  grpc_server_secure_state *state = statep;
+  if (state->destroy_callback != NULL) {
+    state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg,
+                                success);
+  }
+  grpc_server_security_connector_shutdown(exec_ctx, state->sc);
+  state_unref(state);
+}
+
+/* Server callback: destroy the tcp listener (so we don't generate further
+   callbacks) */
+static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
+                    grpc_closure *callback) {
+  grpc_server_secure_state *state = statep;
+  grpc_tcp_server *tcp;
+  gpr_mu_lock(&state->mu);
+  state->is_shutdown = 1;
+  state->destroy_callback = callback;
+  tcp = state->tcp;
+  gpr_mu_unlock(&state->mu);
+  grpc_tcp_server_unref(exec_ctx, tcp);
+}
+
+int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
+                                      grpc_server_credentials *creds) {
+  grpc_resolved_addresses *resolved = NULL;
+  grpc_tcp_server *tcp = NULL;
+  grpc_server_secure_state *state = NULL;
+  size_t i;
+  unsigned count = 0;
+  int port_num = -1;
+  int port_temp;
+  grpc_security_status status = GRPC_SECURITY_ERROR;
+  grpc_server_security_connector *sc = NULL;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  GRPC_API_TRACE(
+      "grpc_server_add_secure_http2_port("
+      "server=%p, addr=%s, creds=%p)",
+      3, (server, addr, creds));
+
+  /* create security context */
+  if (creds == NULL) goto error;
+  status = grpc_server_credentials_create_security_connector(creds, &sc);
+  if (status != GRPC_SECURITY_OK) {
+    gpr_log(GPR_ERROR,
+            "Unable to create secure server with credentials of type %s.",
+            creds->type);
+    goto error;
+  }
+  sc->channel_args = grpc_server_get_channel_args(server);
+
+  /* resolve address */
+  resolved = grpc_blocking_resolve_address(addr, "https");
+  if (!resolved) {
+    goto error;
+  }
+  state = gpr_malloc(sizeof(*state));
+  memset(state, 0, sizeof(*state));
+  grpc_closure_init(&state->destroy_closure, destroy_done, state);
+  tcp = grpc_tcp_server_create(&state->destroy_closure);
+  if (!tcp) {
+    goto error;
+  }
+
+  state->server = server;
+  state->tcp = tcp;
+  state->sc = sc;
+  state->creds = grpc_server_credentials_ref(creds);
+  state->is_shutdown = 0;
+  gpr_mu_init(&state->mu);
+  gpr_ref_init(&state->refcount, 1);
+
+  for (i = 0; i < resolved->naddrs; i++) {
+    port_temp = grpc_tcp_server_add_port(
+        tcp, (struct sockaddr *)&resolved->addrs[i].addr,
+        resolved->addrs[i].len);
+    if (port_temp > 0) {
+      if (port_num == -1) {
+        port_num = port_temp;
+      } else {
+        GPR_ASSERT(port_num == port_temp);
+      }
+      count++;
+    }
+  }
+  if (count == 0) {
+    gpr_log(GPR_ERROR, "No address added out of total %d resolved",
+            resolved->naddrs);
+    goto error;
+  }
+  if (count != resolved->naddrs) {
+    gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
+            count, resolved->naddrs);
+    /* if it's an error, don't we want to goto error; here ? */
+  }
+  grpc_resolved_addresses_destroy(resolved);
+
+  /* Register with the server only upon success */
+  grpc_server_add_listener(&exec_ctx, server, state, start, destroy);
+
+  grpc_exec_ctx_finish(&exec_ctx);
+  return port_num;
+
+/* Error path: cleanup and return */
+error:
+  if (resolved) {
+    grpc_resolved_addresses_destroy(resolved);
+  }
+  if (tcp) {
+    grpc_tcp_server_unref(&exec_ctx, tcp);
+  } else {
+    if (sc) {
+      GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "server");
+    }
+    if (state) {
+      gpr_free(state);
+    }
+  }
+  grpc_exec_ctx_finish(&exec_ctx);
+  return 0;
+}
diff --git a/src/core/ext/transport/chttp2/transport/README.md b/src/core/ext/transport/chttp2/transport/README.md
new file mode 100644
index 0000000..4684e58
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/README.md
@@ -0,0 +1,4 @@
+chttp2 transport plugin - implements grpc over http2
+
+Used by chttp2/{client,server}/{insecure,secure} plugins to implement most of
+their functionality
diff --git a/src/core/ext/transport/chttp2/transport/alpn.c b/src/core/ext/transport/chttp2/transport/alpn.c
new file mode 100644
index 0000000..c901905
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/alpn.c
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/alpn.h"
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+/* in order of preference */
+static const char *const supported_versions[] = {"h2"};
+
+int grpc_chttp2_is_alpn_version_supported(const char *version, size_t size) {
+  size_t i;
+  for (i = 0; i < GPR_ARRAY_SIZE(supported_versions); i++) {
+    if (!strncmp(version, supported_versions[i], size)) return 1;
+  }
+  return 0;
+}
+
+size_t grpc_chttp2_num_alpn_versions(void) {
+  return GPR_ARRAY_SIZE(supported_versions);
+}
+
+const char *grpc_chttp2_get_alpn_version_index(size_t i) {
+  GPR_ASSERT(i < GPR_ARRAY_SIZE(supported_versions));
+  return supported_versions[i];
+}
diff --git a/src/core/ext/transport/chttp2/transport/alpn.h b/src/core/ext/transport/chttp2/transport/alpn.h
new file mode 100644
index 0000000..94843a1
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/alpn.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_ALPN_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_ALPN_H
+
+#include <string.h>
+
+/* Retuns 1 if the version is supported, 0 otherwise. */
+int grpc_chttp2_is_alpn_version_supported(const char *version, size_t size);
+
+/* Returns the number of protocol versions to advertise */
+size_t grpc_chttp2_num_alpn_versions(void);
+
+/* Returns the protocol version at index i (0 <= i <
+ * grpc_chttp2_num_alpn_versions()) */
+const char *grpc_chttp2_get_alpn_version_index(size_t i);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_ALPN_H */
diff --git a/src/core/ext/transport/chttp2/transport/bin_encoder.c b/src/core/ext/transport/chttp2/transport/bin_encoder.c
new file mode 100644
index 0000000..d39f99c
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/bin_encoder.c
@@ -0,0 +1,233 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include "src/core/ext/transport/chttp2/transport/huffsyms.h"
+
+static const char alphabet[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+typedef struct {
+  uint16_t bits;
+  uint8_t 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 uint8_t tail_xtra[3] = {0, 2, 3};
+
+gpr_slice grpc_chttp2_base64_encode(gpr_slice input) {
+  size_t input_length = GPR_SLICE_LENGTH(input);
+  size_t input_triplets = input_length / 3;
+  size_t tail_case = input_length % 3;
+  size_t output_length = input_triplets * 4 + tail_xtra[tail_case];
+  gpr_slice output = gpr_slice_malloc(output_length);
+  uint8_t *in = GPR_SLICE_START_PTR(input);
+  char *out = (char *)GPR_SLICE_START_PTR(output);
+  size_t i;
+
+  /* encode full triplets */
+  for (i = 0; i < input_triplets; i++) {
+    out[0] = alphabet[in[0] >> 2];
+    out[1] = alphabet[((in[0] & 0x3) << 4) | (in[1] >> 4)];
+    out[2] = alphabet[((in[1] & 0xf) << 2) | (in[2] >> 6)];
+    out[3] = alphabet[in[2] & 0x3f];
+    out += 4;
+    in += 3;
+  }
+
+  /* encode the remaining bytes */
+  switch (tail_case) {
+    case 0:
+      break;
+    case 1:
+      out[0] = alphabet[in[0] >> 2];
+      out[1] = alphabet[(in[0] & 0x3) << 4];
+      out += 2;
+      in += 1;
+      break;
+    case 2:
+      out[0] = alphabet[in[0] >> 2];
+      out[1] = alphabet[((in[0] & 0x3) << 4) | (in[1] >> 4)];
+      out[2] = alphabet[(in[1] & 0xf) << 2];
+      out += 3;
+      in += 2;
+      break;
+  }
+
+  GPR_ASSERT(out == (char *)GPR_SLICE_END_PTR(output));
+  GPR_ASSERT(in == GPR_SLICE_END_PTR(input));
+  return output;
+}
+
+gpr_slice grpc_chttp2_huffman_compress(gpr_slice input) {
+  size_t nbits;
+  uint8_t *in;
+  uint8_t *out;
+  gpr_slice output;
+  uint32_t temp = 0;
+  uint32_t temp_length = 0;
+
+  nbits = 0;
+  for (in = GPR_SLICE_START_PTR(input); in != GPR_SLICE_END_PTR(input); ++in) {
+    nbits += grpc_chttp2_huffsyms[*in].length;
+  }
+
+  output = gpr_slice_malloc(nbits / 8 + (nbits % 8 != 0));
+  out = GPR_SLICE_START_PTR(output);
+  for (in = GPR_SLICE_START_PTR(input); in != GPR_SLICE_END_PTR(input); ++in) {
+    int sym = *in;
+    temp <<= grpc_chttp2_huffsyms[sym].length;
+    temp |= grpc_chttp2_huffsyms[sym].bits;
+    temp_length += grpc_chttp2_huffsyms[sym].length;
+
+    while (temp_length > 8) {
+      temp_length -= 8;
+      *out++ = (uint8_t)(temp >> temp_length);
+    }
+  }
+
+  if (temp_length) {
+    /* NB: the following integer arithmetic operation needs to be in its
+     * expanded form due to the "integral promotion" performed (see section
+     * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type
+     * is then required to avoid the compiler warning */
+    *out++ = (uint8_t)((uint8_t)(temp << (8u - temp_length)) |
+                       (uint8_t)(0xffu >> temp_length));
+  }
+
+  GPR_ASSERT(out == GPR_SLICE_END_PTR(output));
+
+  return output;
+}
+
+typedef struct {
+  uint32_t temp;
+  uint32_t temp_length;
+  uint8_t *out;
+} huff_out;
+
+static void enc_flush_some(huff_out *out) {
+  while (out->temp_length > 8) {
+    out->temp_length -= 8;
+    *out->out++ = (uint8_t)(out->temp >> out->temp_length);
+  }
+}
+
+static void enc_add2(huff_out *out, uint8_t a, uint8_t b) {
+  b64_huff_sym sa = huff_alphabet[a];
+  b64_huff_sym sb = huff_alphabet[b];
+  out->temp = (out->temp << (sa.length + sb.length)) |
+              ((uint32_t)sa.bits << sb.length) | sb.bits;
+  out->temp_length += (uint32_t)sa.length + (uint32_t)sb.length;
+  enc_flush_some(out);
+}
+
+static void enc_add1(huff_out *out, uint8_t a) {
+  b64_huff_sym sa = huff_alphabet[a];
+  out->temp = (out->temp << sa.length) | sa.bits;
+  out->temp_length += sa.length;
+  enc_flush_some(out);
+}
+
+gpr_slice grpc_chttp2_base64_encode_and_huffman_compress(gpr_slice input) {
+  size_t input_length = GPR_SLICE_LENGTH(input);
+  size_t input_triplets = input_length / 3;
+  size_t tail_case = input_length % 3;
+  size_t output_syms = input_triplets * 4 + tail_xtra[tail_case];
+  size_t max_output_bits = 11 * output_syms;
+  size_t max_output_length = max_output_bits / 8 + (max_output_bits % 8 != 0);
+  gpr_slice output = gpr_slice_malloc(max_output_length);
+  uint8_t *in = GPR_SLICE_START_PTR(input);
+  uint8_t *start_out = GPR_SLICE_START_PTR(output);
+  huff_out out;
+  size_t i;
+
+  out.temp = 0;
+  out.temp_length = 0;
+  out.out = start_out;
+
+  /* encode full triplets */
+  for (i = 0; i < input_triplets; i++) {
+    enc_add2(&out, in[0] >> 2, (uint8_t)((in[0] & 0x3) << 4) | (in[1] >> 4));
+    enc_add2(&out, (uint8_t)((in[1] & 0xf) << 2) | (in[2] >> 6),
+             (uint8_t)(in[2] & 0x3f));
+    in += 3;
+  }
+
+  /* encode the remaining bytes */
+  switch (tail_case) {
+    case 0:
+      break;
+    case 1:
+      enc_add2(&out, in[0] >> 2, (uint8_t)((in[0] & 0x3) << 4));
+      in += 1;
+      break;
+    case 2:
+      enc_add2(&out, in[0] >> 2,
+               (uint8_t)((in[0] & 0x3) << 4) | (uint8_t)(in[1] >> 4));
+      enc_add1(&out, (uint8_t)((in[1] & 0xf) << 2));
+      in += 2;
+      break;
+  }
+
+  if (out.temp_length) {
+    /* NB: the following integer arithmetic operation needs to be in its
+     * expanded form due to the "integral promotion" performed (see section
+     * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type
+     * is then required to avoid the compiler warning */
+    *out.out++ = (uint8_t)((uint8_t)(out.temp << (8u - out.temp_length)) |
+                           (uint8_t)(0xffu >> out.temp_length));
+  }
+
+  GPR_ASSERT(out.out <= GPR_SLICE_END_PTR(output));
+  GPR_SLICE_SET_LENGTH(output, out.out - start_out);
+
+  GPR_ASSERT(in == GPR_SLICE_END_PTR(input));
+  return output;
+}
diff --git a/src/core/ext/transport/chttp2/transport/bin_encoder.h b/src/core/ext/transport/chttp2/transport/bin_encoder.h
new file mode 100644
index 0000000..39dae97
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/bin_encoder.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_ENCODER_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_ENCODER_H
+
+#include <grpc/support/slice.h>
+
+/* base64 encode a slice. Returns a new slice, does not take ownership of the
+   input */
+gpr_slice grpc_chttp2_base64_encode(gpr_slice input);
+
+/* Compress a slice with the static huffman encoder detailed in the hpack
+   standard. Returns a new slice, does not take ownership of the input */
+gpr_slice grpc_chttp2_huffman_compress(gpr_slice input);
+
+/* equivalent to:
+   gpr_slice x = grpc_chttp2_base64_encode(input);
+   gpr_slice y = grpc_chttp2_huffman_compress(x);
+   gpr_slice_unref(x);
+   return y; */
+gpr_slice grpc_chttp2_base64_encode_and_huffman_compress(gpr_slice input);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_ENCODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
new file mode 100644
index 0000000..0a307a7
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -0,0 +1,1785 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <string.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/ext/transport/chttp2/transport/http2_errors.h"
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
+#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/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
+
+int grpc_http_trace = 0;
+int grpc_flowctl_trace = 0;
+
+#define TRANSPORT_FROM_WRITING(tw)                                        \
+  ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
+                                                   writing)))
+
+#define TRANSPORT_FROM_PARSING(tw)                                        \
+  ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
+                                                   parsing)))
+
+#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 STREAM_FROM_PARSING(sg) \
+  ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, parsing)))
+
+static const grpc_transport_vtable vtable;
+
+static void lock(grpc_chttp2_transport *t);
+static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
+
+/* forward declarations of various callbacks that we'll build closures around */
+static void writing_action(grpc_exec_ctx *exec_ctx, void *t,
+                           bool 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,
+                         uint32_t value);
+
+/** Endpoint callback to process incoming data */
+static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success);
+
+/** Start disconnection chain */
+static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
+
+/** Perform a transport_op */
+static void perform_stream_op_locked(
+    grpc_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx,
+                            grpc_chttp2_transport_global *transport_global,
+                            grpc_chttp2_stream_global *stream_global,
+                            grpc_status_code status);
+
+static void close_from_api(grpc_exec_ctx *exec_ctx,
+                           grpc_chttp2_transport_global *transport_global,
+                           grpc_chttp2_stream_global *stream_global,
+                           grpc_status_code status,
+                           gpr_slice *optional_message);
+
+/** Add endpoint from this transport to pollset */
+static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
+                                  grpc_chttp2_transport *t,
+                                  grpc_pollset *pollset);
+static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_transport *t,
+                                      grpc_pollset_set *pollset_set);
+
+/** Start new streams that have been created if we can */
+static void maybe_start_some_streams(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global);
+
+static void connectivity_state_set(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+    grpc_connectivity_state state, const char *reason);
+
+static void check_read_ops(grpc_exec_ctx *exec_ctx,
+                           grpc_chttp2_transport_global *transport_global);
+
+static void incoming_byte_stream_update_flow_control(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
+    size_t have_already);
+
+static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_stream_global *stream_global);
+
+/*******************************************************************************
+ * CONSTRUCTION/DESTRUCTION/REFCOUNTING
+ */
+
+static void destruct_transport(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_transport *t) {
+  size_t i;
+
+  gpr_mu_lock(&t->mu);
+
+  GPR_ASSERT(t->ep == NULL);
+
+  gpr_slice_buffer_destroy(&t->global.qbuf);
+
+  gpr_slice_buffer_destroy(&t->writing.outbuf);
+  grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor);
+
+  gpr_slice_buffer_destroy(&t->parsing.qbuf);
+  gpr_slice_buffer_destroy(&t->read_buffer);
+  grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser);
+  grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser);
+
+  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->parsing_stream_map) == 0);
+  GPR_ASSERT(grpc_chttp2_stream_map_size(&t->new_stream_map) == 0);
+
+  grpc_chttp2_stream_map_destroy(&t->parsing_stream_map);
+  grpc_chttp2_stream_map_destroy(&t->new_stream_map);
+  grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker);
+
+  gpr_mu_unlock(&t->mu);
+  gpr_mu_destroy(&t->mu);
+
+  /* callback remaining pings: they're not allowed to call into the transpot,
+     and maybe they hold resources that need to be freed */
+  while (t->global.pings.next != &t->global.pings) {
+    grpc_chttp2_outstanding_ping *ping = t->global.pings.next;
+    grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, false, NULL);
+    ping->next->prev = ping->prev;
+    ping->prev->next = ping->next;
+    gpr_free(ping);
+  }
+
+  gpr_free(t->peer_string);
+  gpr_free(t);
+}
+
+#ifdef REFCOUNTING_DEBUG
+#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__)
+#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t, r, __FILE__, __LINE__)
+static void unref_transport(grpc_exec_ctx *exec_ctx, 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(exec_ctx, t);
+}
+
+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(cl, t, r) unref_transport(cl, t)
+static void unref_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
+  if (!gpr_unref(&t->refs)) return;
+  destruct_transport(exec_ctx, t);
+}
+
+static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
+#endif
+
+static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                           const grpc_channel_args *channel_args,
+                           grpc_endpoint *ep, uint8_t is_client) {
+  size_t i;
+  int j;
+
+  GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) ==
+             GRPC_CHTTP2_CLIENT_CONNECT_STRLEN);
+
+  memset(t, 0, sizeof(*t));
+
+  t->base.vtable = &vtable;
+  t->ep = ep;
+  /* one ref is for destroy, the other for when ep becomes NULL */
+  gpr_ref_init(&t->refs, 2);
+  /* ref is dropped at transport close() */
+  gpr_ref_init(&t->shutdown_ep_refs, 1);
+  gpr_mu_init(&t->mu);
+  t->peer_string = grpc_endpoint_get_peer(ep);
+  t->endpoint_reading = 1;
+  t->global.next_stream_id = is_client ? 1 : 2;
+  t->global.is_client = is_client;
+  t->writing.outgoing_window = DEFAULT_WINDOW;
+  t->parsing.incoming_window = DEFAULT_WINDOW;
+  t->global.stream_lookahead = 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.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,
+      is_client ? "client_transport" : "server_transport");
+
+  gpr_slice_buffer_init(&t->global.qbuf);
+
+  gpr_slice_buffer_init(&t->writing.outbuf);
+  grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor);
+  grpc_closure_init(&t->writing_action, writing_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);
+
+  grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing,
+                    &t->writing);
+  grpc_closure_init(&t->recv_data, recv_data, t);
+  gpr_slice_buffer_init(&t->read_buffer);
+
+  if (is_client) {
+    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->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 < 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->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->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 (is_client) {
+    push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
+    push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
+  }
+  push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW);
+
+  if (channel_args) {
+    for (i = 0; i < channel_args->num_args; i++) {
+      if (0 ==
+          strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) {
+        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) {
+          gpr_log(GPR_ERROR, "%s: must be an integer",
+                  GRPC_ARG_MAX_CONCURRENT_STREAMS);
+        } else {
+          push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
+                       (uint32_t)channel_args->args[i].value.integer);
+        }
+      } else if (0 == strcmp(channel_args->args[i].key,
+                             GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) {
+        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->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->global.next_stream_id & 1,
+                  is_client ? "client" : "server");
+        } else {
+          t->global.next_stream_id =
+              (uint32_t)channel_args->args[i].value.integer;
+        }
+      } else if (0 == strcmp(channel_args->args[i].key,
+                             GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES)) {
+        if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
+          gpr_log(GPR_ERROR, "%s: must be an integer",
+                  GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
+        } else if (channel_args->args[i].value.integer <= 5) {
+          gpr_log(GPR_ERROR, "%s: must be at least 5",
+                  GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
+        } else {
+          t->global.stream_lookahead =
+              (uint32_t)channel_args->args[i].value.integer;
+        }
+      } else if (0 == strcmp(channel_args->args[i].key,
+                             GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER)) {
+        if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
+          gpr_log(GPR_ERROR, "%s: must be an integer",
+                  GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
+        } else if (channel_args->args[i].value.integer < 0) {
+          gpr_log(GPR_ERROR, "%s: must be non-negative",
+                  GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
+        } else {
+          push_setting(t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
+                       (uint32_t)channel_args->args[i].value.integer);
+        }
+      } else if (0 == strcmp(channel_args->args[i].key,
+                             GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) {
+        if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
+          gpr_log(GPR_ERROR, "%s: must be an integer",
+                  GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
+        } else if (channel_args->args[i].value.integer < 0) {
+          gpr_log(GPR_ERROR, "%s: must be non-negative",
+                  GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
+        } else {
+          grpc_chttp2_hpack_compressor_set_max_usable_size(
+              &t->writing.hpack_compressor,
+              (uint32_t)channel_args->args[i].value.integer);
+        }
+      }
+    }
+  }
+}
+
+static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+
+  lock(t);
+  t->destroying = 1;
+  drop_connection(exec_ctx, t);
+  unlock(exec_ctx, t);
+
+  UNREF_TRANSPORT(exec_ctx, t, "destroy");
+}
+
+/** block grpc_endpoint_shutdown being called until a paired
+    allow_endpoint_shutdown is made */
+static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) {
+  GPR_ASSERT(t->ep);
+  gpr_ref(&t->shutdown_ep_refs);
+}
+
+static void allow_endpoint_shutdown_locked(grpc_exec_ctx *exec_ctx,
+                                           grpc_chttp2_transport *t) {
+  if (gpr_unref(&t->shutdown_ep_refs)) {
+    if (t->ep) {
+      grpc_endpoint_shutdown(exec_ctx, t->ep);
+    }
+  }
+}
+
+static void allow_endpoint_shutdown_unlocked(grpc_exec_ctx *exec_ctx,
+                                             grpc_chttp2_transport *t) {
+  if (gpr_unref(&t->shutdown_ep_refs)) {
+    gpr_mu_lock(&t->mu);
+    if (t->ep) {
+      grpc_endpoint_shutdown(exec_ctx, t->ep);
+    }
+    gpr_mu_unlock(&t->mu);
+  }
+}
+
+static void destroy_endpoint(grpc_exec_ctx *exec_ctx,
+                             grpc_chttp2_transport *t) {
+  grpc_endpoint_destroy(exec_ctx, t->ep);
+  t->ep = NULL;
+  /* safe because we'll still have the ref for write */
+  UNREF_TRANSPORT(exec_ctx, t, "disconnect");
+}
+
+static void close_transport_locked(grpc_exec_ctx *exec_ctx,
+                                   grpc_chttp2_transport *t) {
+  if (!t->closed) {
+    t->closed = 1;
+    connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_FATAL_FAILURE,
+                           "close_transport");
+    if (t->ep) {
+      allow_endpoint_shutdown_locked(exec_ctx, t);
+    }
+
+    /* flush writable stream list to avoid dangling references */
+    grpc_chttp2_stream_global *stream_global;
+    grpc_chttp2_stream_writing *stream_writing;
+    while (grpc_chttp2_list_pop_writable_stream(
+        &t->global, &t->writing, &stream_global, &stream_writing)) {
+      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
+    }
+  }
+}
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global,
+                            const char *reason) {
+  grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount, reason);
+}
+void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
+                              grpc_chttp2_stream_global *stream_global,
+                              const char *reason) {
+  grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount,
+                    reason);
+}
+#else
+void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global) {
+  grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount);
+}
+void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
+                              grpc_chttp2_stream_global *stream_global) {
+  grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount);
+}
+#endif
+
+static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                       grpc_stream *gs, grpc_stream_refcount *refcount,
+                       const void *server_data) {
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+  grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
+
+  memset(s, 0, sizeof(*s));
+
+  s->refcount = refcount;
+  GRPC_CHTTP2_STREAM_REF(&s->global, "chttp2");
+
+  grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[0]);
+  grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[1]);
+  grpc_chttp2_incoming_metadata_buffer_init(
+      &s->global.received_initial_metadata);
+  grpc_chttp2_incoming_metadata_buffer_init(
+      &s->global.received_trailing_metadata);
+  grpc_chttp2_data_parser_init(&s->parsing.data_parser);
+  gpr_slice_buffer_init(&s->writing.flow_controlled_buffer);
+
+  REF_TRANSPORT(t, "stream");
+
+  lock(t);
+  grpc_chttp2_register_stream(t, s);
+  if (server_data) {
+    GPR_ASSERT(t->parsing_active);
+    s->global.id = (uint32_t)(uintptr_t)server_data;
+    s->parsing.id = s->global.id;
+    s->global.outgoing_window =
+        t->global.settings[GRPC_PEER_SETTINGS]
+                          [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+    s->parsing.incoming_window = s->global.max_recv_bytes =
+        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;
+  }
+  unlock(exec_ctx, t);
+
+  return 0;
+}
+
+static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                           grpc_stream *gs) {
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+  grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
+  int i;
+  grpc_byte_stream *bs;
+
+  GPR_TIMER_BEGIN("destroy_stream", 0);
+
+  gpr_mu_lock(&t->mu);
+
+  GPR_ASSERT((s->global.write_closed && s->global.read_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(exec_ctx, t);
+  }
+  if (!t->parsing_active && s->global.id) {
+    GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
+                                           s->global.id) == NULL);
+  }
+
+  grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global,
+                                                                &s->global);
+  grpc_chttp2_list_remove_stalled_by_transport(&t->global, &s->global);
+
+  gpr_mu_unlock(&t->mu);
+
+  for (i = 0; i < STREAM_LIST_COUNT; i++) {
+    if (s->included[i]) {
+      gpr_log(GPR_ERROR, "%s stream %d still included in list %d",
+              t->global.is_client ? "client" : "server", s->global.id, i);
+      abort();
+    }
+  }
+
+  while (
+      (bs = grpc_chttp2_incoming_frame_queue_pop(&s->global.incoming_frames))) {
+    grpc_byte_stream_destroy(exec_ctx, bs);
+  }
+
+  GPR_ASSERT(s->global.send_initial_metadata_finished == NULL);
+  GPR_ASSERT(s->global.send_message_finished == NULL);
+  GPR_ASSERT(s->global.send_trailing_metadata_finished == NULL);
+  GPR_ASSERT(s->global.recv_initial_metadata_ready == NULL);
+  GPR_ASSERT(s->global.recv_message_ready == NULL);
+  GPR_ASSERT(s->global.recv_trailing_metadata_finished == NULL);
+  grpc_chttp2_data_parser_destroy(exec_ctx, &s->parsing.data_parser);
+  grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[0]);
+  grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[1]);
+  grpc_chttp2_incoming_metadata_buffer_destroy(
+      &s->global.received_initial_metadata);
+  grpc_chttp2_incoming_metadata_buffer_destroy(
+      &s->global.received_trailing_metadata);
+  gpr_slice_buffer_destroy(&s->writing.flow_controlled_buffer);
+
+  UNREF_TRANSPORT(exec_ctx, t, "stream");
+
+  GPR_TIMER_END("destroy_stream", 0);
+}
+
+grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
+    grpc_chttp2_transport_parsing *transport_parsing, uint32_t 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;
+}
+
+grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+    uint32_t 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(exec_ctx,
+                                    t->channel_callback.accept_stream_user_data,
+                                    &t->base, (void *)(uintptr_t)id);
+  t->accepting_stream = NULL;
+  return &accepting->parsing;
+}
+
+/*******************************************************************************
+ * LOCK MANAGEMENT
+ */
+
+/* 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(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
+
+static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
+  GPR_TIMER_BEGIN("unlock", 0);
+  if (!t->writing_active && !t->closed &&
+      grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing,
+                                         t->parsing_active)) {
+    t->writing_active = 1;
+    REF_TRANSPORT(t, "writing");
+    grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL);
+    prevent_endpoint_shutdown(t);
+  }
+  check_read_ops(exec_ctx, &t->global);
+
+  gpr_mu_unlock(&t->mu);
+  GPR_TIMER_END("unlock", 0);
+}
+
+/*******************************************************************************
+ * OUTPUT PROCESSING
+ */
+
+void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
+                                 grpc_chttp2_stream_global *stream_global) {
+  if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed &&
+      grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) {
+    GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
+  }
+}
+
+static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
+                         uint32_t value) {
+  const grpc_chttp2_setting_parameters *sp =
+      &grpc_chttp2_settings_parameters[id];
+  uint32_t use_value = GPR_CLAMP(value, sp->min_value, sp->max_value);
+  if (use_value != value) {
+    gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name,
+            value, use_value);
+  }
+  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;
+  }
+}
+
+void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
+                                   void *transport_writing_ptr, bool success) {
+  grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr;
+  grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
+  grpc_chttp2_stream_global *stream_global;
+
+  GPR_TIMER_BEGIN("grpc_chttp2_terminate_writing", 0);
+
+  lock(t);
+
+  allow_endpoint_shutdown_locked(exec_ctx, t);
+
+  if (!success) {
+    drop_connection(exec_ctx, t);
+  }
+
+  grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
+
+  while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
+                                                         &stream_global)) {
+    fail_pending_writes(exec_ctx, stream_global);
+    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
+  }
+
+  /* leave the writing flag up on shutdown to prevent further writes in unlock()
+     from starting */
+  t->writing_active = 0;
+  if (t->ep && !t->endpoint_reading) {
+    destroy_endpoint(exec_ctx, t);
+  }
+
+  unlock(exec_ctx, t);
+
+  UNREF_TRANSPORT(exec_ctx, t, "writing");
+
+  GPR_TIMER_END("grpc_chttp2_terminate_writing", 0);
+}
+
+static void writing_action(grpc_exec_ctx *exec_ctx, void *gt,
+                           bool iomgr_success_ignored) {
+  grpc_chttp2_transport *t = gt;
+  GPR_TIMER_BEGIN("writing_action", 0);
+  grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep);
+  GPR_TIMER_END("writing_action", 0);
+}
+
+void grpc_chttp2_add_incoming_goaway(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+    uint32_t 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(exec_ctx, transport_global, GRPC_CHANNEL_FATAL_FAILURE,
+                         "got_goaway");
+}
+
+static void maybe_start_some_streams(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global) {
+  grpc_chttp2_stream_global *stream_global;
+  uint32_t stream_incoming_window;
+  /* 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)) {
+    /* safe since we can't (legally) be parsing this stream yet */
+    grpc_chttp2_stream_parsing *stream_parsing =
+        &STREAM_FROM_GLOBAL(stream_global)->parsing;
+    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 = stream_parsing->id = transport_global->next_stream_id;
+    transport_global->next_stream_id += 2;
+
+    if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
+      connectivity_state_set(exec_ctx, transport_global,
+                             GRPC_CHANNEL_TRANSIENT_FAILURE,
+                             "no_more_stream_ids");
+    }
+
+    stream_global->outgoing_window =
+        transport_global->settings[GRPC_PEER_SETTINGS]
+                                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+    stream_parsing->incoming_window = stream_incoming_window =
+        transport_global->settings[GRPC_SENT_SETTINGS]
+                                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+    stream_global->max_recv_bytes =
+        GPR_MAX(stream_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_become_writable(transport_global, stream_global);
+  }
+  /* cancel out streams that will never be started */
+  while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
+         grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
+                                                      &stream_global)) {
+    cancel_from_api(exec_ctx, transport_global, stream_global,
+                    GRPC_STATUS_UNAVAILABLE);
+  }
+}
+
+static grpc_closure *add_closure_barrier(grpc_closure *closure) {
+  closure->final_data += 2;
+  return closure;
+}
+
+void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
+                                       grpc_closure **pclosure, int success) {
+  grpc_closure *closure = *pclosure;
+  if (closure == NULL) {
+    return;
+  }
+  closure->final_data -= 2;
+  if (!success) {
+    closure->final_data |= 1;
+  }
+  if (closure->final_data < 2) {
+    grpc_exec_ctx_enqueue(exec_ctx, closure, closure->final_data == 0, NULL);
+  }
+  *pclosure = NULL;
+}
+
+static int contains_non_ok_status(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_metadata_batch *batch) {
+  grpc_linked_mdelem *l;
+  for (l = batch->list.head; l; l = l->next) {
+    if (l->md->key == GRPC_MDSTR_GRPC_STATUS &&
+        l->md != GRPC_MDELEM_GRPC_STATUS_0) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {}
+
+static void perform_stream_op_locked(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
+  grpc_closure *on_complete;
+
+  GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
+
+  on_complete = op->on_complete;
+  if (on_complete == NULL) {
+    on_complete = grpc_closure_create(do_nothing, NULL);
+  }
+  /* use final_data as a barrier until enqueue time; the inital counter is
+     dropped at the end of this function */
+  on_complete->final_data = 2;
+
+  if (op->cancel_with_status != GRPC_STATUS_OK) {
+    cancel_from_api(exec_ctx, transport_global, stream_global,
+                    op->cancel_with_status);
+  }
+
+  if (op->close_with_status != GRPC_STATUS_OK) {
+    close_from_api(exec_ctx, transport_global, stream_global,
+                   op->close_with_status, op->optional_close_message);
+  }
+
+  if (op->send_initial_metadata != NULL) {
+    GPR_ASSERT(stream_global->send_initial_metadata_finished == NULL);
+    stream_global->send_initial_metadata_finished =
+        add_closure_barrier(on_complete);
+    stream_global->send_initial_metadata = op->send_initial_metadata;
+    if (contains_non_ok_status(transport_global, op->send_initial_metadata)) {
+      stream_global->seen_error = 1;
+      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+    }
+    if (!stream_global->write_closed) {
+      if (transport_global->is_client) {
+        GPR_ASSERT(stream_global->id == 0);
+        grpc_chttp2_list_add_waiting_for_concurrency(transport_global,
+                                                     stream_global);
+        maybe_start_some_streams(exec_ctx, transport_global);
+      } else {
+        GPR_ASSERT(stream_global->id != 0);
+        grpc_chttp2_become_writable(transport_global, stream_global);
+      }
+    } else {
+      grpc_chttp2_complete_closure_step(
+          exec_ctx, &stream_global->send_initial_metadata_finished, 0);
+    }
+  }
+
+  if (op->send_message != NULL) {
+    GPR_ASSERT(stream_global->send_message_finished == NULL);
+    GPR_ASSERT(stream_global->send_message == NULL);
+    stream_global->send_message_finished = add_closure_barrier(on_complete);
+    if (stream_global->write_closed) {
+      grpc_chttp2_complete_closure_step(
+          exec_ctx, &stream_global->send_message_finished, 0);
+    } else {
+      stream_global->send_message = op->send_message;
+      if (stream_global->id != 0) {
+        grpc_chttp2_become_writable(transport_global, stream_global);
+      }
+    }
+  }
+
+  if (op->send_trailing_metadata != NULL) {
+    GPR_ASSERT(stream_global->send_trailing_metadata_finished == NULL);
+    stream_global->send_trailing_metadata_finished =
+        add_closure_barrier(on_complete);
+    stream_global->send_trailing_metadata = op->send_trailing_metadata;
+    if (contains_non_ok_status(transport_global, op->send_trailing_metadata)) {
+      stream_global->seen_error = 1;
+      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+    }
+    if (stream_global->write_closed) {
+      grpc_chttp2_complete_closure_step(
+          exec_ctx, &stream_global->send_trailing_metadata_finished,
+          grpc_metadata_batch_is_empty(op->send_trailing_metadata));
+    } else if (stream_global->id != 0) {
+      /* TODO(ctiller): check if there's flow control for any outstanding
+         bytes before going writable */
+      grpc_chttp2_become_writable(transport_global, stream_global);
+    }
+  }
+
+  if (op->recv_initial_metadata != NULL) {
+    GPR_ASSERT(stream_global->recv_initial_metadata_ready == NULL);
+    stream_global->recv_initial_metadata_ready =
+        op->recv_initial_metadata_ready;
+    stream_global->recv_initial_metadata = op->recv_initial_metadata;
+    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+  }
+
+  if (op->recv_message != NULL) {
+    GPR_ASSERT(stream_global->recv_message_ready == NULL);
+    stream_global->recv_message_ready = op->recv_message_ready;
+    stream_global->recv_message = op->recv_message;
+    if (stream_global->id != 0 &&
+        (stream_global->incoming_frames.head == NULL ||
+         stream_global->incoming_frames.head->is_tail)) {
+      incoming_byte_stream_update_flow_control(
+          transport_global, stream_global, transport_global->stream_lookahead,
+          0);
+    }
+    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+  }
+
+  if (op->recv_trailing_metadata != NULL) {
+    GPR_ASSERT(stream_global->recv_trailing_metadata_finished == NULL);
+    stream_global->recv_trailing_metadata_finished =
+        add_closure_barrier(on_complete);
+    stream_global->recv_trailing_metadata = op->recv_trailing_metadata;
+    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+  }
+
+  grpc_chttp2_complete_closure_step(exec_ctx, &on_complete, 1);
+
+  GPR_TIMER_END("perform_stream_op_locked", 0);
+}
+
+static void perform_stream_op(grpc_exec_ctx *exec_ctx, 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(exec_ctx, &t->global, &s->global, op);
+  unlock(exec_ctx, t);
+}
+
+static void send_ping_locked(grpc_chttp2_transport *t, grpc_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] = (uint8_t)((t->global.ping_counter >> 56) & 0xff);
+  p->id[1] = (uint8_t)((t->global.ping_counter >> 48) & 0xff);
+  p->id[2] = (uint8_t)((t->global.ping_counter >> 40) & 0xff);
+  p->id[3] = (uint8_t)((t->global.ping_counter >> 32) & 0xff);
+  p->id[4] = (uint8_t)((t->global.ping_counter >> 24) & 0xff);
+  p->id[5] = (uint8_t)((t->global.ping_counter >> 16) & 0xff);
+  p->id[6] = (uint8_t)((t->global.ping_counter >> 8) & 0xff);
+  p->id[7] = (uint8_t)(t->global.ping_counter & 0xff);
+  p->on_recv = on_recv;
+  gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
+}
+
+void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
+                          grpc_chttp2_transport_parsing *transport_parsing,
+                          const uint8_t *opaque_8bytes) {
+  grpc_chttp2_outstanding_ping *ping;
+  grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
+  grpc_chttp2_transport_global *transport_global = &t->global;
+  lock(t);
+  for (ping = transport_global->pings.next; ping != &transport_global->pings;
+       ping = ping->next) {
+    if (0 == memcmp(opaque_8bytes, ping->id, 8)) {
+      grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, true, NULL);
+      ping->next->prev = ping->prev;
+      ping->prev->next = ping->next;
+      gpr_free(ping);
+      break;
+    }
+  }
+  unlock(exec_ctx, t);
+}
+
+static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
+                                        grpc_chttp2_transport *t,
+                                        grpc_transport_op *op) {
+  bool close_transport = false;
+
+  grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
+
+  if (op->on_connectivity_state_change != NULL) {
+    grpc_connectivity_state_notify_on_state_change(
+        exec_ctx, &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,
+        (uint32_t)grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
+        gpr_slice_ref(*op->goaway_message), &t->global.qbuf);
+    close_transport = !grpc_chttp2_has_streams(t);
+  }
+
+  if (op->set_accept_stream) {
+    t->channel_callback.accept_stream = op->set_accept_stream_fn;
+    t->channel_callback.accept_stream_user_data =
+        op->set_accept_stream_user_data;
+  }
+
+  if (op->bind_pollset) {
+    add_to_pollset_locked(exec_ctx, t, op->bind_pollset);
+  }
+
+  if (op->bind_pollset_set) {
+    add_to_pollset_set_locked(exec_ctx, t, op->bind_pollset_set);
+  }
+
+  if (op->send_ping) {
+    send_ping_locked(t, op->send_ping);
+  }
+
+  if (op->disconnect) {
+    close_transport_locked(exec_ctx, t);
+  }
+
+  if (close_transport) {
+    close_transport_locked(exec_ctx, t);
+  }
+}
+
+static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                                 grpc_transport_op *op) {
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+
+  lock(t);
+
+  /* If there's a set_accept_stream ensure that we're not parsing
+     to avoid changing things out from underneath */
+  if (t->parsing_active && op->set_accept_stream) {
+    GPR_ASSERT(t->post_parsing_op == NULL);
+    t->post_parsing_op = gpr_malloc(sizeof(*op));
+    memcpy(t->post_parsing_op, op, sizeof(*op));
+  } else {
+    perform_transport_op_locked(exec_ctx, t, op);
+  }
+
+  unlock(exec_ctx, t);
+}
+
+/*******************************************************************************
+ * INPUT PROCESSING
+ */
+
+static void check_read_ops(grpc_exec_ctx *exec_ctx,
+                           grpc_chttp2_transport_global *transport_global) {
+  grpc_chttp2_stream_global *stream_global;
+  grpc_byte_stream *bs;
+  while (
+      grpc_chttp2_list_pop_check_read_ops(transport_global, &stream_global)) {
+    if (stream_global->recv_initial_metadata_ready != NULL &&
+        stream_global->published_initial_metadata) {
+      grpc_chttp2_incoming_metadata_buffer_publish(
+          &stream_global->received_initial_metadata,
+          stream_global->recv_initial_metadata);
+      grpc_exec_ctx_enqueue(
+          exec_ctx, stream_global->recv_initial_metadata_ready, true, NULL);
+      stream_global->recv_initial_metadata_ready = NULL;
+    }
+    if (stream_global->recv_message_ready != NULL) {
+      while (stream_global->seen_error &&
+             (bs = grpc_chttp2_incoming_frame_queue_pop(
+                  &stream_global->incoming_frames)) != NULL) {
+        grpc_byte_stream_destroy(exec_ctx, bs);
+      }
+      if (stream_global->incoming_frames.head != NULL) {
+        *stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop(
+            &stream_global->incoming_frames);
+        GPR_ASSERT(*stream_global->recv_message != NULL);
+        grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true,
+                              NULL);
+        stream_global->recv_message_ready = NULL;
+      } else if (stream_global->published_trailing_metadata) {
+        *stream_global->recv_message = NULL;
+        grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true,
+                              NULL);
+        stream_global->recv_message_ready = NULL;
+      }
+    }
+    if (stream_global->recv_trailing_metadata_finished != NULL &&
+        stream_global->read_closed && stream_global->write_closed) {
+      while (stream_global->seen_error &&
+             (bs = grpc_chttp2_incoming_frame_queue_pop(
+                  &stream_global->incoming_frames)) != NULL) {
+        grpc_byte_stream_destroy(exec_ctx, bs);
+      }
+      if (stream_global->incoming_frames.head == NULL) {
+        grpc_chttp2_incoming_metadata_buffer_publish(
+            &stream_global->received_trailing_metadata,
+            stream_global->recv_trailing_metadata);
+        grpc_chttp2_complete_closure_step(
+            exec_ctx, &stream_global->recv_trailing_metadata_finished, 1);
+      }
+    }
+  }
+}
+
+static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                          uint32_t 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);
+  }
+  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(exec_ctx, &t->parsing);
+  }
+  if (s->parsing.data_parser.parsing_frame != NULL) {
+    grpc_chttp2_incoming_byte_stream_finished(
+        exec_ctx, s->parsing.data_parser.parsing_frame, 0, 0);
+    s->parsing.data_parser.parsing_frame = NULL;
+  }
+
+  if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
+    close_transport_locked(exec_ctx, t);
+  }
+  if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) {
+    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing");
+  }
+
+  new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) +
+                     grpc_chttp2_stream_map_size(&t->new_stream_map);
+  GPR_ASSERT(new_stream_count <= UINT32_MAX);
+  if (new_stream_count != t->global.concurrent_stream_count) {
+    t->global.concurrent_stream_count = (uint32_t)new_stream_count;
+    maybe_start_some_streams(exec_ctx, &t->global);
+  }
+}
+
+static void cancel_from_api(grpc_exec_ctx *exec_ctx,
+                            grpc_chttp2_transport_global *transport_global,
+                            grpc_chttp2_stream_global *stream_global,
+                            grpc_status_code status) {
+  if (stream_global->id != 0) {
+    gpr_slice_buffer_add(
+        &transport_global->qbuf,
+        grpc_chttp2_rst_stream_create(
+            stream_global->id,
+            (uint32_t)grpc_chttp2_grpc_status_to_http2_error(status)));
+  }
+  grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status,
+                          NULL);
+  grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
+                                 1);
+}
+
+void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
+                             grpc_chttp2_transport_global *transport_global,
+                             grpc_chttp2_stream_global *stream_global,
+                             grpc_status_code status, gpr_slice *slice) {
+  if (status != GRPC_STATUS_OK) {
+    stream_global->seen_error = 1;
+    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+  }
+  /* stream_global->recv_trailing_metadata_finished gives us a
+     last chance replacement: we've received trailing metadata,
+     but something more important has become available to signal
+     to the upper layers - drop what we've got, and then publish
+     what we want - which is safe because we haven't told anyone
+     about the metadata yet */
+  if (!stream_global->published_trailing_metadata ||
+      stream_global->recv_trailing_metadata_finished != NULL) {
+    char status_string[GPR_LTOA_MIN_BUFSIZE];
+    gpr_ltoa(status, status_string);
+    grpc_chttp2_incoming_metadata_buffer_add(
+        &stream_global->received_trailing_metadata,
+        grpc_mdelem_from_metadata_strings(
+            GRPC_MDSTR_GRPC_STATUS, grpc_mdstr_from_string(status_string)));
+    if (slice) {
+      grpc_chttp2_incoming_metadata_buffer_add(
+          &stream_global->received_trailing_metadata,
+          grpc_mdelem_from_metadata_strings(
+              GRPC_MDSTR_GRPC_MESSAGE,
+              grpc_mdstr_from_slice(gpr_slice_ref(*slice))));
+    }
+    stream_global->published_trailing_metadata = 1;
+    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+  }
+  if (slice) {
+    gpr_slice_unref(*slice);
+  }
+}
+
+static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_stream_global *stream_global) {
+  grpc_chttp2_complete_closure_step(
+      exec_ctx, &stream_global->send_initial_metadata_finished, 0);
+  grpc_chttp2_complete_closure_step(
+      exec_ctx, &stream_global->send_trailing_metadata_finished, 0);
+  grpc_chttp2_complete_closure_step(exec_ctx,
+                                    &stream_global->send_message_finished, 0);
+}
+
+void grpc_chttp2_mark_stream_closed(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global, int close_reads,
+    int close_writes) {
+  if (stream_global->read_closed && stream_global->write_closed) {
+    /* already closed */
+    return;
+  }
+  grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+  if (close_reads && !stream_global->read_closed) {
+    stream_global->read_closed = 1;
+    stream_global->published_initial_metadata = 1;
+    stream_global->published_trailing_metadata = 1;
+  }
+  if (close_writes && !stream_global->write_closed) {
+    stream_global->write_closed = 1;
+    if (TRANSPORT_FROM_GLOBAL(transport_global)->writing_active) {
+      GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes");
+      grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
+                                                      stream_global);
+    } else {
+      fail_pending_writes(exec_ctx, stream_global);
+    }
+  }
+  if (stream_global->read_closed && stream_global->write_closed) {
+    if (stream_global->id != 0 &&
+        TRANSPORT_FROM_GLOBAL(transport_global)->parsing_active) {
+      grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
+                                                      stream_global);
+    } else {
+      if (stream_global->id != 0) {
+        remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global),
+                      stream_global->id);
+      }
+      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
+    }
+  }
+}
+
+static void close_from_api(grpc_exec_ctx *exec_ctx,
+                           grpc_chttp2_transport_global *transport_global,
+                           grpc_chttp2_stream_global *stream_global,
+                           grpc_status_code status,
+                           gpr_slice *optional_message) {
+  gpr_slice hdr;
+  gpr_slice status_hdr;
+  gpr_slice message_pfx;
+  uint8_t *p;
+  uint32_t len = 0;
+
+  GPR_ASSERT(status >= 0 && (int)status < 100);
+
+  GPR_ASSERT(stream_global->id != 0);
+
+  /* Hand roll a header block.
+     This is unnecessarily ugly - at some point we should find a more elegant
+     solution.
+     It's complicated by the fact that our send machinery would be dead by the
+     time we got around to sending this, so instead we ignore HPACK compression
+     and just write the uncompressed bytes onto the wire. */
+  status_hdr = gpr_slice_malloc(15 + (status >= 10));
+  p = GPR_SLICE_START_PTR(status_hdr);
+  *p++ = 0x40; /* literal header */
+  *p++ = 11;   /* len(grpc-status) */
+  *p++ = 'g';
+  *p++ = 'r';
+  *p++ = 'p';
+  *p++ = 'c';
+  *p++ = '-';
+  *p++ = 's';
+  *p++ = 't';
+  *p++ = 'a';
+  *p++ = 't';
+  *p++ = 'u';
+  *p++ = 's';
+  if (status < 10) {
+    *p++ = 1;
+    *p++ = (uint8_t)('0' + status);
+  } else {
+    *p++ = 2;
+    *p++ = (uint8_t)('0' + (status / 10));
+    *p++ = (uint8_t)('0' + (status % 10));
+  }
+  GPR_ASSERT(p == GPR_SLICE_END_PTR(status_hdr));
+  len += (uint32_t)GPR_SLICE_LENGTH(status_hdr);
+
+  if (optional_message) {
+    GPR_ASSERT(GPR_SLICE_LENGTH(*optional_message) < 127);
+    message_pfx = gpr_slice_malloc(15);
+    p = GPR_SLICE_START_PTR(message_pfx);
+    *p++ = 0x40;
+    *p++ = 12; /* len(grpc-message) */
+    *p++ = 'g';
+    *p++ = 'r';
+    *p++ = 'p';
+    *p++ = 'c';
+    *p++ = '-';
+    *p++ = 'm';
+    *p++ = 'e';
+    *p++ = 's';
+    *p++ = 's';
+    *p++ = 'a';
+    *p++ = 'g';
+    *p++ = 'e';
+    *p++ = (uint8_t)GPR_SLICE_LENGTH(*optional_message);
+    GPR_ASSERT(p == GPR_SLICE_END_PTR(message_pfx));
+    len += (uint32_t)GPR_SLICE_LENGTH(message_pfx);
+    len += (uint32_t)GPR_SLICE_LENGTH(*optional_message);
+  }
+
+  hdr = gpr_slice_malloc(9);
+  p = GPR_SLICE_START_PTR(hdr);
+  *p++ = (uint8_t)(len >> 16);
+  *p++ = (uint8_t)(len >> 8);
+  *p++ = (uint8_t)(len);
+  *p++ = GRPC_CHTTP2_FRAME_HEADER;
+  *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS;
+  *p++ = (uint8_t)(stream_global->id >> 24);
+  *p++ = (uint8_t)(stream_global->id >> 16);
+  *p++ = (uint8_t)(stream_global->id >> 8);
+  *p++ = (uint8_t)(stream_global->id);
+  GPR_ASSERT(p == GPR_SLICE_END_PTR(hdr));
+
+  gpr_slice_buffer_add(&transport_global->qbuf, hdr);
+  gpr_slice_buffer_add(&transport_global->qbuf, status_hdr);
+  if (optional_message) {
+    gpr_slice_buffer_add(&transport_global->qbuf, message_pfx);
+    gpr_slice_buffer_add(&transport_global->qbuf,
+                         gpr_slice_ref(*optional_message));
+  }
+
+  gpr_slice_buffer_add(
+      &transport_global->qbuf,
+      grpc_chttp2_rst_stream_create(stream_global->id, GRPC_CHTTP2_NO_ERROR));
+
+  if (optional_message) {
+    gpr_slice_ref(*optional_message);
+  }
+  grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status,
+                          optional_message);
+  grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
+                                 1);
+}
+
+static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global,
+                             void *user_data,
+                             grpc_chttp2_stream_global *stream_global) {
+  cancel_from_api(user_data, transport_global, stream_global,
+                  GRPC_STATUS_UNAVAILABLE);
+}
+
+static void end_all_the_calls(grpc_exec_ctx *exec_ctx,
+                              grpc_chttp2_transport *t) {
+  grpc_chttp2_for_all_streams(&t->global, exec_ctx, cancel_stream_cb);
+}
+
+static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
+  close_transport_locked(exec_ctx, t);
+  end_all_the_calls(exec_ctx, t);
+}
+
+/** update window from a settings change */
+static void update_global_window(void *args, uint32_t 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;
+  int64_t initial_window_update = t->parsing.initial_window_update;
+
+  was_zero = stream_global->outgoing_window <= 0;
+  GRPC_CHTTP2_FLOW_CREDIT_STREAM("settings", transport_global, stream_global,
+                                 outgoing_window, initial_window_update);
+  is_zero = stream_global->outgoing_window <= 0;
+
+  if (was_zero && !is_zero) {
+    grpc_chttp2_become_writable(transport_global, stream_global);
+  }
+}
+
+static void read_error_locked(grpc_exec_ctx *exec_ctx,
+                              grpc_chttp2_transport *t) {
+  t->endpoint_reading = 0;
+  if (!t->writing_active && t->ep) {
+    destroy_endpoint(exec_ctx, t);
+  }
+}
+
+/* tcp read callback */
+static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
+  size_t i;
+  int keep_reading = 0;
+  grpc_chttp2_transport *t = tp;
+  grpc_chttp2_transport_global *transport_global = &t->global;
+  grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
+  grpc_chttp2_stream_global *stream_global;
+
+  GPR_TIMER_BEGIN("recv_data", 0);
+
+  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(transport_global, transport_parsing);
+    gpr_mu_unlock(&t->mu);
+    GPR_TIMER_BEGIN("recv_data.parse", 0);
+    for (; i < t->read_buffer.count &&
+           grpc_chttp2_perform_read(exec_ctx, transport_parsing,
+                                    t->read_buffer.slices[i]);
+         i++)
+      ;
+    GPR_TIMER_END("recv_data.parse", 0);
+    gpr_mu_lock(&t->mu);
+    /* copy parsing qbuf to global qbuf */
+    gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
+    if (i != t->read_buffer.count) {
+      unlock(exec_ctx, t);
+      lock(t);
+      drop_connection(exec_ctx, t);
+    }
+    /* merge stream lists */
+    grpc_chttp2_stream_map_move_into(&t->new_stream_map,
+                                     &t->parsing_stream_map);
+    transport_global->concurrent_stream_count =
+        (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map);
+    if (transport_parsing->initial_window_update != 0) {
+      grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
+                                      update_global_window, t);
+      transport_parsing->initial_window_update = 0;
+    }
+    /* handle higher level things */
+    grpc_chttp2_publish_reads(exec_ctx, transport_global, transport_parsing);
+    t->parsing_active = 0;
+    /* handle delayed transport ops (if there is one) */
+    if (t->post_parsing_op) {
+      grpc_transport_op *op = t->post_parsing_op;
+      t->post_parsing_op = NULL;
+      perform_transport_op_locked(exec_ctx, t, op);
+      gpr_free(op);
+    }
+    /* 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_closed);
+      GPR_ASSERT(stream_global->read_closed);
+      remove_stream(exec_ctx, t, stream_global->id);
+      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
+    }
+  }
+  if (!success || i != t->read_buffer.count || t->closed) {
+    drop_connection(exec_ctx, t);
+    read_error_locked(exec_ctx, t);
+  } else if (!t->closed) {
+    keep_reading = 1;
+    REF_TRANSPORT(t, "keep_reading");
+    prevent_endpoint_shutdown(t);
+  }
+  gpr_slice_buffer_reset_and_unref(&t->read_buffer);
+  unlock(exec_ctx, t);
+
+  if (keep_reading) {
+    grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->recv_data);
+    allow_endpoint_shutdown_unlocked(exec_ctx, t);
+    UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
+  } else {
+    UNREF_TRANSPORT(exec_ctx, t, "recv_data");
+  }
+
+  GPR_TIMER_END("recv_data", 0);
+}
+
+/*******************************************************************************
+ * CALLBACK LOOP
+ */
+
+static void connectivity_state_set(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+    grpc_connectivity_state state, const char *reason) {
+  GRPC_CHTTP2_IF_TRACING(
+      gpr_log(GPR_DEBUG, "set connectivity_state=%d", state));
+  grpc_connectivity_state_set(
+      exec_ctx,
+      &TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker,
+      state, reason);
+}
+
+/*******************************************************************************
+ * POLLSET STUFF
+ */
+
+static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
+                                  grpc_chttp2_transport *t,
+                                  grpc_pollset *pollset) {
+  if (t->ep) {
+    grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset);
+  }
+}
+
+static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_transport *t,
+                                      grpc_pollset_set *pollset_set) {
+  if (t->ep) {
+    grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set);
+  }
+}
+
+static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                        grpc_stream *gs, grpc_pollset *pollset) {
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+  lock(t);
+  add_to_pollset_locked(exec_ctx, t, pollset);
+  unlock(exec_ctx, t);
+}
+
+/*******************************************************************************
+ * BYTE STREAM
+ */
+
+static void incoming_byte_stream_update_flow_control(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
+    size_t have_already) {
+  uint32_t max_recv_bytes;
+
+  /* clamp max recv hint to an allowable size */
+  if (max_size_hint >= UINT32_MAX - transport_global->stream_lookahead) {
+    max_recv_bytes = UINT32_MAX - transport_global->stream_lookahead;
+  } else {
+    max_recv_bytes = (uint32_t)max_size_hint;
+  }
+
+  /* account for bytes already received but unknown to higher layers */
+  if (max_recv_bytes >= have_already) {
+    max_recv_bytes -= (uint32_t)have_already;
+  } else {
+    max_recv_bytes = 0;
+  }
+
+  /* add some small lookahead to keep pipelines flowing */
+  GPR_ASSERT(max_recv_bytes <= UINT32_MAX - transport_global->stream_lookahead);
+  max_recv_bytes += transport_global->stream_lookahead;
+  if (stream_global->max_recv_bytes < max_recv_bytes) {
+    uint32_t add_max_recv_bytes =
+        max_recv_bytes - stream_global->max_recv_bytes;
+    GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global,
+                                   max_recv_bytes, add_max_recv_bytes);
+    GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global,
+                                   unannounced_incoming_window_for_parse,
+                                   add_max_recv_bytes);
+    GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global,
+                                   unannounced_incoming_window_for_writing,
+                                   add_max_recv_bytes);
+    grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global,
+                                                               stream_global);
+    grpc_chttp2_become_writable(transport_global, stream_global);
+  }
+}
+
+static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
+                                     grpc_byte_stream *byte_stream,
+                                     gpr_slice *slice, size_t max_size_hint,
+                                     grpc_closure *on_complete) {
+  grpc_chttp2_incoming_byte_stream *bs =
+      (grpc_chttp2_incoming_byte_stream *)byte_stream;
+  grpc_chttp2_transport_global *transport_global = &bs->transport->global;
+  grpc_chttp2_stream_global *stream_global = &bs->stream->global;
+
+  lock(bs->transport);
+  if (bs->is_tail) {
+    incoming_byte_stream_update_flow_control(transport_global, stream_global,
+                                             max_size_hint, bs->slices.length);
+  }
+  if (bs->slices.count > 0) {
+    *slice = gpr_slice_buffer_take_first(&bs->slices);
+    unlock(exec_ctx, bs->transport);
+    return 1;
+  } else if (bs->failed) {
+    grpc_exec_ctx_enqueue(exec_ctx, on_complete, false, NULL);
+    unlock(exec_ctx, bs->transport);
+    return 0;
+  } else {
+    bs->on_next = on_complete;
+    bs->next = slice;
+    unlock(exec_ctx, bs->transport);
+    return 0;
+  }
+}
+
+static void incoming_byte_stream_unref(grpc_chttp2_incoming_byte_stream *bs) {
+  if (gpr_unref(&bs->refs)) {
+    gpr_slice_buffer_destroy(&bs->slices);
+    gpr_free(bs);
+  }
+}
+
+static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
+                                         grpc_byte_stream *byte_stream) {
+  incoming_byte_stream_unref((grpc_chttp2_incoming_byte_stream *)byte_stream);
+}
+
+void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
+                                           grpc_chttp2_incoming_byte_stream *bs,
+                                           gpr_slice slice) {
+  gpr_mu_lock(&bs->transport->mu);
+  if (bs->on_next != NULL) {
+    *bs->next = slice;
+    grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, true, NULL);
+    bs->on_next = NULL;
+  } else {
+    gpr_slice_buffer_add(&bs->slices, slice);
+  }
+  gpr_mu_unlock(&bs->transport->mu);
+}
+
+void grpc_chttp2_incoming_byte_stream_finished(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
+    int from_parsing_thread) {
+  if (!success) {
+    if (from_parsing_thread) {
+      gpr_mu_lock(&bs->transport->mu);
+    }
+    grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL);
+    bs->on_next = NULL;
+    bs->failed = 1;
+    if (from_parsing_thread) {
+      gpr_mu_unlock(&bs->transport->mu);
+    }
+  } else {
+#ifndef NDEBUG
+    if (from_parsing_thread) {
+      gpr_mu_lock(&bs->transport->mu);
+    }
+    GPR_ASSERT(bs->on_next == NULL);
+    if (from_parsing_thread) {
+      gpr_mu_unlock(&bs->transport->mu);
+    }
+#endif
+  }
+  incoming_byte_stream_unref(bs);
+}
+
+grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size,
+    uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue) {
+  grpc_chttp2_incoming_byte_stream *incoming_byte_stream =
+      gpr_malloc(sizeof(*incoming_byte_stream));
+  incoming_byte_stream->base.length = frame_size;
+  incoming_byte_stream->base.flags = flags;
+  incoming_byte_stream->base.next = incoming_byte_stream_next;
+  incoming_byte_stream->base.destroy = incoming_byte_stream_destroy;
+  gpr_ref_init(&incoming_byte_stream->refs, 2);
+  incoming_byte_stream->next_message = NULL;
+  incoming_byte_stream->transport = TRANSPORT_FROM_PARSING(transport_parsing);
+  incoming_byte_stream->stream = STREAM_FROM_PARSING(stream_parsing);
+  gpr_slice_buffer_init(&incoming_byte_stream->slices);
+  incoming_byte_stream->on_next = NULL;
+  incoming_byte_stream->is_tail = 1;
+  incoming_byte_stream->failed = 0;
+  if (add_to_queue->head == NULL) {
+    add_to_queue->head = incoming_byte_stream;
+  } else {
+    add_to_queue->tail->is_tail = 0;
+    add_to_queue->tail->next_message = incoming_byte_stream;
+  }
+  add_to_queue->tail = incoming_byte_stream;
+  return incoming_byte_stream;
+}
+
+/*******************************************************************************
+ * TRACING
+ */
+
+static char *format_flowctl_context_var(const char *context, const char *var,
+                                        int64_t val, uint32_t id,
+                                        char **scope) {
+  char *underscore_pos;
+  char *result;
+  if (context == NULL) {
+    *scope = NULL;
+    gpr_asprintf(&result, "%s(%lld)", var, val);
+    return result;
+  }
+  underscore_pos = strchr(context, '_');
+  *scope = gpr_strdup(context);
+  (*scope)[underscore_pos - context] = 0;
+  if (id != 0) {
+    char *tmp = *scope;
+    gpr_asprintf(scope, "%s[%d]", tmp, id);
+    gpr_free(tmp);
+  }
+  gpr_asprintf(&result, "%s.%s(%lld)", underscore_pos + 1, var, val);
+  return result;
+}
+
+static int samestr(char *a, char *b) {
+  if (a == NULL) {
+    return b == NULL;
+  }
+  if (b == NULL) {
+    return 0;
+  }
+  return 0 == strcmp(a, b);
+}
+
+void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
+                               grpc_chttp2_flowctl_op op, const char *context1,
+                               const char *var1, const char *context2,
+                               const char *var2, int is_client,
+                               uint32_t stream_id, int64_t val1, int64_t val2) {
+  char *scope1;
+  char *scope2;
+  char *label1 =
+      format_flowctl_context_var(context1, var1, val1, stream_id, &scope1);
+  char *label2 =
+      format_flowctl_context_var(context2, var2, val2, stream_id, &scope2);
+  char *clisvr = is_client ? "client" : "server";
+  char *prefix;
+
+  gpr_asprintf(&prefix, "FLOW % 8s: %s % 11s ", phase, clisvr, scope1);
+
+  switch (op) {
+    case GRPC_CHTTP2_FLOWCTL_MOVE:
+      GPR_ASSERT(samestr(scope1, scope2));
+      if (val2 != 0) {
+        gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+                "%sMOVE   % 40s <- % 40s giving %d", prefix, label1, label2,
+                val1 + val2);
+      }
+      break;
+    case GRPC_CHTTP2_FLOWCTL_CREDIT:
+      GPR_ASSERT(val2 >= 0);
+      if (val2 != 0) {
+        gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+                "%sCREDIT % 40s by % 40s giving %d", prefix, label1, label2,
+                val1 + val2);
+      }
+      break;
+    case GRPC_CHTTP2_FLOWCTL_DEBIT:
+      GPR_ASSERT(val2 >= 0);
+      if (val2 != 0) {
+        gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+                "%sDEBIT  % 40s by % 40s giving %d", prefix, label1, label2,
+                val1 - val2);
+      }
+      break;
+  }
+
+  gpr_free(scope1);
+  gpr_free(scope2);
+  gpr_free(label1);
+  gpr_free(label2);
+  gpr_free(prefix);
+}
+
+/*******************************************************************************
+ * INTEGRATION GLUE
+ */
+
+static char *chttp2_get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *t) {
+  return gpr_strdup(((grpc_chttp2_transport *)t)->peer_string);
+}
+
+static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream),
+                                             "chttp2",
+                                             init_stream,
+                                             set_pollset,
+                                             perform_stream_op,
+                                             perform_transport_op,
+                                             destroy_stream,
+                                             destroy_transport,
+                                             chttp2_get_peer};
+
+grpc_transport *grpc_create_chttp2_transport(
+    grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args,
+    grpc_endpoint *ep, int is_client) {
+  grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport));
+  init_transport(exec_ctx, t, channel_args, ep, is_client != 0);
+  return &t->base;
+}
+
+void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
+                                         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 */
+  gpr_slice_buffer_addn(&t->read_buffer, slices, nslices);
+  recv_data(exec_ctx, t, 1);
+}
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.h b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
new file mode 100644
index 0000000..8ebf9fc
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_TRANSPORT_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_TRANSPORT_H
+
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/transport/transport.h"
+
+extern int grpc_http_trace;
+extern int grpc_flowctl_trace;
+
+grpc_transport *grpc_create_chttp2_transport(
+    grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args,
+    grpc_endpoint *ep, int is_client);
+
+void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
+                                         grpc_transport *transport,
+                                         gpr_slice *slices, size_t nslices);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_TRANSPORT_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame.h b/src/core/ext/transport/chttp2/transport/frame.h
new file mode 100644
index 0000000..e1311a1
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_H
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+
+/* Common definitions for frame handling in the chttp2 transport */
+
+typedef enum {
+  GRPC_CHTTP2_PARSE_OK,
+  GRPC_CHTTP2_STREAM_ERROR,
+  GRPC_CHTTP2_CONNECTION_ERROR
+} grpc_chttp2_parse_error;
+
+/* 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
+#define GRPC_CHTTP2_FRAME_CONTINUATION 9
+#define GRPC_CHTTP2_FRAME_RST_STREAM 3
+#define GRPC_CHTTP2_FRAME_SETTINGS 4
+#define GRPC_CHTTP2_FRAME_PING 6
+#define GRPC_CHTTP2_FRAME_GOAWAY 7
+#define GRPC_CHTTP2_FRAME_WINDOW_UPDATE 8
+
+#define GRPC_CHTTP2_MAX_PAYLOAD_LENGTH ((1 << 14) - 1)
+
+#define GRPC_CHTTP2_DATA_FLAG_END_STREAM 1
+#define GRPC_CHTTP2_FLAG_ACK 1
+#define GRPC_CHTTP2_DATA_FLAG_END_HEADERS 4
+#define GRPC_CHTTP2_DATA_FLAG_PADDED 8
+#define GRPC_CHTTP2_FLAG_HAS_PRIORITY 0x20
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.c b/src/core/ext/transport/chttp2/transport/frame_data.c
new file mode 100644
index 0000000..cdd6246
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_data.c
@@ -0,0 +1,248 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/frame_data.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/transport.h"
+
+grpc_chttp2_parse_error grpc_chttp2_data_parser_init(
+    grpc_chttp2_data_parser *parser) {
+  parser->state = GRPC_CHTTP2_DATA_FH_0;
+  parser->parsing_frame = NULL;
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_data_parser *parser) {
+  grpc_byte_stream *bs;
+  if (parser->parsing_frame) {
+    grpc_chttp2_incoming_byte_stream_finished(exec_ctx, parser->parsing_frame,
+                                              0, 1);
+  }
+  while (
+      (bs = grpc_chttp2_incoming_frame_queue_pop(&parser->incoming_frames))) {
+    grpc_byte_stream_destroy(exec_ctx, bs);
+  }
+}
+
+grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
+    grpc_chttp2_data_parser *parser, uint8_t flags) {
+  if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
+    gpr_log(GPR_ERROR, "unsupported data flags: 0x%02x", flags);
+    return GRPC_CHTTP2_STREAM_ERROR;
+  }
+
+  if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
+    parser->is_last_frame = 1;
+  } else {
+    parser->is_last_frame = 0;
+  }
+
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+void grpc_chttp2_incoming_frame_queue_merge(
+    grpc_chttp2_incoming_frame_queue *head_dst,
+    grpc_chttp2_incoming_frame_queue *tail_src) {
+  if (tail_src->head == NULL) {
+    return;
+  }
+
+  if (head_dst->head == NULL) {
+    *head_dst = *tail_src;
+    memset(tail_src, 0, sizeof(*tail_src));
+    return;
+  }
+
+  head_dst->tail->next_message = tail_src->head;
+  head_dst->tail = tail_src->tail;
+  memset(tail_src, 0, sizeof(*tail_src));
+}
+
+grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop(
+    grpc_chttp2_incoming_frame_queue *q) {
+  grpc_byte_stream *out;
+  if (q->head == NULL) {
+    return NULL;
+  }
+  out = &q->head->base;
+  if (q->head == q->tail) {
+    memset(q, 0, sizeof(*q));
+  } else {
+    q->head = q->head->next_message;
+  }
+  return out;
+}
+
+void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf,
+                             uint32_t write_bytes, int is_eof,
+                             gpr_slice_buffer *outbuf) {
+  gpr_slice hdr;
+  uint8_t *p;
+
+  hdr = gpr_slice_malloc(9);
+  p = GPR_SLICE_START_PTR(hdr);
+  GPR_ASSERT(write_bytes < (1 << 24));
+  *p++ = (uint8_t)(write_bytes >> 16);
+  *p++ = (uint8_t)(write_bytes >> 8);
+  *p++ = (uint8_t)(write_bytes);
+  *p++ = GRPC_CHTTP2_FRAME_DATA;
+  *p++ = is_eof ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0;
+  *p++ = (uint8_t)(id >> 24);
+  *p++ = (uint8_t)(id >> 16);
+  *p++ = (uint8_t)(id >> 8);
+  *p++ = (uint8_t)(id);
+  gpr_slice_buffer_add(outbuf, hdr);
+
+  gpr_slice_buffer_move_first(inbuf, write_bytes, outbuf);
+}
+
+grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
+    grpc_exec_ctx *exec_ctx, void *parser,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+  uint8_t *const beg = GPR_SLICE_START_PTR(slice);
+  uint8_t *const end = GPR_SLICE_END_PTR(slice);
+  uint8_t *cur = beg;
+  grpc_chttp2_data_parser *p = parser;
+  uint32_t message_flags;
+  grpc_chttp2_incoming_byte_stream *incoming_byte_stream;
+
+  if (is_last && p->is_last_frame) {
+    stream_parsing->received_close = 1;
+  }
+
+  if (cur == end) {
+    return GRPC_CHTTP2_PARSE_OK;
+  }
+
+  switch (p->state) {
+  fh_0:
+    case GRPC_CHTTP2_DATA_FH_0:
+      p->frame_type = *cur;
+      switch (p->frame_type) {
+        case 0:
+          p->is_frame_compressed = 0; /* GPR_FALSE */
+          break;
+        case 1:
+          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 = ((uint32_t)*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 |= ((uint32_t)*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 |= ((uint32_t)*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 |= ((uint32_t)*cur);
+      p->state = GRPC_CHTTP2_DATA_FRAME;
+      ++cur;
+      message_flags = 0;
+      if (p->is_frame_compressed) {
+        message_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
+      }
+      p->parsing_frame = incoming_byte_stream =
+          grpc_chttp2_incoming_byte_stream_create(
+              exec_ctx, transport_parsing, stream_parsing, p->frame_size,
+              message_flags, &p->incoming_frames);
+    /* 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;
+      }
+      grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
+                                               stream_parsing);
+      if ((uint32_t)(end - cur) == p->frame_size) {
+        grpc_chttp2_incoming_byte_stream_push(
+            exec_ctx, p->parsing_frame,
+            gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
+        grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1,
+                                                  1);
+        p->parsing_frame = NULL;
+        p->state = GRPC_CHTTP2_DATA_FH_0;
+        return GRPC_CHTTP2_PARSE_OK;
+      } else if ((uint32_t)(end - cur) > p->frame_size) {
+        grpc_chttp2_incoming_byte_stream_push(
+            exec_ctx, p->parsing_frame,
+            gpr_slice_sub(slice, (size_t)(cur - beg),
+                          (size_t)(cur + p->frame_size - beg)));
+        grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1,
+                                                  1);
+        p->parsing_frame = NULL;
+        cur += p->frame_size;
+        goto fh_0; /* loop */
+      } else {
+        grpc_chttp2_incoming_byte_stream_push(
+            exec_ctx, p->parsing_frame,
+            gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
+        GPR_ASSERT((size_t)(end - cur) <= p->frame_size);
+        p->frame_size -= (uint32_t)(end - cur);
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+  }
+
+  GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
+}
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.h b/src/core/ext/transport/chttp2/transport/frame_data.h
new file mode 100644
index 0000000..f2762ed
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_data.h
@@ -0,0 +1,101 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_DATA_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_DATA_H
+
+/* Parser for GRPC streams embedded in DATA frames */
+
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+#include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/byte_stream.h"
+
+typedef enum {
+  GRPC_CHTTP2_DATA_FH_0,
+  GRPC_CHTTP2_DATA_FH_1,
+  GRPC_CHTTP2_DATA_FH_2,
+  GRPC_CHTTP2_DATA_FH_3,
+  GRPC_CHTTP2_DATA_FH_4,
+  GRPC_CHTTP2_DATA_FRAME
+} grpc_chttp2_stream_state;
+
+typedef struct grpc_chttp2_incoming_byte_stream
+    grpc_chttp2_incoming_byte_stream;
+
+typedef struct grpc_chttp2_incoming_frame_queue {
+  grpc_chttp2_incoming_byte_stream *head;
+  grpc_chttp2_incoming_byte_stream *tail;
+} grpc_chttp2_incoming_frame_queue;
+
+typedef struct {
+  grpc_chttp2_stream_state state;
+  uint8_t is_last_frame;
+  uint8_t frame_type;
+  uint32_t frame_size;
+
+  int is_frame_compressed;
+  grpc_chttp2_incoming_frame_queue incoming_frames;
+  grpc_chttp2_incoming_byte_stream *parsing_frame;
+} grpc_chttp2_data_parser;
+
+void grpc_chttp2_incoming_frame_queue_merge(
+    grpc_chttp2_incoming_frame_queue *head_dst,
+    grpc_chttp2_incoming_frame_queue *tail_src);
+grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop(
+    grpc_chttp2_incoming_frame_queue *q);
+
+/* initialize per-stream state for data frame parsing */
+grpc_chttp2_parse_error grpc_chttp2_data_parser_init(
+    grpc_chttp2_data_parser *parser);
+
+void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_data_parser *parser);
+
+/* start processing a new data frame */
+grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
+    grpc_chttp2_data_parser *parser, uint8_t flags);
+
+/* 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(
+    grpc_exec_ctx *exec_ctx, void *parser,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+
+void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf,
+                             uint32_t write_bytes, int is_eof,
+                             gpr_slice_buffer *outbuf);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_DATA_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.c b/src/core/ext/transport/chttp2/transport/frame_goaway.c
new file mode 100644
index 0000000..3697fde
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.c
@@ -0,0 +1,193 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p) {
+  p->debug_data = NULL;
+}
+
+void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p) {
+  gpr_free(p->debug_data);
+}
+
+grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
+    grpc_chttp2_goaway_parser *p, uint32_t length, uint8_t flags) {
+  if (length < 8) {
+    gpr_log(GPR_ERROR, "goaway frame too short (%d bytes)", length);
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  }
+
+  gpr_free(p->debug_data);
+  p->debug_length = length - 8;
+  p->debug_data = gpr_malloc(p->debug_length);
+  p->debug_pos = 0;
+  p->state = GRPC_CHTTP2_GOAWAY_LSI0;
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
+    grpc_exec_ctx *exec_ctx, void *parser,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+  uint8_t *const beg = GPR_SLICE_START_PTR(slice);
+  uint8_t *const end = GPR_SLICE_END_PTR(slice);
+  uint8_t *cur = beg;
+  grpc_chttp2_goaway_parser *p = parser;
+
+  switch (p->state) {
+    case GRPC_CHTTP2_GOAWAY_LSI0:
+      if (cur == end) {
+        p->state = GRPC_CHTTP2_GOAWAY_LSI0;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+      p->last_stream_id = ((uint32_t)*cur) << 24;
+      ++cur;
+    /* fallthrough */
+    case GRPC_CHTTP2_GOAWAY_LSI1:
+      if (cur == end) {
+        p->state = GRPC_CHTTP2_GOAWAY_LSI1;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+      p->last_stream_id |= ((uint32_t)*cur) << 16;
+      ++cur;
+    /* fallthrough */
+    case GRPC_CHTTP2_GOAWAY_LSI2:
+      if (cur == end) {
+        p->state = GRPC_CHTTP2_GOAWAY_LSI2;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+      p->last_stream_id |= ((uint32_t)*cur) << 8;
+      ++cur;
+    /* fallthrough */
+    case GRPC_CHTTP2_GOAWAY_LSI3:
+      if (cur == end) {
+        p->state = GRPC_CHTTP2_GOAWAY_LSI3;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+      p->last_stream_id |= ((uint32_t)*cur);
+      ++cur;
+    /* fallthrough */
+    case GRPC_CHTTP2_GOAWAY_ERR0:
+      if (cur == end) {
+        p->state = GRPC_CHTTP2_GOAWAY_ERR0;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+      p->error_code = ((uint32_t)*cur) << 24;
+      ++cur;
+    /* fallthrough */
+    case GRPC_CHTTP2_GOAWAY_ERR1:
+      if (cur == end) {
+        p->state = GRPC_CHTTP2_GOAWAY_ERR1;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+      p->error_code |= ((uint32_t)*cur) << 16;
+      ++cur;
+    /* fallthrough */
+    case GRPC_CHTTP2_GOAWAY_ERR2:
+      if (cur == end) {
+        p->state = GRPC_CHTTP2_GOAWAY_ERR2;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+      p->error_code |= ((uint32_t)*cur) << 8;
+      ++cur;
+    /* fallthrough */
+    case GRPC_CHTTP2_GOAWAY_ERR3:
+      if (cur == end) {
+        p->state = GRPC_CHTTP2_GOAWAY_ERR3;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
+      p->error_code |= ((uint32_t)*cur);
+      ++cur;
+    /* fallthrough */
+    case GRPC_CHTTP2_GOAWAY_DEBUG:
+      memcpy(p->debug_data + p->debug_pos, cur, (size_t)(end - cur));
+      GPR_ASSERT((size_t)(end - cur) < UINT32_MAX - p->debug_pos);
+      p->debug_pos += (uint32_t)(end - cur);
+      p->state = GRPC_CHTTP2_GOAWAY_DEBUG;
+      if (is_last) {
+        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 = (grpc_status_code)p->error_code;
+        transport_parsing->goaway_text =
+            gpr_slice_new(p->debug_data, p->debug_length, gpr_free);
+        p->debug_data = NULL;
+      }
+      return GRPC_CHTTP2_PARSE_OK;
+  }
+  GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
+}
+
+void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,
+                               gpr_slice debug_data,
+                               gpr_slice_buffer *slice_buffer) {
+  gpr_slice header = gpr_slice_malloc(9 + 4 + 4);
+  uint8_t *p = GPR_SLICE_START_PTR(header);
+  uint32_t frame_length;
+  GPR_ASSERT(GPR_SLICE_LENGTH(debug_data) < UINT32_MAX - 4 - 4);
+  frame_length = 4 + 4 + (uint32_t)GPR_SLICE_LENGTH(debug_data);
+
+  /* frame header: length */
+  *p++ = (uint8_t)(frame_length >> 16);
+  *p++ = (uint8_t)(frame_length >> 8);
+  *p++ = (uint8_t)(frame_length);
+  /* frame header: type */
+  *p++ = GRPC_CHTTP2_FRAME_GOAWAY;
+  /* frame header: flags */
+  *p++ = 0;
+  /* frame header: stream id */
+  *p++ = 0;
+  *p++ = 0;
+  *p++ = 0;
+  *p++ = 0;
+  /* payload: last stream id */
+  *p++ = (uint8_t)(last_stream_id >> 24);
+  *p++ = (uint8_t)(last_stream_id >> 16);
+  *p++ = (uint8_t)(last_stream_id >> 8);
+  *p++ = (uint8_t)(last_stream_id);
+  /* payload: error code */
+  *p++ = (uint8_t)(error_code >> 24);
+  *p++ = (uint8_t)(error_code >> 16);
+  *p++ = (uint8_t)(error_code >> 8);
+  *p++ = (uint8_t)(error_code);
+  GPR_ASSERT(p == GPR_SLICE_END_PTR(header));
+  gpr_slice_buffer_add(slice_buffer, header);
+  gpr_slice_buffer_add(slice_buffer, debug_data);
+}
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.h b/src/core/ext/transport/chttp2/transport/frame_goaway.h
new file mode 100644
index 0000000..e655134
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_GOAWAY_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_GOAWAY_H
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+#include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+typedef enum {
+  GRPC_CHTTP2_GOAWAY_LSI0,
+  GRPC_CHTTP2_GOAWAY_LSI1,
+  GRPC_CHTTP2_GOAWAY_LSI2,
+  GRPC_CHTTP2_GOAWAY_LSI3,
+  GRPC_CHTTP2_GOAWAY_ERR0,
+  GRPC_CHTTP2_GOAWAY_ERR1,
+  GRPC_CHTTP2_GOAWAY_ERR2,
+  GRPC_CHTTP2_GOAWAY_ERR3,
+  GRPC_CHTTP2_GOAWAY_DEBUG
+} grpc_chttp2_goaway_parse_state;
+
+typedef struct {
+  grpc_chttp2_goaway_parse_state state;
+  uint32_t last_stream_id;
+  uint32_t error_code;
+  char *debug_data;
+  uint32_t debug_length;
+  uint32_t debug_pos;
+} grpc_chttp2_goaway_parser;
+
+void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p);
+void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p);
+grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
+    grpc_chttp2_goaway_parser *parser, uint32_t length, uint8_t flags);
+grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
+    grpc_exec_ctx *exec_ctx, 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(uint32_t last_stream_id, uint32_t error_code,
+                               gpr_slice debug_data,
+                               gpr_slice_buffer *slice_buffer);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_GOAWAY_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c
new file mode 100644
index 0000000..c0192a7
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.c
@@ -0,0 +1,97 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/frame_ping.h"
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) {
+  gpr_slice slice = gpr_slice_malloc(9 + 8);
+  uint8_t *p = GPR_SLICE_START_PTR(slice);
+
+  *p++ = 0;
+  *p++ = 0;
+  *p++ = 8;
+  *p++ = GRPC_CHTTP2_FRAME_PING;
+  *p++ = ack ? 1 : 0;
+  *p++ = 0;
+  *p++ = 0;
+  *p++ = 0;
+  *p++ = 0;
+  memcpy(p, opaque_8bytes, 8);
+
+  return slice;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
+    grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags) {
+  if (flags & 0xfe || length != 8) {
+    gpr_log(GPR_ERROR, "invalid ping: length=%d, flags=%02x", length, flags);
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  }
+  parser->byte = 0;
+  parser->is_ack = flags;
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
+    grpc_exec_ctx *exec_ctx, void *parser,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+  uint8_t *const beg = GPR_SLICE_START_PTR(slice);
+  uint8_t *const end = GPR_SLICE_END_PTR(slice);
+  uint8_t *cur = beg;
+  grpc_chttp2_ping_parser *p = parser;
+
+  while (p->byte != 8 && cur != end) {
+    p->opaque_8bytes[p->byte] = *cur;
+    cur++;
+    p->byte++;
+  }
+
+  if (p->byte == 8) {
+    GPR_ASSERT(is_last);
+    if (p->is_ack) {
+      grpc_chttp2_ack_ping(exec_ctx, transport_parsing, p->opaque_8bytes);
+    } else {
+      gpr_slice_buffer_add(&transport_parsing->qbuf,
+                           grpc_chttp2_ping_create(1, p->opaque_8bytes));
+    }
+  }
+
+  return GRPC_CHTTP2_PARSE_OK;
+}
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.h b/src/core/ext/transport/chttp2/transport/frame_ping.h
new file mode 100644
index 0000000..1c1d513
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H
+
+#include <grpc/support/slice.h>
+#include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+typedef struct {
+  uint8_t byte;
+  uint8_t is_ack;
+  uint8_t opaque_8bytes[8];
+} grpc_chttp2_ping_parser;
+
+gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes);
+
+grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
+    grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags);
+grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
+    grpc_exec_ctx *exec_ctx, void *parser,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
new file mode 100644
index 0000000..acfc362
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
@@ -0,0 +1,99 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/frame_rst_stream.h"
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+
+#include <grpc/support/log.h>
+
+#include "src/core/ext/transport/chttp2/transport/frame.h"
+
+gpr_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code) {
+  gpr_slice slice = gpr_slice_malloc(13);
+  uint8_t *p = GPR_SLICE_START_PTR(slice);
+
+  *p++ = 0;
+  *p++ = 0;
+  *p++ = 4;
+  *p++ = GRPC_CHTTP2_FRAME_RST_STREAM;
+  *p++ = 0;
+  *p++ = (uint8_t)(id >> 24);
+  *p++ = (uint8_t)(id >> 16);
+  *p++ = (uint8_t)(id >> 8);
+  *p++ = (uint8_t)(id);
+  *p++ = (uint8_t)(code >> 24);
+  *p++ = (uint8_t)(code >> 16);
+  *p++ = (uint8_t)(code >> 8);
+  *p++ = (uint8_t)(code);
+
+  return slice;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame(
+    grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags) {
+  if (length != 4) {
+    gpr_log(GPR_ERROR, "invalid rst_stream: length=%d, flags=%02x", length,
+            flags);
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  }
+  parser->byte = 0;
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
+    grpc_exec_ctx *exec_ctx, void *parser,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+  uint8_t *const beg = GPR_SLICE_START_PTR(slice);
+  uint8_t *const end = GPR_SLICE_END_PTR(slice);
+  uint8_t *cur = beg;
+  grpc_chttp2_rst_stream_parser *p = parser;
+
+  while (p->byte != 4 && cur != end) {
+    p->reason_bytes[p->byte] = *cur;
+    cur++;
+    p->byte++;
+  }
+
+  if (p->byte == 4) {
+    GPR_ASSERT(is_last);
+    stream_parsing->received_close = 1;
+    stream_parsing->saw_rst_stream = 1;
+    stream_parsing->rst_stream_reason = (((uint32_t)p->reason_bytes[0]) << 24) |
+                                        (((uint32_t)p->reason_bytes[1]) << 16) |
+                                        (((uint32_t)p->reason_bytes[2]) << 8) |
+                                        (((uint32_t)p->reason_bytes[3]));
+  }
+
+  return GRPC_CHTTP2_PARSE_OK;
+}
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
new file mode 100644
index 0000000..134f136
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H
+
+#include <grpc/support/slice.h>
+#include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+typedef struct {
+  uint8_t byte;
+  uint8_t reason_bytes[4];
+} grpc_chttp2_rst_stream_parser;
+
+gpr_slice grpc_chttp2_rst_stream_create(uint32_t stream_id, uint32_t code);
+
+grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame(
+    grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags);
+grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
+    grpc_exec_ctx *exec_ctx, void *parser,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.c b/src/core/ext/transport/chttp2/transport/frame_settings.c
new file mode 100644
index 0000000..799d87b
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.c
@@ -0,0 +1,259 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/frame_settings.h"
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
+#include "src/core/lib/debug/trace.h"
+
+#define MAX_MAX_HEADER_LIST_SIZE (1024 * 1024 * 1024)
+
+/* HTTP/2 mandated initial connection settings */
+const grpc_chttp2_setting_parameters
+    grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
+        {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
+         GRPC_CHTTP2_PROTOCOL_ERROR},
+        {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff,
+         GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
+        {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
+         GRPC_CHTTP2_PROTOCOL_ERROR},
+        {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu,
+         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
+        {"INITIAL_WINDOW_SIZE", 65535, 0, 0x7fffffffu,
+         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
+         GRPC_CHTTP2_FLOW_CONTROL_ERROR},
+        {"MAX_FRAME_SIZE", 16384, 16384, 16777215,
+         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
+        {"MAX_HEADER_LIST_SIZE", MAX_MAX_HEADER_LIST_SIZE, 0,
+         MAX_MAX_HEADER_LIST_SIZE, GRPC_CHTTP2_CLAMP_INVALID_VALUE,
+         GRPC_CHTTP2_PROTOCOL_ERROR},
+};
+
+static uint8_t *fill_header(uint8_t *out, uint32_t length, uint8_t flags) {
+  *out++ = (uint8_t)(length >> 16);
+  *out++ = (uint8_t)(length >> 8);
+  *out++ = (uint8_t)(length);
+  *out++ = GRPC_CHTTP2_FRAME_SETTINGS;
+  *out++ = flags;
+  *out++ = 0;
+  *out++ = 0;
+  *out++ = 0;
+  *out++ = 0;
+  return out;
+}
+
+gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
+                                      uint32_t force_mask, size_t count) {
+  size_t i;
+  uint32_t n = 0;
+  gpr_slice output;
+  uint8_t *p;
+
+  for (i = 0; i < count; i++) {
+    n += (new[i] != old[i] || (force_mask & (1u << i)) != 0);
+  }
+
+  output = gpr_slice_malloc(9 + 6 * n);
+  p = fill_header(GPR_SLICE_START_PTR(output), 6 * n, 0);
+
+  for (i = 0; i < count; i++) {
+    if (new[i] != old[i] || (force_mask & (1u << i)) != 0) {
+      GPR_ASSERT(i);
+      *p++ = (uint8_t)(i >> 8);
+      *p++ = (uint8_t)(i);
+      *p++ = (uint8_t)(new[i] >> 24);
+      *p++ = (uint8_t)(new[i] >> 16);
+      *p++ = (uint8_t)(new[i] >> 8);
+      *p++ = (uint8_t)(new[i]);
+      old[i] = new[i];
+    }
+  }
+
+  GPR_ASSERT(p == GPR_SLICE_END_PTR(output));
+
+  return output;
+}
+
+gpr_slice grpc_chttp2_settings_ack_create(void) {
+  gpr_slice output = gpr_slice_malloc(9);
+  fill_header(GPR_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
+  return output;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
+    grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags,
+    uint32_t *settings) {
+  parser->target_settings = settings;
+  memcpy(parser->incoming_settings, settings,
+         GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
+  parser->is_ack = 0;
+  parser->state = GRPC_CHTTP2_SPS_ID0;
+  if (flags == GRPC_CHTTP2_FLAG_ACK) {
+    parser->is_ack = 1;
+    if (length != 0) {
+      gpr_log(GPR_ERROR, "non-empty settings ack frame received");
+      return GRPC_CHTTP2_CONNECTION_ERROR;
+    }
+    return GRPC_CHTTP2_PARSE_OK;
+  } else if (flags != 0) {
+    gpr_log(GPR_ERROR, "invalid flags on settings frame");
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  } else if (length % 6 != 0) {
+    gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes");
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  } else {
+    return GRPC_CHTTP2_PARSE_OK;
+  }
+}
+
+grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
+    grpc_exec_ctx *exec_ctx, 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 uint8_t *cur = GPR_SLICE_START_PTR(slice);
+  const uint8_t *end = GPR_SLICE_END_PTR(slice);
+
+  if (parser->is_ack) {
+    return GRPC_CHTTP2_PARSE_OK;
+  }
+
+  for (;;) {
+    switch (parser->state) {
+      case GRPC_CHTTP2_SPS_ID0:
+        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(uint32_t));
+            gpr_slice_buffer_add(&transport_parsing->qbuf,
+                                 grpc_chttp2_settings_ack_create());
+          }
+          return GRPC_CHTTP2_PARSE_OK;
+        }
+        parser->id = (uint16_t)(((uint16_t)*cur) << 8);
+        cur++;
+      /* fallthrough */
+      case GRPC_CHTTP2_SPS_ID1:
+        if (cur == end) {
+          parser->state = GRPC_CHTTP2_SPS_ID1;
+          return GRPC_CHTTP2_PARSE_OK;
+        }
+        parser->id = (uint16_t)(parser->id | (*cur));
+        cur++;
+      /* fallthrough */
+      case GRPC_CHTTP2_SPS_VAL0:
+        if (cur == end) {
+          parser->state = GRPC_CHTTP2_SPS_VAL0;
+          return GRPC_CHTTP2_PARSE_OK;
+        }
+        parser->value = ((uint32_t)*cur) << 24;
+        cur++;
+      /* fallthrough */
+      case GRPC_CHTTP2_SPS_VAL1:
+        if (cur == end) {
+          parser->state = GRPC_CHTTP2_SPS_VAL1;
+          return GRPC_CHTTP2_PARSE_OK;
+        }
+        parser->value |= ((uint32_t)*cur) << 16;
+        cur++;
+      /* fallthrough */
+      case GRPC_CHTTP2_SPS_VAL2:
+        if (cur == end) {
+          parser->state = GRPC_CHTTP2_SPS_VAL2;
+          return GRPC_CHTTP2_PARSE_OK;
+        }
+        parser->value |= ((uint32_t)*cur) << 8;
+        cur++;
+      /* fallthrough */
+      case GRPC_CHTTP2_SPS_VAL3:
+        if (cur == end) {
+          parser->state = GRPC_CHTTP2_SPS_VAL3;
+          return GRPC_CHTTP2_PARSE_OK;
+        } else {
+          parser->state = GRPC_CHTTP2_SPS_ID0;
+        }
+        parser->value |= *cur;
+        cur++;
+
+        if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) {
+          const grpc_chttp2_setting_parameters *sp =
+              &grpc_chttp2_settings_parameters[parser->id];
+          if (parser->value < sp->min_value || parser->value > sp->max_value) {
+            switch (sp->invalid_value_behavior) {
+              case GRPC_CHTTP2_CLAMP_INVALID_VALUE:
+                parser->value =
+                    GPR_CLAMP(parser->value, sp->min_value, sp->max_value);
+                break;
+              case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE:
+                grpc_chttp2_goaway_append(
+                    transport_parsing->last_incoming_stream_id, sp->error_value,
+                    gpr_slice_from_static_string("HTTP2 settings error"),
+                    &transport_parsing->qbuf);
+                gpr_log(GPR_ERROR, "invalid value %u passed for %s",
+                        parser->value, sp->name);
+                return GRPC_CHTTP2_CONNECTION_ERROR;
+            }
+          }
+          if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
+              parser->incoming_settings[parser->id] != parser->value) {
+            transport_parsing->initial_window_update =
+                (int64_t)parser->value - parser->incoming_settings[parser->id];
+            if (grpc_http_trace) {
+              gpr_log(GPR_DEBUG, "adding %d for initial_window change",
+                      (int)transport_parsing->initial_window_update);
+            }
+          }
+          parser->incoming_settings[parser->id] = parser->value;
+          if (grpc_http_trace) {
+            gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d",
+                    transport_parsing->is_client ? "CLI" : "SVR", parser->id,
+                    parser->value);
+          }
+        } else {
+          gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
+                  parser->id, parser->value);
+        }
+        break;
+    }
+  }
+}
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.h b/src/core/ext/transport/chttp2/transport/frame_settings.h
new file mode 100644
index 0000000..73524ad
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.h
@@ -0,0 +1,103 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+#include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+typedef enum {
+  GRPC_CHTTP2_SPS_ID0,
+  GRPC_CHTTP2_SPS_ID1,
+  GRPC_CHTTP2_SPS_VAL0,
+  GRPC_CHTTP2_SPS_VAL1,
+  GRPC_CHTTP2_SPS_VAL2,
+  GRPC_CHTTP2_SPS_VAL3
+} grpc_chttp2_settings_parse_state;
+
+/* The things HTTP/2 defines as connection level settings */
+typedef enum {
+  GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE = 1,
+  GRPC_CHTTP2_SETTINGS_ENABLE_PUSH = 2,
+  GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 3,
+  GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 4,
+  GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE = 5,
+  GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 6,
+  GRPC_CHTTP2_NUM_SETTINGS
+} grpc_chttp2_setting_id;
+
+typedef struct {
+  grpc_chttp2_settings_parse_state state;
+  uint32_t *target_settings;
+  uint8_t is_ack;
+  uint16_t id;
+  uint32_t value;
+  uint32_t incoming_settings[GRPC_CHTTP2_NUM_SETTINGS];
+} grpc_chttp2_settings_parser;
+
+typedef enum {
+  GRPC_CHTTP2_CLAMP_INVALID_VALUE,
+  GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE
+} grpc_chttp2_invalid_value_behavior;
+
+typedef struct {
+  const char *name;
+  uint32_t default_value;
+  uint32_t min_value;
+  uint32_t max_value;
+  grpc_chttp2_invalid_value_behavior invalid_value_behavior;
+  uint32_t error_value;
+} grpc_chttp2_setting_parameters;
+
+/* HTTP/2 mandated connection setting parameters */
+extern const grpc_chttp2_setting_parameters
+    grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS];
+
+/* Create a settings frame by diffing old & new, and updating old to be new */
+gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
+                                      uint32_t force_mask, size_t count);
+/* Create an ack settings frame */
+gpr_slice grpc_chttp2_settings_ack_create(void);
+
+grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
+    grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags,
+    uint32_t *settings);
+grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
+    grpc_exec_ctx *exec_ctx, void *parser,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.c b/src/core/ext/transport/chttp2/transport/frame_window_update.c
new file mode 100644
index 0000000..1a561ce
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.c
@@ -0,0 +1,113 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/frame_window_update.h"
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+
+#include <grpc/support/log.h>
+
+gpr_slice grpc_chttp2_window_update_create(uint32_t id,
+                                           uint32_t window_update) {
+  gpr_slice slice = gpr_slice_malloc(13);
+  uint8_t *p = GPR_SLICE_START_PTR(slice);
+
+  GPR_ASSERT(window_update);
+
+  *p++ = 0;
+  *p++ = 0;
+  *p++ = 4;
+  *p++ = GRPC_CHTTP2_FRAME_WINDOW_UPDATE;
+  *p++ = 0;
+  *p++ = (uint8_t)(id >> 24);
+  *p++ = (uint8_t)(id >> 16);
+  *p++ = (uint8_t)(id >> 8);
+  *p++ = (uint8_t)(id);
+  *p++ = (uint8_t)(window_update >> 24);
+  *p++ = (uint8_t)(window_update >> 16);
+  *p++ = (uint8_t)(window_update >> 8);
+  *p++ = (uint8_t)(window_update);
+
+  return slice;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
+    grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags) {
+  if (flags || length != 4) {
+    gpr_log(GPR_ERROR, "invalid window update: length=%d, flags=%02x", length,
+            flags);
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  }
+  parser->byte = 0;
+  parser->amount = 0;
+  return GRPC_CHTTP2_PARSE_OK;
+}
+
+grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
+    grpc_exec_ctx *exec_ctx, void *parser,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+  uint8_t *const beg = GPR_SLICE_START_PTR(slice);
+  uint8_t *const end = GPR_SLICE_END_PTR(slice);
+  uint8_t *cur = beg;
+  grpc_chttp2_window_update_parser *p = parser;
+
+  while (p->byte != 4 && cur != end) {
+    p->amount |= ((uint32_t)*cur) << (8 * (3 - p->byte));
+    cur++;
+    p->byte++;
+  }
+
+  if (p->byte == 4) {
+    uint32_t received_update = p->amount;
+    if (received_update == 0 || (received_update & 0x80000000u)) {
+      gpr_log(GPR_ERROR, "invalid window update bytes: %d", p->amount);
+      return GRPC_CHTTP2_CONNECTION_ERROR;
+    }
+    GPR_ASSERT(is_last);
+
+    if (transport_parsing->incoming_stream_id != 0) {
+      if (stream_parsing != NULL) {
+        GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", transport_parsing,
+                                       stream_parsing, outgoing_window,
+                                       received_update);
+        grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
+                                                 stream_parsing);
+      }
+    } else {
+      GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parse", transport_parsing,
+                                        outgoing_window, received_update);
+    }
+  }
+
+  return GRPC_CHTTP2_PARSE_OK;
+}
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.h b/src/core/ext/transport/chttp2/transport/frame_window_update.h
new file mode 100644
index 0000000..f9f670b
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H
+
+#include <grpc/support/slice.h>
+#include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+typedef struct {
+  uint8_t byte;
+  uint8_t is_connection_update;
+  uint32_t amount;
+} grpc_chttp2_window_update_parser;
+
+gpr_slice grpc_chttp2_window_update_create(uint32_t id, uint32_t window_delta);
+
+grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
+    grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags);
+grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
+    grpc_exec_ctx *exec_ctx, void *parser,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
new file mode 100644
index 0000000..819addd
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
@@ -0,0 +1,568 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
+
+#include <assert.h>
+#include <string.h>
+
+/* This is here for grpc_is_binary_header
+ * TODO(murgatroid99): Remove this
+ */
+#include <grpc/grpc.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
+#include "src/core/ext/transport/chttp2/transport/hpack_table.h"
+#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
+#include "src/core/ext/transport/chttp2/transport/varint.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#define HASH_FRAGMENT_1(x) ((x)&255)
+#define HASH_FRAGMENT_2(x) ((x >> 8) & 255)
+#define HASH_FRAGMENT_3(x) ((x >> 16) & 255)
+#define HASH_FRAGMENT_4(x) ((x >> 24) & 255)
+
+/* if the probability of this item being seen again is < 1/x then don't add
+   it to the table */
+#define ONE_ON_ADD_PROBABILITY 128
+/* don't consider adding anything bigger than this to the hpack table */
+#define MAX_DECODER_SPACE_USAGE 512
+
+typedef struct {
+  int is_first_frame;
+  /* number of bytes in 'output' when we started the frame - used to calculate
+     frame length */
+  size_t output_length_at_start_of_frame;
+  /* index (in output) of the header for the current frame */
+  size_t header_idx;
+  /* have we seen a regular (non-colon-prefixed) header yet? */
+  uint8_t seen_regular_header;
+  /* output stream id */
+  uint32_t stream_id;
+  gpr_slice_buffer *output;
+} framer_state;
+
+/* fills p (which is expected to be 9 bytes long) with a data frame header */
+static void fill_header(uint8_t *p, uint8_t type, uint32_t id, size_t len,
+                        uint8_t flags) {
+  GPR_ASSERT(len < 16777316);
+  *p++ = (uint8_t)(len >> 16);
+  *p++ = (uint8_t)(len >> 8);
+  *p++ = (uint8_t)(len);
+  *p++ = type;
+  *p++ = flags;
+  *p++ = (uint8_t)(id >> 24);
+  *p++ = (uint8_t)(id >> 16);
+  *p++ = (uint8_t)(id >> 8);
+  *p++ = (uint8_t)(id);
+}
+
+/* finish a frame - fill in the previously reserved header */
+static void finish_frame(framer_state *st, int is_header_boundary,
+                         int is_last_in_stream) {
+  uint8_t type = 0xff;
+  type = st->is_first_frame ? GRPC_CHTTP2_FRAME_HEADER
+                            : GRPC_CHTTP2_FRAME_CONTINUATION;
+  fill_header(
+      GPR_SLICE_START_PTR(st->output->slices[st->header_idx]), type,
+      st->stream_id, st->output->length - st->output_length_at_start_of_frame,
+      (uint8_t)((is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) |
+                (is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0)));
+  st->is_first_frame = 0;
+}
+
+/* begin a new frame: reserve off header space, remember how many bytes we'd
+   output before beginning */
+static void begin_frame(framer_state *st) {
+  st->header_idx =
+      gpr_slice_buffer_add_indexed(st->output, gpr_slice_malloc(9));
+  st->output_length_at_start_of_frame = st->output->length;
+}
+
+/* make sure that the current frame is of the type desired, and has sufficient
+   space to add at least about_to_add bytes -- finishes the current frame if
+   needed */
+static void ensure_space(framer_state *st, size_t need_bytes) {
+  if (st->output->length - st->output_length_at_start_of_frame + need_bytes <=
+      GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) {
+    return;
+  }
+  finish_frame(st, 0, 0);
+  begin_frame(st);
+}
+
+/* increment a filter count, halve all counts if one element reaches max */
+static void inc_filter(uint8_t idx, uint32_t *sum, uint8_t *elems) {
+  elems[idx]++;
+  if (elems[idx] < 255) {
+    (*sum)++;
+  } else {
+    int i;
+    *sum = 0;
+    for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_FILTERS; i++) {
+      elems[i] /= 2;
+      (*sum) += elems[i];
+    }
+  }
+}
+
+static void add_header_data(framer_state *st, gpr_slice slice) {
+  size_t len = GPR_SLICE_LENGTH(slice);
+  size_t remaining;
+  if (len == 0) return;
+  remaining = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH +
+              st->output_length_at_start_of_frame - st->output->length;
+  if (len <= remaining) {
+    gpr_slice_buffer_add(st->output, slice);
+  } else {
+    gpr_slice_buffer_add(st->output, gpr_slice_split_head(&slice, remaining));
+    finish_frame(st, 0, 0);
+    begin_frame(st);
+    add_header_data(st, slice);
+  }
+}
+
+static uint8_t *add_tiny_header_data(framer_state *st, size_t len) {
+  ensure_space(st, len);
+  return gpr_slice_buffer_tiny_add(st->output, len);
+}
+
+static void evict_entry(grpc_chttp2_hpack_compressor *c) {
+  c->tail_remote_index++;
+  GPR_ASSERT(c->tail_remote_index > 0);
+  GPR_ASSERT(c->table_size >=
+             c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
+  GPR_ASSERT(c->table_elems > 0);
+  c->table_size =
+      (uint16_t)(c->table_size -
+                 c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
+  c->table_elems--;
+}
+
+/* add an element to the decoder table */
+static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
+  uint32_t key_hash = elem->key->hash;
+  uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
+  uint32_t new_index = c->tail_remote_index + c->table_elems + 1;
+  size_t elem_size = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
+                     GPR_SLICE_LENGTH(elem->value->slice);
+
+  GPR_ASSERT(elem_size < 65536);
+
+  if (elem_size > c->max_table_size) {
+    while (c->table_size > 0) {
+      evict_entry(c);
+    }
+    return;
+  }
+
+  /* Reserve space for this element in the remote table: if this overflows
+     the current table, drop elements until it fits, matching the decompressor
+     algorithm */
+  while (c->table_size + elem_size > c->max_table_size) {
+    evict_entry(c);
+  }
+  GPR_ASSERT(c->table_elems < c->max_table_size);
+  c->table_elem_size[new_index % c->cap_table_elems] = (uint16_t)elem_size;
+  c->table_size = (uint16_t)(c->table_size + elem_size);
+  c->table_elems++;
+
+  /* Store this element into {entries,indices}_elem */
+  if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) {
+    /* already there: update with new index */
+    c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
+  } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) {
+    /* already there (cuckoo): update with new index */
+    c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
+  } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) {
+    /* not there, but a free element: add */
+    c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
+    c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
+  } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) {
+    /* not there (cuckoo), but a free element: add */
+    c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
+    c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
+  } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] <
+             c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) {
+    /* not there: replace oldest */
+    GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_2(elem_hash)]);
+    c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
+    c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
+  } else {
+    /* not there: replace oldest */
+    GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_3(elem_hash)]);
+    c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
+    c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
+  }
+
+  /* do exactly the same for the key (so we can find by that again too) */
+
+  if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key) {
+    c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
+  } 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->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->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);
+    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);
+    c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
+  }
+}
+
+static void emit_indexed(grpc_chttp2_hpack_compressor *c, uint32_t elem_index,
+                         framer_state *st) {
+  uint32_t len = GRPC_CHTTP2_VARINT_LENGTH(elem_index, 1);
+  GRPC_CHTTP2_WRITE_VARINT(elem_index, 1, 0x80, add_tiny_header_data(st, len),
+                           len);
+}
+
+static gpr_slice get_wire_value(grpc_mdelem *elem, uint8_t *huffman_prefix) {
+  if (grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(elem->key->slice),
+                            GPR_SLICE_LENGTH(elem->key->slice))) {
+    *huffman_prefix = 0x80;
+    return grpc_mdstr_as_base64_encoded_and_huffman_compressed(elem->value);
+  }
+  /* TODO(ctiller): opportunistically compress non-binary headers */
+  *huffman_prefix = 0x00;
+  return elem->value->slice;
+}
+
+static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c,
+                               uint32_t key_index, grpc_mdelem *elem,
+                               framer_state *st) {
+  uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2);
+  uint8_t huffman_prefix;
+  gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
+  size_t len_val = GPR_SLICE_LENGTH(value_slice);
+  uint32_t len_val_len;
+  GPR_ASSERT(len_val <= UINT32_MAX);
+  len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
+  GRPC_CHTTP2_WRITE_VARINT(key_index, 2, 0x40,
+                           add_tiny_header_data(st, len_pfx), len_pfx);
+  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
+                           add_tiny_header_data(st, len_val_len), len_val_len);
+  add_header_data(st, gpr_slice_ref(value_slice));
+}
+
+static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
+                              uint32_t key_index, grpc_mdelem *elem,
+                              framer_state *st) {
+  uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4);
+  uint8_t huffman_prefix;
+  gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
+  size_t len_val = GPR_SLICE_LENGTH(value_slice);
+  uint32_t len_val_len;
+  GPR_ASSERT(len_val <= UINT32_MAX);
+  len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
+  GRPC_CHTTP2_WRITE_VARINT(key_index, 4, 0x00,
+                           add_tiny_header_data(st, len_pfx), len_pfx);
+  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
+                           add_tiny_header_data(st, len_val_len), len_val_len);
+  add_header_data(st, gpr_slice_ref(value_slice));
+}
+
+static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
+                                 grpc_mdelem *elem, framer_state *st) {
+  uint32_t len_key = (uint32_t)GPR_SLICE_LENGTH(elem->key->slice);
+  uint8_t huffman_prefix;
+  gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
+  uint32_t len_val = (uint32_t)GPR_SLICE_LENGTH(value_slice);
+  uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
+  uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
+  GPR_ASSERT(len_key <= UINT32_MAX);
+  GPR_ASSERT(GPR_SLICE_LENGTH(value_slice) <= UINT32_MAX);
+  *add_tiny_header_data(st, 1) = 0x40;
+  GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
+                           add_tiny_header_data(st, len_key_len), len_key_len);
+  add_header_data(st, gpr_slice_ref(elem->key->slice));
+  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
+                           add_tiny_header_data(st, len_val_len), len_val_len);
+  add_header_data(st, gpr_slice_ref(value_slice));
+}
+
+static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
+                                grpc_mdelem *elem, framer_state *st) {
+  uint32_t len_key = (uint32_t)GPR_SLICE_LENGTH(elem->key->slice);
+  uint8_t huffman_prefix;
+  gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
+  uint32_t len_val = (uint32_t)GPR_SLICE_LENGTH(value_slice);
+  uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
+  uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
+  GPR_ASSERT(len_key <= UINT32_MAX);
+  GPR_ASSERT(GPR_SLICE_LENGTH(value_slice) <= UINT32_MAX);
+  *add_tiny_header_data(st, 1) = 0x00;
+  GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
+                           add_tiny_header_data(st, len_key_len), len_key_len);
+  add_header_data(st, gpr_slice_ref(elem->key->slice));
+  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
+                           add_tiny_header_data(st, len_val_len), len_val_len);
+  add_header_data(st, gpr_slice_ref(value_slice));
+}
+
+static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c,
+                                             framer_state *st) {
+  uint32_t len = GRPC_CHTTP2_VARINT_LENGTH(c->max_table_size, 3);
+  GRPC_CHTTP2_WRITE_VARINT(c->max_table_size, 3, 0x20,
+                           add_tiny_header_data(st, len), len);
+  c->advertise_table_size_change = 0;
+}
+
+static uint32_t dynidx(grpc_chttp2_hpack_compressor *c, uint32_t elem_index) {
+  return 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY + c->tail_remote_index +
+         c->table_elems - elem_index;
+}
+
+/* encode an mdelem */
+static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
+                      framer_state *st) {
+  uint32_t key_hash = elem->key->hash;
+  uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
+  size_t decoder_space_usage;
+  uint32_t indices_key;
+  int should_add_elem;
+
+  GPR_ASSERT(GPR_SLICE_LENGTH(elem->key->slice) > 0);
+  if (GPR_SLICE_START_PTR(elem->key->slice)[0] != ':') { /* regular header */
+    st->seen_regular_header = 1;
+  } else {
+    GPR_ASSERT(
+        st->seen_regular_header == 0 &&
+        "Reserved header (colon-prefixed) happening after regular ones.");
+  }
+
+  inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems);
+
+  /* is this elem currently in the decoders table? */
+
+  if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem &&
+      c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
+    /* HIT: complete element (first cuckoo hash) */
+    emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
+                 st);
+    return;
+  }
+
+  if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem &&
+      c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) {
+    /* HIT: complete element (second cuckoo hash) */
+    emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
+                 st);
+    return;
+  }
+
+  /* should this elem be in the table? */
+  decoder_space_usage = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
+                        GPR_SLICE_LENGTH(elem->value->slice);
+  should_add_elem = decoder_space_usage < MAX_DECODER_SPACE_USAGE &&
+                    c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
+                        c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
+
+  /* no hits for the elem... maybe there's a key? */
+
+  indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
+  if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key &&
+      indices_key > c->tail_remote_index) {
+    /* HIT: key (first cuckoo hash) */
+    if (should_add_elem) {
+      emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
+      add_elem(c, elem);
+      return;
+    } else {
+      emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
+      return;
+    }
+    GPR_UNREACHABLE_CODE(return );
+  }
+
+  indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
+  if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key &&
+      indices_key > c->tail_remote_index) {
+    /* HIT: key (first cuckoo hash) */
+    if (should_add_elem) {
+      emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
+      add_elem(c, elem);
+      return;
+    } else {
+      emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
+      return;
+    }
+    GPR_UNREACHABLE_CODE(return );
+  }
+
+  /* no elem, key in the table... fall back to literal emission */
+
+  if (should_add_elem) {
+    emit_lithdr_incidx_v(c, elem, st);
+    add_elem(c, elem);
+    return;
+  } else {
+    emit_lithdr_noidx_v(c, elem, st);
+    return;
+  }
+  GPR_UNREACHABLE_CODE(return );
+}
+
+#define STRLEN_LIT(x) (sizeof(x) - 1)
+#define TIMEOUT_KEY "grpc-timeout"
+
+static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
+                         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(deadline.clock_type)), timeout_str);
+  mdelem = grpc_mdelem_from_metadata_strings(
+      GRPC_MDSTR_GRPC_TIMEOUT, grpc_mdstr_from_string(timeout_str));
+  hpack_enc(c, mdelem, st);
+  GRPC_MDELEM_UNREF(mdelem);
+}
+
+static uint32_t elems_for_bytes(uint32_t bytes) { return (bytes + 31) / 32; }
+
+void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c) {
+  memset(c, 0, sizeof(*c));
+  c->max_table_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
+  c->cap_table_elems = elems_for_bytes(c->max_table_size);
+  c->max_table_elems = c->cap_table_elems;
+  c->max_usable_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
+  c->table_elem_size =
+      gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems);
+  memset(c->table_elem_size, 0,
+         sizeof(*c->table_elem_size) * c->cap_table_elems);
+}
+
+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]);
+  }
+  gpr_free(c->table_elem_size);
+}
+
+void grpc_chttp2_hpack_compressor_set_max_usable_size(
+    grpc_chttp2_hpack_compressor *c, uint32_t max_table_size) {
+  c->max_usable_size = max_table_size;
+  grpc_chttp2_hpack_compressor_set_max_table_size(
+      c, GPR_MIN(c->max_table_size, max_table_size));
+}
+
+static void rebuild_elems(grpc_chttp2_hpack_compressor *c, uint32_t new_cap) {
+  uint16_t *table_elem_size = gpr_malloc(sizeof(*table_elem_size) * new_cap);
+  uint32_t i;
+
+  memset(table_elem_size, 0, sizeof(*table_elem_size) * new_cap);
+  GPR_ASSERT(c->table_elems <= new_cap);
+
+  for (i = 0; i < c->table_elems; i++) {
+    uint32_t ofs = c->tail_remote_index + i + 1;
+    table_elem_size[ofs % new_cap] =
+        c->table_elem_size[ofs % c->cap_table_elems];
+  }
+
+  c->cap_table_elems = new_cap;
+  gpr_free(c->table_elem_size);
+  c->table_elem_size = table_elem_size;
+}
+
+void grpc_chttp2_hpack_compressor_set_max_table_size(
+    grpc_chttp2_hpack_compressor *c, uint32_t max_table_size) {
+  max_table_size = GPR_MIN(max_table_size, c->max_usable_size);
+  if (max_table_size == c->max_table_size) {
+    return;
+  }
+  while (c->table_size > 0 && c->table_size > max_table_size) {
+    evict_entry(c);
+  }
+  c->max_table_size = max_table_size;
+  c->max_table_elems = elems_for_bytes(max_table_size);
+  if (c->max_table_elems > c->cap_table_elems) {
+    rebuild_elems(c, GPR_MAX(c->max_table_elems, 2 * c->cap_table_elems));
+  } else if (c->max_table_elems < c->cap_table_elems / 3) {
+    uint32_t new_cap = GPR_MAX(c->max_table_elems, 16);
+    if (new_cap != c->cap_table_elems) {
+      rebuild_elems(c, new_cap);
+    }
+  }
+  c->advertise_table_size_change = 1;
+  gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size);
+}
+
+void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
+                               uint32_t stream_id,
+                               grpc_metadata_batch *metadata, int is_eof,
+                               gpr_slice_buffer *outbuf) {
+  framer_state st;
+  grpc_linked_mdelem *l;
+  gpr_timespec deadline;
+
+  GPR_ASSERT(stream_id != 0);
+
+  st.seen_regular_header = 0;
+  st.stream_id = stream_id;
+  st.output = outbuf;
+  st.is_first_frame = 1;
+
+  /* Encode a metadata batch; store the returned values, representing
+     a metadata element that needs to be unreffed back into the metadata
+     slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got
+     updated). After this loop, we'll do a batch unref of elements. */
+  begin_frame(&st);
+  if (c->advertise_table_size_change != 0) {
+    emit_advertise_table_size_change(c, &st);
+  }
+  grpc_metadata_batch_assert_ok(metadata);
+  for (l = metadata->list.head; l; l = l->next) {
+    hpack_enc(c, l->md, &st);
+  }
+  deadline = metadata->deadline;
+  if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) != 0) {
+    deadline_enc(c, deadline, &st);
+  }
+
+  finish_frame(&st, 1, is_eof);
+}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.h b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
new file mode 100644
index 0000000..d79de35
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
@@ -0,0 +1,95 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_ENCODER_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_ENCODER_H
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+#include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/lib/transport/metadata.h"
+#include "src/core/lib/transport/metadata_batch.h"
+
+#define GRPC_CHTTP2_HPACKC_NUM_FILTERS 256
+#define GRPC_CHTTP2_HPACKC_NUM_VALUES 256
+/* initial table size, per spec */
+#define GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE 4096
+/* maximum table size we'll actually use */
+#define GRPC_CHTTP2_HPACKC_MAX_TABLE_SIZE (1024 * 1024)
+
+typedef struct {
+  uint32_t filter_elems_sum;
+  uint32_t max_table_size;
+  uint32_t max_table_elems;
+  uint32_t cap_table_elems;
+  /** if non-zero, advertise to the decoder that we'll start using a table
+      of this size */
+  uint8_t advertise_table_size_change;
+  /** maximum number of bytes we'll use for the decode table (to guard against
+      peers ooming us by setting decode table size high) */
+  uint32_t max_usable_size;
+  /* one before the lowest usable table index */
+  uint32_t tail_remote_index;
+  uint32_t table_size;
+  uint32_t table_elems;
+
+  /* filter tables for elems: this tables provides an approximate
+     popularity count for particular hashes, and are used to determine whether
+     a new literal should be added to the compression table or not.
+     They track a single integer that counts how often a particular value has
+     been seen. When that count reaches max (255), all values are halved. */
+  uint8_t filter_elems[GRPC_CHTTP2_HPACKC_NUM_FILTERS];
+
+  /* entry tables for keys & elems: these tables track values that have been
+     seen and *may* be in the decompressor table */
+  grpc_mdstr *entries_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
+  grpc_mdelem *entries_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
+  uint32_t indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
+  uint32_t indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
+
+  uint16_t *table_elem_size;
+} grpc_chttp2_hpack_compressor;
+
+void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c);
+void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c);
+void grpc_chttp2_hpack_compressor_set_max_table_size(
+    grpc_chttp2_hpack_compressor *c, uint32_t max_table_size);
+void grpc_chttp2_hpack_compressor_set_max_usable_size(
+    grpc_chttp2_hpack_compressor *c, uint32_t max_table_size);
+
+void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, uint32_t id,
+                               grpc_metadata_batch *metadata, int is_eof,
+                               gpr_slice_buffer *outbuf);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_ENCODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c
new file mode 100644
index 0000000..ec3387e
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c
@@ -0,0 +1,1463 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+/* This is here for grpc_is_binary_header
+ * TODO(murgatroid99): Remove this
+ */
+#include <grpc/grpc.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/string.h"
+
+extern int grpc_http_trace;
+
+typedef enum {
+  NOT_BINARY,
+  B64_BYTE0,
+  B64_BYTE1,
+  B64_BYTE2,
+  B64_BYTE3
+} binary_state;
+
+/* How parsing works:
+
+   The parser object keeps track of a function pointer which represents the
+   current parse state.
+
+   Each time new bytes are presented, we call into the current state, which
+   recursively parses until all bytes in the given chunk are exhausted.
+
+   The parse state that terminates then saves its function pointer to be the
+   current state so that it can resume when more bytes are available.
+
+   It's expected that most optimizing compilers will turn this code into
+   a set of indirect jumps, and so not waste stack space. */
+
+/* forward declarations for parsing states */
+static int parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                       const uint8_t *end);
+static int parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                       const uint8_t *end);
+static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                            const uint8_t *end);
+
+static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                               const uint8_t *end);
+static int parse_key_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                            const uint8_t *end);
+static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p,
+                                               const uint8_t *cur,
+                                               const uint8_t *end);
+static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p,
+                                               const uint8_t *cur,
+                                               const uint8_t *end);
+
+static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                        const uint8_t *end);
+static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                        const uint8_t *end);
+static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                        const uint8_t *end);
+static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                        const uint8_t *end);
+static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                        const uint8_t *end);
+static int parse_value5up(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                          const uint8_t *end);
+
+static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                               const uint8_t *end);
+static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end);
+static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                               const uint8_t *end);
+static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end);
+static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end);
+static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                               const uint8_t *end);
+static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end);
+static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end);
+static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                               const uint8_t *end);
+static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end);
+static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end);
+static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                              const uint8_t *end);
+static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                                const uint8_t *end);
+
+/* we translate the first byte of a hpack field into one of these decoding
+   cases, then use a lookup table to jump directly to the appropriate parser.
+
+   _X => the integer index is all ones, meaning we need to do varint decoding
+   _V => the integer index is all zeros, meaning we need to decode an additional
+         string value */
+typedef enum {
+  INDEXED_FIELD,
+  INDEXED_FIELD_X,
+  LITHDR_INCIDX,
+  LITHDR_INCIDX_X,
+  LITHDR_INCIDX_V,
+  LITHDR_NOTIDX,
+  LITHDR_NOTIDX_X,
+  LITHDR_NOTIDX_V,
+  LITHDR_NVRIDX,
+  LITHDR_NVRIDX_X,
+  LITHDR_NVRIDX_V,
+  MAX_TBL_SIZE,
+  MAX_TBL_SIZE_X,
+  ILLEGAL
+} first_byte_type;
+
+/* 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_max_tbl_size_x,  parse_illegal_op};
+
+/* indexes the first byte to a parse state function - generated by
+   gen_hpack_tables.c */
+static const uint8_t first_byte_lut[256] = {
+    LITHDR_NOTIDX_V, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX,
+    LITHDR_NOTIDX,   LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX,
+    LITHDR_NOTIDX,   LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX,
+    LITHDR_NOTIDX,   LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX_X,
+    LITHDR_NVRIDX_V, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
+    LITHDR_NVRIDX,   LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
+    LITHDR_NVRIDX,   LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
+    LITHDR_NVRIDX,   LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX_X,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
+    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE_X,
+    LITHDR_INCIDX_V, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
+    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX_X,
+    ILLEGAL,         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,   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,   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,   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,   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,   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,   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,   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,
+};
+
+/* 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
+   considered returns the next state.
+
+   generated by gen_hpack_tables.c */
+static const uint8_t next_tbl[256] = {
+    0,  1,  2,  3,  4,  1,  2, 5,  6,  1, 7,  8,  1,  3,  3,  9,  10, 11, 1,  1,
+    1,  12, 1,  2,  13, 1,  1, 1,  1,  1, 1,  1,  1,  1,  1,  1,  1,  1,  1,  2,
+    14, 1,  15, 16, 1,  17, 1, 15, 2,  7, 3,  18, 19, 1,  1,  1,  1,  20, 1,  1,
+    1,  1,  1,  1,  1,  1,  1, 1,  15, 2, 2,  7,  21, 1,  22, 1,  1,  1,  1,  1,
+    1,  1,  1,  15, 2,  2,  2, 2,  2,  2, 23, 24, 25, 1,  1,  1,  1,  2,  2,  2,
+    26, 3,  3,  27, 10, 28, 1, 1,  1,  1, 1,  1,  2,  3,  29, 10, 30, 1,  1,  1,
+    1,  1,  1,  1,  1,  1,  1, 1,  1,  1, 1,  31, 1,  1,  1,  1,  1,  1,  1,  2,
+    2,  2,  2,  2,  2,  2,  2, 32, 1,  1, 15, 33, 1,  34, 35, 9,  36, 1,  1,  1,
+    1,  1,  1,  1,  37, 1,  1, 1,  1,  1, 1,  2,  2,  2,  2,  2,  2,  2,  26, 9,
+    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,
+};
+
+/* next state, based upon current state and the current nibble: see above.
+   generated by gen_hpack_tables.c */
+static const int16_t next_sub_tbl[48 * 16] = {
+    1,   204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217,
+    218, 2,   6,   10,  13,  14,  15,  16,  17,  2,   6,   10,  13,  14,  15,
+    16,  17,  3,   7,   11,  24,  3,   7,   11,  24,  3,   7,   11,  24,  3,
+    7,   11,  24,  4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,
+    4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   5,
+    199, 200, 201, 202, 203, 4,   8,   4,   8,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   9,   133, 134, 135, 136, 137, 138, 139, 140,
+    141, 142, 143, 144, 145, 146, 147, 3,   7,   11,  24,  3,   7,   11,  24,
+    4,   8,   4,   8,   4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   12,  132, 4,   8,   4,   8,   4,   8,
+    4,   8,   4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   18,  19,  20,  21,  4,   8,   4,
+    8,   4,   8,   4,   8,   4,   8,   0,   0,   0,   22,  23,  91,  25,  26,
+    27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  3,
+    7,   11,  24,  3,   7,   11,  24,  0,   0,   0,   0,   0,   41,  42,  43,
+    2,   6,   10,  13,  14,  15,  16,  17,  3,   7,   11,  24,  3,   7,   11,
+    24,  4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   0,   0,
+    44,  45,  2,   6,   10,  13,  14,  15,  16,  17,  46,  47,  48,  49,  50,
+    51,  52,  57,  4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   53,  54,  55,  56,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,
+    68,  69,  70,  71,  72,  74,  0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   73,  75,  76,  77,  78,  79,  80,  81,  82,
+    83,  84,  85,  86,  87,  88,  89,  90,  3,   7,   11,  24,  3,   7,   11,
+    24,  3,   7,   11,  24,  0,   0,   0,   0,   3,   7,   11,  24,  3,   7,
+    11,  24,  4,   8,   4,   8,   0,   0,   0,   92,  0,   0,   0,   93,  94,
+    95,  96,  97,  98,  99,  100, 101, 102, 103, 104, 105, 3,   7,   11,  24,
+    4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,
+    8,   4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 4,
+    8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   0,   0,
+    0,   117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
+    131, 2,   6,   10,  13,  14,  15,  16,  17,  4,   8,   4,   8,   4,   8,
+    4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   148,
+    149, 150, 151, 3,   7,   11,  24,  4,   8,   4,   8,   0,   0,   0,   0,
+    0,   0,   152, 153, 3,   7,   11,  24,  3,   7,   11,  24,  3,   7,   11,
+    24,  154, 155, 156, 164, 3,   7,   11,  24,  3,   7,   11,  24,  3,   7,
+    11,  24,  4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    157, 158, 159, 160, 161, 162, 163, 165, 166, 167, 168, 169, 170, 171, 172,
+    173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187,
+    188, 189, 190, 191, 192, 193, 194, 195, 196, 4,   8,   4,   8,   4,   8,
+    4,   8,   4,   8,   4,   8,   4,   8,   197, 198, 4,   8,   4,   8,   4,
+    8,   4,   8,   0,   0,   0,   0,   0,   0,   219, 220, 3,   7,   11,  24,
+    4,   8,   4,   8,   4,   8,   0,   0,   221, 222, 223, 224, 3,   7,   11,
+    24,  3,   7,   11,  24,  4,   8,   4,   8,   4,   8,   225, 228, 4,   8,
+    4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   226, 227, 229,
+    230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244,
+    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,
+};
+
+/* emission table: indexed like next_tbl, ultimately gives the byte to be
+   emitted, or -1 for no byte, or 256 for end of stream
+
+   generated by gen_hpack_tables.c */
+static const uint16_t emit_tbl[256] = {
+    0,   1,   2,   3,   4,   5,   6,   7,   0,   8,   9,   10,  11,  12,  13,
+    14,  15,  16,  17,  18,  19,  20,  21,  22,  0,   23,  24,  25,  26,  27,
+    28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,
+    43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  0,   55,  56,
+    57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  0,
+    71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,
+    86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99,  100,
+    101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
+    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
+    131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145,
+    146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 0,
+    160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
+    0,   175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
+    189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
+    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,
+};
+
+/* generated by gen_hpack_tables.c */
+static const int16_t emit_sub_tbl[249 * 16] = {
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+    -1,  48,  48,  48,  48,  48,  48,  48,  48,  49,  49,  49,  49,  49,  49,
+    49,  49,  48,  48,  48,  48,  49,  49,  49,  49,  50,  50,  50,  50,  97,
+    97,  97,  97,  48,  48,  49,  49,  50,  50,  97,  97,  99,  99,  101, 101,
+    105, 105, 111, 111, 48,  49,  50,  97,  99,  101, 105, 111, 115, 116, -1,
+    -1,  -1,  -1,  -1,  -1,  32,  32,  32,  32,  32,  32,  32,  32,  37,  37,
+    37,  37,  37,  37,  37,  37,  99,  99,  99,  99,  101, 101, 101, 101, 105,
+    105, 105, 105, 111, 111, 111, 111, 115, 115, 116, 116, 32,  37,  45,  46,
+    47,  51,  52,  53,  54,  55,  56,  57,  61,  61,  61,  61,  61,  61,  61,
+    61,  65,  65,  65,  65,  65,  65,  65,  65,  115, 115, 115, 115, 116, 116,
+    116, 116, 32,  32,  37,  37,  45,  45,  46,  46,  61,  65,  95,  98,  100,
+    102, 103, 104, 108, 109, 110, 112, 114, 117, -1,  -1,  58,  58,  58,  58,
+    58,  58,  58,  58,  66,  66,  66,  66,  66,  66,  66,  66,  47,  47,  51,
+    51,  52,  52,  53,  53,  54,  54,  55,  55,  56,  56,  57,  57,  61,  61,
+    65,  65,  95,  95,  98,  98,  100, 100, 102, 102, 103, 103, 104, 104, 108,
+    108, 109, 109, 110, 110, 112, 112, 114, 114, 117, 117, 58,  66,  67,  68,
+    69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,
+    84,  85,  86,  87,  89,  106, 107, 113, 118, 119, 120, 121, 122, -1,  -1,
+    -1,  -1,  38,  38,  38,  38,  38,  38,  38,  38,  42,  42,  42,  42,  42,
+    42,  42,  42,  44,  44,  44,  44,  44,  44,  44,  44,  59,  59,  59,  59,
+    59,  59,  59,  59,  88,  88,  88,  88,  88,  88,  88,  88,  90,  90,  90,
+    90,  90,  90,  90,  90,  33,  33,  34,  34,  40,  40,  41,  41,  63,  63,
+    39,  43,  124, -1,  -1,  -1,  35,  35,  35,  35,  35,  35,  35,  35,  62,
+    62,  62,  62,  62,  62,  62,  62,  0,   0,   0,   0,   36,  36,  36,  36,
+    64,  64,  64,  64,  91,  91,  91,  91,  69,  69,  69,  69,  69,  69,  69,
+    69,  70,  70,  70,  70,  70,  70,  70,  70,  71,  71,  71,  71,  71,  71,
+    71,  71,  72,  72,  72,  72,  72,  72,  72,  72,  73,  73,  73,  73,  73,
+    73,  73,  73,  74,  74,  74,  74,  74,  74,  74,  74,  75,  75,  75,  75,
+    75,  75,  75,  75,  76,  76,  76,  76,  76,  76,  76,  76,  77,  77,  77,
+    77,  77,  77,  77,  77,  78,  78,  78,  78,  78,  78,  78,  78,  79,  79,
+    79,  79,  79,  79,  79,  79,  80,  80,  80,  80,  80,  80,  80,  80,  81,
+    81,  81,  81,  81,  81,  81,  81,  82,  82,  82,  82,  82,  82,  82,  82,
+    83,  83,  83,  83,  83,  83,  83,  83,  84,  84,  84,  84,  84,  84,  84,
+    84,  85,  85,  85,  85,  85,  85,  85,  85,  86,  86,  86,  86,  86,  86,
+    86,  86,  87,  87,  87,  87,  87,  87,  87,  87,  89,  89,  89,  89,  89,
+    89,  89,  89,  106, 106, 106, 106, 106, 106, 106, 106, 107, 107, 107, 107,
+    107, 107, 107, 107, 113, 113, 113, 113, 113, 113, 113, 113, 118, 118, 118,
+    118, 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, 120, 120,
+    120, 120, 120, 120, 120, 120, 121, 121, 121, 121, 121, 121, 121, 121, 122,
+    122, 122, 122, 122, 122, 122, 122, 38,  38,  38,  38,  42,  42,  42,  42,
+    44,  44,  44,  44,  59,  59,  59,  59,  88,  88,  88,  88,  90,  90,  90,
+    90,  33,  34,  40,  41,  63,  -1,  -1,  -1,  39,  39,  39,  39,  39,  39,
+    39,  39,  43,  43,  43,  43,  43,  43,  43,  43,  124, 124, 124, 124, 124,
+    124, 124, 124, 35,  35,  35,  35,  62,  62,  62,  62,  0,   0,   36,  36,
+    64,  64,  91,  91,  93,  93,  126, 126, 94,  125, -1,  -1,  60,  60,  60,
+    60,  60,  60,  60,  60,  96,  96,  96,  96,  96,  96,  96,  96,  123, 123,
+    123, 123, 123, 123, 123, 123, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  92,
+    92,  92,  92,  92,  92,  92,  92,  195, 195, 195, 195, 195, 195, 195, 195,
+    208, 208, 208, 208, 208, 208, 208, 208, 128, 128, 128, 128, 130, 130, 130,
+    130, 131, 131, 131, 131, 162, 162, 162, 162, 184, 184, 184, 184, 194, 194,
+    194, 194, 224, 224, 224, 224, 226, 226, 226, 226, 153, 153, 161, 161, 167,
+    167, 172, 172, 176, 176, 177, 177, 179, 179, 209, 209, 216, 216, 217, 217,
+    227, 227, 229, 229, 230, 230, 129, 132, 133, 134, 136, 146, 154, 156, 160,
+    163, 164, 169, 170, 173, 178, 181, 185, 186, 187, 189, 190, 196, 198, 228,
+    232, 233, -1,  -1,  -1,  -1,  1,   1,   1,   1,   1,   1,   1,   1,   135,
+    135, 135, 135, 135, 135, 135, 135, 137, 137, 137, 137, 137, 137, 137, 137,
+    138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139, 139, 139, 139,
+    139, 140, 140, 140, 140, 140, 140, 140, 140, 141, 141, 141, 141, 141, 141,
+    141, 141, 143, 143, 143, 143, 143, 143, 143, 143, 147, 147, 147, 147, 147,
+    147, 147, 147, 149, 149, 149, 149, 149, 149, 149, 149, 150, 150, 150, 150,
+    150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 151, 151, 152, 152, 152,
+    152, 152, 152, 152, 152, 155, 155, 155, 155, 155, 155, 155, 155, 157, 157,
+    157, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158, 158, 158, 158, 165,
+    165, 165, 165, 165, 165, 165, 165, 166, 166, 166, 166, 166, 166, 166, 166,
+    168, 168, 168, 168, 168, 168, 168, 168, 174, 174, 174, 174, 174, 174, 174,
+    174, 175, 175, 175, 175, 175, 175, 175, 175, 180, 180, 180, 180, 180, 180,
+    180, 180, 182, 182, 182, 182, 182, 182, 182, 182, 183, 183, 183, 183, 183,
+    183, 183, 183, 188, 188, 188, 188, 188, 188, 188, 188, 191, 191, 191, 191,
+    191, 191, 191, 191, 197, 197, 197, 197, 197, 197, 197, 197, 231, 231, 231,
+    231, 231, 231, 231, 231, 239, 239, 239, 239, 239, 239, 239, 239, 9,   9,
+    9,   9,   142, 142, 142, 142, 144, 144, 144, 144, 145, 145, 145, 145, 148,
+    148, 148, 148, 159, 159, 159, 159, 171, 171, 171, 171, 206, 206, 206, 206,
+    215, 215, 215, 215, 225, 225, 225, 225, 236, 236, 236, 236, 237, 237, 237,
+    237, 199, 199, 207, 207, 234, 234, 235, 235, 192, 193, 200, 201, 202, 205,
+    210, 213, 218, 219, 238, 240, 242, 243, 255, -1,  203, 203, 203, 203, 203,
+    203, 203, 203, 204, 204, 204, 204, 204, 204, 204, 204, 211, 211, 211, 211,
+    211, 211, 211, 211, 212, 212, 212, 212, 212, 212, 212, 212, 214, 214, 214,
+    214, 214, 214, 214, 214, 221, 221, 221, 221, 221, 221, 221, 221, 222, 222,
+    222, 222, 222, 222, 222, 222, 223, 223, 223, 223, 223, 223, 223, 223, 241,
+    241, 241, 241, 241, 241, 241, 241, 244, 244, 244, 244, 244, 244, 244, 244,
+    245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246,
+    246, 247, 247, 247, 247, 247, 247, 247, 247, 248, 248, 248, 248, 248, 248,
+    248, 248, 250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251,
+    251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253,
+    253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 2,   2,   2,
+    2,   3,   3,   3,   3,   4,   4,   4,   4,   5,   5,   5,   5,   6,   6,
+    6,   6,   7,   7,   7,   7,   8,   8,   8,   8,   11,  11,  11,  11,  12,
+    12,  12,  12,  14,  14,  14,  14,  15,  15,  15,  15,  16,  16,  16,  16,
+    17,  17,  17,  17,  18,  18,  18,  18,  19,  19,  19,  19,  20,  20,  20,
+    20,  21,  21,  21,  21,  23,  23,  23,  23,  24,  24,  24,  24,  25,  25,
+    25,  25,  26,  26,  26,  26,  27,  27,  27,  27,  28,  28,  28,  28,  29,
+    29,  29,  29,  30,  30,  30,  30,  31,  31,  31,  31,  127, 127, 127, 127,
+    220, 220, 220, 220, 249, 249, 249, 249, 10,  13,  22,  256, 93,  93,  93,
+    93,  126, 126, 126, 126, 94,  94,  125, 125, 60,  96,  123, -1,  92,  195,
+    208, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  128,
+    128, 128, 128, 128, 128, 128, 128, 130, 130, 130, 130, 130, 130, 130, 130,
+    131, 131, 131, 131, 131, 131, 131, 131, 162, 162, 162, 162, 162, 162, 162,
+    162, 184, 184, 184, 184, 184, 184, 184, 184, 194, 194, 194, 194, 194, 194,
+    194, 194, 224, 224, 224, 224, 224, 224, 224, 224, 226, 226, 226, 226, 226,
+    226, 226, 226, 153, 153, 153, 153, 161, 161, 161, 161, 167, 167, 167, 167,
+    172, 172, 172, 172, 176, 176, 176, 176, 177, 177, 177, 177, 179, 179, 179,
+    179, 209, 209, 209, 209, 216, 216, 216, 216, 217, 217, 217, 217, 227, 227,
+    227, 227, 229, 229, 229, 229, 230, 230, 230, 230, 129, 129, 132, 132, 133,
+    133, 134, 134, 136, 136, 146, 146, 154, 154, 156, 156, 160, 160, 163, 163,
+    164, 164, 169, 169, 170, 170, 173, 173, 178, 178, 181, 181, 185, 185, 186,
+    186, 187, 187, 189, 189, 190, 190, 196, 196, 198, 198, 228, 228, 232, 232,
+    233, 233, 1,   135, 137, 138, 139, 140, 141, 143, 147, 149, 150, 151, 152,
+    155, 157, 158, 165, 166, 168, 174, 175, 180, 182, 183, 188, 191, 197, 231,
+    239, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  9,   9,   9,
+    9,   9,   9,   9,   9,   142, 142, 142, 142, 142, 142, 142, 142, 144, 144,
+    144, 144, 144, 144, 144, 144, 145, 145, 145, 145, 145, 145, 145, 145, 148,
+    148, 148, 148, 148, 148, 148, 148, 159, 159, 159, 159, 159, 159, 159, 159,
+    171, 171, 171, 171, 171, 171, 171, 171, 206, 206, 206, 206, 206, 206, 206,
+    206, 215, 215, 215, 215, 215, 215, 215, 215, 225, 225, 225, 225, 225, 225,
+    225, 225, 236, 236, 236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 237,
+    237, 237, 237, 199, 199, 199, 199, 207, 207, 207, 207, 234, 234, 234, 234,
+    235, 235, 235, 235, 192, 192, 193, 193, 200, 200, 201, 201, 202, 202, 205,
+    205, 210, 210, 213, 213, 218, 218, 219, 219, 238, 238, 240, 240, 242, 242,
+    243, 243, 255, 255, 203, 204, 211, 212, 214, 221, 222, 223, 241, 244, 245,
+    246, 247, 248, 250, 251, 252, 253, 254, -1,  -1,  -1,  -1,  -1,  -1,  -1,
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  2,   2,   2,   2,   2,   2,   2,
+    2,   3,   3,   3,   3,   3,   3,   3,   3,   4,   4,   4,   4,   4,   4,
+    4,   4,   5,   5,   5,   5,   5,   5,   5,   5,   6,   6,   6,   6,   6,
+    6,   6,   6,   7,   7,   7,   7,   7,   7,   7,   7,   8,   8,   8,   8,
+    8,   8,   8,   8,   11,  11,  11,  11,  11,  11,  11,  11,  12,  12,  12,
+    12,  12,  12,  12,  12,  14,  14,  14,  14,  14,  14,  14,  14,  15,  15,
+    15,  15,  15,  15,  15,  15,  16,  16,  16,  16,  16,  16,  16,  16,  17,
+    17,  17,  17,  17,  17,  17,  17,  18,  18,  18,  18,  18,  18,  18,  18,
+    19,  19,  19,  19,  19,  19,  19,  19,  20,  20,  20,  20,  20,  20,  20,
+    20,  21,  21,  21,  21,  21,  21,  21,  21,  23,  23,  23,  23,  23,  23,
+    23,  23,  24,  24,  24,  24,  24,  24,  24,  24,  25,  25,  25,  25,  25,
+    25,  25,  25,  26,  26,  26,  26,  26,  26,  26,  26,  27,  27,  27,  27,
+    27,  27,  27,  27,  28,  28,  28,  28,  28,  28,  28,  28,  29,  29,  29,
+    29,  29,  29,  29,  29,  30,  30,  30,  30,  30,  30,  30,  30,  31,  31,
+    31,  31,  31,  31,  31,  31,  127, 127, 127, 127, 127, 127, 127, 127, 220,
+    220, 220, 220, 220, 220, 220, 220, 249, 249, 249, 249, 249, 249, 249, 249,
+    10,  10,  13,  13,  22,  22,  256, 256, 67,  67,  67,  67,  67,  67,  67,
+    67,  68,  68,  68,  68,  68,  68,  68,  68,  95,  95,  95,  95,  95,  95,
+    95,  95,  98,  98,  98,  98,  98,  98,  98,  98,  100, 100, 100, 100, 100,
+    100, 100, 100, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103,
+    103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 108, 108, 108,
+    108, 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, 109, 109, 110, 110,
+    110, 110, 110, 110, 110, 110, 112, 112, 112, 112, 112, 112, 112, 112, 114,
+    114, 114, 114, 114, 114, 114, 114, 117, 117, 117, 117, 117, 117, 117, 117,
+    58,  58,  58,  58,  66,  66,  66,  66,  67,  67,  67,  67,  68,  68,  68,
+    68,  69,  69,  69,  69,  70,  70,  70,  70,  71,  71,  71,  71,  72,  72,
+    72,  72,  73,  73,  73,  73,  74,  74,  74,  74,  75,  75,  75,  75,  76,
+    76,  76,  76,  77,  77,  77,  77,  78,  78,  78,  78,  79,  79,  79,  79,
+    80,  80,  80,  80,  81,  81,  81,  81,  82,  82,  82,  82,  83,  83,  83,
+    83,  84,  84,  84,  84,  85,  85,  85,  85,  86,  86,  86,  86,  87,  87,
+    87,  87,  89,  89,  89,  89,  106, 106, 106, 106, 107, 107, 107, 107, 113,
+    113, 113, 113, 118, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 120,
+    121, 121, 121, 121, 122, 122, 122, 122, 38,  38,  42,  42,  44,  44,  59,
+    59,  88,  88,  90,  90,  -1,  -1,  -1,  -1,  33,  33,  33,  33,  33,  33,
+    33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  40,  40,  40,  40,  40,
+    40,  40,  40,  41,  41,  41,  41,  41,  41,  41,  41,  63,  63,  63,  63,
+    63,  63,  63,  63,  39,  39,  39,  39,  43,  43,  43,  43,  124, 124, 124,
+    124, 35,  35,  62,  62,  0,   36,  64,  91,  93,  126, -1,  -1,  94,  94,
+    94,  94,  94,  94,  94,  94,  125, 125, 125, 125, 125, 125, 125, 125, 60,
+    60,  60,  60,  96,  96,  96,  96,  123, 123, 123, 123, -1,  -1,  -1,  -1,
+    92,  92,  92,  92,  195, 195, 195, 195, 208, 208, 208, 208, 128, 128, 130,
+    130, 131, 131, 162, 162, 184, 184, 194, 194, 224, 224, 226, 226, 153, 161,
+    167, 172, 176, 177, 179, 209, 216, 217, 227, 229, 230, -1,  -1,  -1,  -1,
+    -1,  -1,  -1,  129, 129, 129, 129, 129, 129, 129, 129, 132, 132, 132, 132,
+    132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, 134, 134, 134,
+    134, 134, 134, 134, 134, 136, 136, 136, 136, 136, 136, 136, 136, 146, 146,
+    146, 146, 146, 146, 146, 146, 154, 154, 154, 154, 154, 154, 154, 154, 156,
+    156, 156, 156, 156, 156, 156, 156, 160, 160, 160, 160, 160, 160, 160, 160,
+    163, 163, 163, 163, 163, 163, 163, 163, 164, 164, 164, 164, 164, 164, 164,
+    164, 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170,
+    170, 170, 173, 173, 173, 173, 173, 173, 173, 173, 178, 178, 178, 178, 178,
+    178, 178, 178, 181, 181, 181, 181, 181, 181, 181, 181, 185, 185, 185, 185,
+    185, 185, 185, 185, 186, 186, 186, 186, 186, 186, 186, 186, 187, 187, 187,
+    187, 187, 187, 187, 187, 189, 189, 189, 189, 189, 189, 189, 189, 190, 190,
+    190, 190, 190, 190, 190, 190, 196, 196, 196, 196, 196, 196, 196, 196, 198,
+    198, 198, 198, 198, 198, 198, 198, 228, 228, 228, 228, 228, 228, 228, 228,
+    232, 232, 232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 233, 233, 233,
+    233, 1,   1,   1,   1,   135, 135, 135, 135, 137, 137, 137, 137, 138, 138,
+    138, 138, 139, 139, 139, 139, 140, 140, 140, 140, 141, 141, 141, 141, 143,
+    143, 143, 143, 147, 147, 147, 147, 149, 149, 149, 149, 150, 150, 150, 150,
+    151, 151, 151, 151, 152, 152, 152, 152, 155, 155, 155, 155, 157, 157, 157,
+    157, 158, 158, 158, 158, 165, 165, 165, 165, 166, 166, 166, 166, 168, 168,
+    168, 168, 174, 174, 174, 174, 175, 175, 175, 175, 180, 180, 180, 180, 182,
+    182, 182, 182, 183, 183, 183, 183, 188, 188, 188, 188, 191, 191, 191, 191,
+    197, 197, 197, 197, 231, 231, 231, 231, 239, 239, 239, 239, 9,   9,   142,
+    142, 144, 144, 145, 145, 148, 148, 159, 159, 171, 171, 206, 206, 215, 215,
+    225, 225, 236, 236, 237, 237, 199, 207, 234, 235, 192, 192, 192, 192, 192,
+    192, 192, 192, 193, 193, 193, 193, 193, 193, 193, 193, 200, 200, 200, 200,
+    200, 200, 200, 200, 201, 201, 201, 201, 201, 201, 201, 201, 202, 202, 202,
+    202, 202, 202, 202, 202, 205, 205, 205, 205, 205, 205, 205, 205, 210, 210,
+    210, 210, 210, 210, 210, 210, 213, 213, 213, 213, 213, 213, 213, 213, 218,
+    218, 218, 218, 218, 218, 218, 218, 219, 219, 219, 219, 219, 219, 219, 219,
+    238, 238, 238, 238, 238, 238, 238, 238, 240, 240, 240, 240, 240, 240, 240,
+    240, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243, 243, 243,
+    243, 243, 255, 255, 255, 255, 255, 255, 255, 255, 203, 203, 203, 203, 204,
+    204, 204, 204, 211, 211, 211, 211, 212, 212, 212, 212, 214, 214, 214, 214,
+    221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 241, 241, 241,
+    241, 244, 244, 244, 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, 247,
+    247, 247, 248, 248, 248, 248, 250, 250, 250, 250, 251, 251, 251, 251, 252,
+    252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 2,   2,   3,   3,
+    4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   11,  11,  12,  12,  14,
+    14,  15,  15,  16,  16,  17,  17,  18,  18,  19,  19,  20,  20,  21,  21,
+    23,  23,  24,  24,  25,  25,  26,  26,  27,  27,  28,  28,  29,  29,  30,
+    30,  31,  31,  127, 127, 220, 220, 249, 249, -1,  -1,  10,  10,  10,  10,
+    10,  10,  10,  10,  13,  13,  13,  13,  13,  13,  13,  13,  22,  22,  22,
+    22,  22,  22,  22,  22,  256, 256, 256, 256, 256, 256, 256, 256, 45,  45,
+    45,  45,  45,  45,  45,  45,  46,  46,  46,  46,  46,  46,  46,  46,  47,
+    47,  47,  47,  47,  47,  47,  47,  51,  51,  51,  51,  51,  51,  51,  51,
+    52,  52,  52,  52,  52,  52,  52,  52,  53,  53,  53,  53,  53,  53,  53,
+    53,  54,  54,  54,  54,  54,  54,  54,  54,  55,  55,  55,  55,  55,  55,
+    55,  55,  56,  56,  56,  56,  56,  56,  56,  56,  57,  57,  57,  57,  57,
+    57,  57,  57,  50,  50,  50,  50,  50,  50,  50,  50,  97,  97,  97,  97,
+    97,  97,  97,  97,  99,  99,  99,  99,  99,  99,  99,  99,  101, 101, 101,
+    101, 101, 101, 101, 101, 105, 105, 105, 105, 105, 105, 105, 105, 111, 111,
+    111, 111, 111, 111, 111, 111, 115, 115, 115, 115, 115, 115, 115, 115, 116,
+    116, 116, 116, 116, 116, 116, 116, 32,  32,  32,  32,  37,  37,  37,  37,
+    45,  45,  45,  45,  46,  46,  46,  46,  47,  47,  47,  47,  51,  51,  51,
+    51,  52,  52,  52,  52,  53,  53,  53,  53,  54,  54,  54,  54,  55,  55,
+    55,  55,  56,  56,  56,  56,  57,  57,  57,  57,  61,  61,  61,  61,  65,
+    65,  65,  65,  95,  95,  95,  95,  98,  98,  98,  98,  100, 100, 100, 100,
+    102, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 104, 108, 108, 108,
+    108, 109, 109, 109, 109, 110, 110, 110, 110, 112, 112, 112, 112, 114, 114,
+    114, 114, 117, 117, 117, 117, 58,  58,  66,  66,  67,  67,  68,  68,  69,
+    69,  70,  70,  71,  71,  72,  72,  73,  73,  74,  74,  75,  75,  76,  76,
+    77,  77,  78,  78,  79,  79,  80,  80,  81,  81,  82,  82,  83,  83,  84,
+    84,  85,  85,  86,  86,  87,  87,  89,  89,  106, 106, 107, 107, 113, 113,
+    118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 38,  42,  44,  59,  88,
+    90,  -1,  -1,  33,  33,  33,  33,  34,  34,  34,  34,  40,  40,  40,  40,
+    41,  41,  41,  41,  63,  63,  63,  63,  39,  39,  43,  43,  124, 124, 35,
+    62,  -1,  -1,  -1,  -1,  0,   0,   0,   0,   0,   0,   0,   0,   36,  36,
+    36,  36,  36,  36,  36,  36,  64,  64,  64,  64,  64,  64,  64,  64,  91,
+    91,  91,  91,  91,  91,  91,  91,  93,  93,  93,  93,  93,  93,  93,  93,
+    126, 126, 126, 126, 126, 126, 126, 126, 94,  94,  94,  94,  125, 125, 125,
+    125, 60,  60,  96,  96,  123, 123, -1,  -1,  92,  92,  195, 195, 208, 208,
+    128, 130, 131, 162, 184, 194, 224, 226, -1,  -1,  153, 153, 153, 153, 153,
+    153, 153, 153, 161, 161, 161, 161, 161, 161, 161, 161, 167, 167, 167, 167,
+    167, 167, 167, 167, 172, 172, 172, 172, 172, 172, 172, 172, 176, 176, 176,
+    176, 176, 176, 176, 176, 177, 177, 177, 177, 177, 177, 177, 177, 179, 179,
+    179, 179, 179, 179, 179, 179, 209, 209, 209, 209, 209, 209, 209, 209, 216,
+    216, 216, 216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217, 217, 217,
+    227, 227, 227, 227, 227, 227, 227, 227, 229, 229, 229, 229, 229, 229, 229,
+    229, 230, 230, 230, 230, 230, 230, 230, 230, 129, 129, 129, 129, 132, 132,
+    132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 136, 136, 136, 136, 146,
+    146, 146, 146, 154, 154, 154, 154, 156, 156, 156, 156, 160, 160, 160, 160,
+    163, 163, 163, 163, 164, 164, 164, 164, 169, 169, 169, 169, 170, 170, 170,
+    170, 173, 173, 173, 173, 178, 178, 178, 178, 181, 181, 181, 181, 185, 185,
+    185, 185, 186, 186, 186, 186, 187, 187, 187, 187, 189, 189, 189, 189, 190,
+    190, 190, 190, 196, 196, 196, 196, 198, 198, 198, 198, 228, 228, 228, 228,
+    232, 232, 232, 232, 233, 233, 233, 233, 1,   1,   135, 135, 137, 137, 138,
+    138, 139, 139, 140, 140, 141, 141, 143, 143, 147, 147, 149, 149, 150, 150,
+    151, 151, 152, 152, 155, 155, 157, 157, 158, 158, 165, 165, 166, 166, 168,
+    168, 174, 174, 175, 175, 180, 180, 182, 182, 183, 183, 188, 188, 191, 191,
+    197, 197, 231, 231, 239, 239, 9,   142, 144, 145, 148, 159, 171, 206, 215,
+    225, 236, 237, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  199, 199,
+    199, 199, 199, 199, 199, 199, 207, 207, 207, 207, 207, 207, 207, 207, 234,
+    234, 234, 234, 234, 234, 234, 234, 235, 235, 235, 235, 235, 235, 235, 235,
+    192, 192, 192, 192, 193, 193, 193, 193, 200, 200, 200, 200, 201, 201, 201,
+    201, 202, 202, 202, 202, 205, 205, 205, 205, 210, 210, 210, 210, 213, 213,
+    213, 213, 218, 218, 218, 218, 219, 219, 219, 219, 238, 238, 238, 238, 240,
+    240, 240, 240, 242, 242, 242, 242, 243, 243, 243, 243, 255, 255, 255, 255,
+    203, 203, 204, 204, 211, 211, 212, 212, 214, 214, 221, 221, 222, 222, 223,
+    223, 241, 241, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 250, 250,
+    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,
+};
+
+static const uint8_t inverse_base64[256] = {
+    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, 62,  255,
+    255, 255, 63,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  255, 255,
+    255, 64,  255, 255, 255, 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
+    10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
+    25,  255, 255, 255, 255, 255, 255, 26,  27,  28,  29,  30,  31,  32,  33,
+    34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
+    49,  50,  51,  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, 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, 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 int on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
+                  int add_to_table) {
+  if (add_to_table) {
+    if (!grpc_chttp2_hptbl_add(&p->table, md)) {
+      return 0;
+    }
+  }
+  p->on_header(p->on_header_user_data, md);
+  return 1;
+}
+
+static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
+                               grpc_chttp2_hpack_parser_string *str) {
+  grpc_mdstr *s = grpc_mdstr_from_buffer((uint8_t *)str->str, str->length);
+  str->length = 0;
+  return s;
+}
+
+/* jump to the next state */
+static int parse_next(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                      const uint8_t *end) {
+  p->state = *p->next_state++;
+  return p->state(p, cur, end);
+}
+
+/* begin parsing a header: all functionality is encoded into lookup tables
+   above */
+static int parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                       const uint8_t *end) {
+  if (cur == end) {
+    p->state = parse_begin;
+    return 1;
+  }
+
+  return first_byte_action[first_byte_lut[*cur]](p, cur, end);
+}
+
+/* stream dependency and prioritization data: we just skip it */
+static int parse_stream_weight(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                               const uint8_t *end) {
+  if (cur == end) {
+    p->state = parse_stream_weight;
+    return 1;
+  }
+
+  return p->after_prioritization(p, cur + 1, end);
+}
+
+static int parse_stream_dep3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                             const uint8_t *end) {
+  if (cur == end) {
+    p->state = parse_stream_dep3;
+    return 1;
+  }
+
+  return parse_stream_weight(p, cur + 1, end);
+}
+
+static int parse_stream_dep2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                             const uint8_t *end) {
+  if (cur == end) {
+    p->state = parse_stream_dep2;
+    return 1;
+  }
+
+  return parse_stream_dep3(p, cur + 1, end);
+}
+
+static int parse_stream_dep1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                             const uint8_t *end) {
+  if (cur == end) {
+    p->state = parse_stream_dep1;
+    return 1;
+  }
+
+  return parse_stream_dep2(p, cur + 1, end);
+}
+
+static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                             const uint8_t *end) {
+  if (cur == end) {
+    p->state = parse_stream_dep0;
+    return 1;
+  }
+
+  return parse_stream_dep1(p, cur + 1, end);
+}
+
+/* emit an indexed field; for now just logs it to console; jumps to
+   begin the next field on completion */
+static int finish_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                                const uint8_t *end) {
+  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+  if (md == NULL) {
+    if (grpc_http_trace) {
+      gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
+    }
+    return 0;
+  }
+  GRPC_MDELEM_REF(md);
+  return on_hdr(p, md, 0) && parse_begin(p, cur, end);
+}
+
+/* parse an indexed field with index < 127 */
+static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                               const uint8_t *end) {
+  p->dynamic_table_update_allowed = 0;
+  p->index = (*cur) & 0x7f;
+  return finish_indexed_field(p, cur + 1, end);
+}
+
+/* parse an indexed field with index >= 127 */
+static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      finish_indexed_field};
+  p->dynamic_table_update_allowed = 0;
+  p->next_state = and_then;
+  p->index = 0x7f;
+  p->parsing.value = &p->index;
+  return parse_value0(p, cur + 1, end);
+}
+
+/* finish a literal header with incremental indexing: just log, and jump to '
+   begin */
+static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                                const uint8_t *end) {
+  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+  GPR_ASSERT(md != NULL); /* handled in string parsing */
+  return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+                                                     take_string(p, &p->value)),
+                1) &&
+         parse_begin(p, cur, end);
+}
+
+/* finish a literal header with incremental indexing with no index */
+static int finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+                                  const uint8_t *cur, const uint8_t *end) {
+  return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+                                                     take_string(p, &p->value)),
+                1) &&
+         parse_begin(p, cur, end);
+}
+
+/* parse a literal header with incremental indexing; index < 63 */
+static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                               const uint8_t *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_value_string_with_indexed_key, finish_lithdr_incidx};
+  p->dynamic_table_update_allowed = 0;
+  p->next_state = and_then;
+  p->index = (*cur) & 0x3f;
+  return parse_string_prefix(p, cur + 1, end);
+}
+
+/* parse a literal header with incremental indexing; index >= 63 */
+static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_string_prefix, parse_value_string_with_indexed_key,
+      finish_lithdr_incidx};
+  p->dynamic_table_update_allowed = 0;
+  p->next_state = and_then;
+  p->index = 0x3f;
+  p->parsing.value = &p->index;
+  return parse_value0(p, cur + 1, end);
+}
+
+/* parse a literal header with incremental indexing; index = 0 */
+static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_key_string, parse_string_prefix,
+      parse_value_string_with_literal_key, finish_lithdr_incidx_v};
+  p->dynamic_table_update_allowed = 0;
+  p->next_state = and_then;
+  return parse_string_prefix(p, cur + 1, end);
+}
+
+/* finish a literal header without incremental indexing */
+static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                                const uint8_t *end) {
+  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+  GPR_ASSERT(md != NULL); /* handled in string parsing */
+  return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+                                                     take_string(p, &p->value)),
+                0) &&
+         parse_begin(p, cur, end);
+}
+
+/* finish a literal header without incremental indexing with index = 0 */
+static int finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+                                  const uint8_t *cur, const uint8_t *end) {
+  return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+                                                     take_string(p, &p->value)),
+                0) &&
+         parse_begin(p, cur, end);
+}
+
+/* parse a literal header without incremental indexing; index < 15 */
+static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                               const uint8_t *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_value_string_with_indexed_key, finish_lithdr_notidx};
+  p->dynamic_table_update_allowed = 0;
+  p->next_state = and_then;
+  p->index = (*cur) & 0xf;
+  return parse_string_prefix(p, cur + 1, end);
+}
+
+/* parse a literal header without incremental indexing; index >= 15 */
+static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_string_prefix, parse_value_string_with_indexed_key,
+      finish_lithdr_notidx};
+  p->dynamic_table_update_allowed = 0;
+  p->next_state = and_then;
+  p->index = 0xf;
+  p->parsing.value = &p->index;
+  return parse_value0(p, cur + 1, end);
+}
+
+/* parse a literal header without incremental indexing; index == 0 */
+static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_key_string, parse_string_prefix,
+      parse_value_string_with_literal_key, finish_lithdr_notidx_v};
+  p->dynamic_table_update_allowed = 0;
+  p->next_state = and_then;
+  return parse_string_prefix(p, cur + 1, end);
+}
+
+/* finish a literal header that is never indexed */
+static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                                const uint8_t *end) {
+  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+  GPR_ASSERT(md != NULL); /* handled in string parsing */
+  return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+                                                     take_string(p, &p->value)),
+                0) &&
+         parse_begin(p, cur, end);
+}
+
+/* finish a literal header that is never indexed with an extra value */
+static int finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+                                  const uint8_t *cur, const uint8_t *end) {
+  return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+                                                     take_string(p, &p->value)),
+                0) &&
+         parse_begin(p, cur, end);
+}
+
+/* parse a literal header that is never indexed; index < 15 */
+static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                               const uint8_t *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_value_string_with_indexed_key, finish_lithdr_nvridx};
+  p->dynamic_table_update_allowed = 0;
+  p->next_state = and_then;
+  p->index = (*cur) & 0xf;
+  return parse_string_prefix(p, cur + 1, end);
+}
+
+/* parse a literal header that is never indexed; index >= 15 */
+static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_string_prefix, parse_value_string_with_indexed_key,
+      finish_lithdr_nvridx};
+  p->dynamic_table_update_allowed = 0;
+  p->next_state = and_then;
+  p->index = 0xf;
+  p->parsing.value = &p->index;
+  return parse_value0(p, cur + 1, end);
+}
+
+/* parse a literal header that is never indexed; index == 0 */
+static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+                                 const uint8_t *cur, const uint8_t *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      parse_key_string, parse_string_prefix,
+      parse_value_string_with_literal_key, finish_lithdr_nvridx_v};
+  p->dynamic_table_update_allowed = 0;
+  p->next_state = and_then;
+  return parse_string_prefix(p, cur + 1, end);
+}
+
+/* finish parsing a max table size change */
+static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                               const uint8_t *end) {
+  if (grpc_http_trace) {
+    gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
+  }
+  return grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index) &&
+         parse_begin(p, cur, end);
+}
+
+/* parse a max table size change, max size < 15 */
+static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                              const uint8_t *end) {
+  if (p->dynamic_table_update_allowed == 0) {
+    return 0;
+  }
+  p->dynamic_table_update_allowed--;
+  p->index = (*cur) & 0x1f;
+  return finish_max_tbl_size(p, cur + 1, end);
+}
+
+/* parse a max table size change, max size >= 15 */
+static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                                const uint8_t *end) {
+  static const grpc_chttp2_hpack_parser_state and_then[] = {
+      finish_max_tbl_size};
+  if (p->dynamic_table_update_allowed == 0) {
+    return 0;
+  }
+  p->dynamic_table_update_allowed--;
+  p->next_state = and_then;
+  p->index = 0x1f;
+  p->parsing.value = &p->index;
+  return parse_value0(p, cur + 1, end);
+}
+
+/* a parse error: jam the parse state into parse_error, and return error */
+static int parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                       const uint8_t *end) {
+  p->state = parse_error;
+  return 0;
+}
+
+static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                            const uint8_t *end) {
+  GPR_ASSERT(cur != end);
+  if (grpc_http_trace) {
+    gpr_log(GPR_DEBUG, "Illegal hpack op code %d", *cur);
+  }
+  return parse_error(p, cur, end);
+}
+
+/* parse the 1st byte of a varint into p->parsing.value
+   no overflow is possible */
+static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                        const uint8_t *end) {
+  if (cur == end) {
+    p->state = parse_value0;
+    return 1;
+  }
+
+  *p->parsing.value += (*cur) & 0x7f;
+
+  if ((*cur) & 0x80) {
+    return parse_value1(p, cur + 1, end);
+  } else {
+    return parse_next(p, cur + 1, end);
+  }
+}
+
+/* parse the 2nd byte of a varint into p->parsing.value
+   no overflow is possible */
+static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                        const uint8_t *end) {
+  if (cur == end) {
+    p->state = parse_value1;
+    return 1;
+  }
+
+  *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 7;
+
+  if ((*cur) & 0x80) {
+    return parse_value2(p, cur + 1, end);
+  } else {
+    return parse_next(p, cur + 1, end);
+  }
+}
+
+/* parse the 3rd byte of a varint into p->parsing.value
+   no overflow is possible */
+static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                        const uint8_t *end) {
+  if (cur == end) {
+    p->state = parse_value2;
+    return 1;
+  }
+
+  *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 14;
+
+  if ((*cur) & 0x80) {
+    return parse_value3(p, cur + 1, end);
+  } else {
+    return parse_next(p, cur + 1, end);
+  }
+}
+
+/* parse the 4th byte of a varint into p->parsing.value
+   no overflow is possible */
+static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                        const uint8_t *end) {
+  if (cur == end) {
+    p->state = parse_value3;
+    return 1;
+  }
+
+  *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 21;
+
+  if ((*cur) & 0x80) {
+    return parse_value4(p, cur + 1, end);
+  } else {
+    return parse_next(p, cur + 1, end);
+  }
+}
+
+/* parse the 5th byte of a varint into p->parsing.value
+   depending on the byte, we may overflow, and care must be taken */
+static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                        const uint8_t *end) {
+  uint8_t c;
+  uint32_t cur_value;
+  uint32_t add_value;
+
+  if (cur == end) {
+    p->state = parse_value4;
+    return 1;
+  }
+
+  c = (*cur) & 0x7f;
+  if (c > 0xf) {
+    goto error;
+  }
+
+  cur_value = *p->parsing.value;
+  add_value = ((uint32_t)c) << 28;
+  if (add_value > 0xffffffffu - cur_value) {
+    goto error;
+  }
+
+  *p->parsing.value = cur_value + add_value;
+
+  if ((*cur) & 0x80) {
+    return parse_value5up(p, cur + 1, end);
+  } else {
+    return parse_next(p, cur + 1, end);
+  }
+
+error:
+  if (grpc_http_trace) {
+    gpr_log(GPR_ERROR,
+            "integer overflow in hpack integer decoding: have 0x%08x, "
+            "got byte 0x%02x on byte 5",
+            *p->parsing.value, *cur);
+  }
+  return parse_error(p, cur, end);
+}
+
+/* parse any trailing bytes in a varint: it's possible to append an arbitrary
+   number of 0x80's and not affect the value - a zero will terminate - and
+   anything else will overflow */
+static int parse_value5up(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                          const uint8_t *end) {
+  while (cur != end && *cur == 0x80) {
+    ++cur;
+  }
+
+  if (cur == end) {
+    p->state = parse_value5up;
+    return 1;
+  }
+
+  if (*cur == 0) {
+    return parse_next(p, cur + 1, end);
+  }
+
+  if (grpc_http_trace) {
+    gpr_log(GPR_ERROR,
+            "integer overflow in hpack integer decoding: have 0x%08x, "
+            "got byte 0x%02x sometime after byte 5",
+            *p->parsing.value, *cur);
+  }
+  return parse_error(p, cur, end);
+}
+
+/* parse a string prefix */
+static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                               const uint8_t *end) {
+  if (cur == end) {
+    p->state = parse_string_prefix;
+    return 1;
+  }
+
+  p->strlen = (*cur) & 0x7f;
+  p->huff = (*cur) >> 7;
+  if (p->strlen == 0x7f) {
+    p->parsing.value = &p->strlen;
+    return parse_value0(p, cur + 1, end);
+  } else {
+    return parse_next(p, cur + 1, end);
+  }
+}
+
+/* append some bytes to a string */
+static void append_bytes(grpc_chttp2_hpack_parser_string *str,
+                         const uint8_t *data, size_t length) {
+  if (length + str->length > str->capacity) {
+    GPR_ASSERT(str->length + length <= UINT32_MAX);
+    str->capacity = (uint32_t)(str->length + length);
+    str->str = gpr_realloc(str->str, str->capacity);
+  }
+  memcpy(str->str + str->length, data, length);
+  GPR_ASSERT(length <= UINT32_MAX - str->length);
+  str->length += (uint32_t)length;
+}
+
+static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                         const uint8_t *end) {
+  grpc_chttp2_hpack_parser_string *str = p->parsing.str;
+  uint32_t bits;
+  uint8_t decoded[3];
+  switch ((binary_state)p->binary) {
+    case NOT_BINARY:
+      append_bytes(str, cur, (size_t)(end - cur));
+      return 1;
+    b64_byte0:
+    case B64_BYTE0:
+      if (cur == end) {
+        p->binary = B64_BYTE0;
+        return 1;
+      }
+      bits = inverse_base64[*cur];
+      ++cur;
+      if (bits == 255)
+        return 0;
+      else if (bits == 64)
+        goto b64_byte0;
+      p->base64_buffer = bits << 18;
+    /* fallthrough */
+    b64_byte1:
+    case B64_BYTE1:
+      if (cur == end) {
+        p->binary = B64_BYTE1;
+        return 1;
+      }
+      bits = inverse_base64[*cur];
+      ++cur;
+      if (bits == 255)
+        return 0;
+      else if (bits == 64)
+        goto b64_byte1;
+      p->base64_buffer |= bits << 12;
+    /* fallthrough */
+    b64_byte2:
+    case B64_BYTE2:
+      if (cur == end) {
+        p->binary = B64_BYTE2;
+        return 1;
+      }
+      bits = inverse_base64[*cur];
+      ++cur;
+      if (bits == 255)
+        return 0;
+      else if (bits == 64)
+        goto b64_byte2;
+      p->base64_buffer |= bits << 6;
+    /* fallthrough */
+    b64_byte3:
+    case B64_BYTE3:
+      if (cur == end) {
+        p->binary = B64_BYTE3;
+        return 1;
+      }
+      bits = inverse_base64[*cur];
+      ++cur;
+      if (bits == 255)
+        return 0;
+      else if (bits == 64)
+        goto b64_byte3;
+      p->base64_buffer |= bits;
+      bits = p->base64_buffer;
+      decoded[0] = (uint8_t)(bits >> 16);
+      decoded[1] = (uint8_t)(bits >> 8);
+      decoded[2] = (uint8_t)(bits);
+      append_bytes(str, decoded, 3);
+      goto b64_byte0;
+  }
+  GPR_UNREACHABLE_CODE(return 1);
+}
+
+/* append a null terminator to a string */
+static int finish_str(grpc_chttp2_hpack_parser *p) {
+  uint8_t terminator = 0;
+  uint8_t decoded[2];
+  uint32_t bits;
+  grpc_chttp2_hpack_parser_string *str = p->parsing.str;
+  switch ((binary_state)p->binary) {
+    case NOT_BINARY:
+      break;
+    case B64_BYTE0:
+      break;
+    case B64_BYTE1:
+      gpr_log(GPR_ERROR, "illegal base64 encoding");
+      return 0; /* illegal encoding */
+    case B64_BYTE2:
+      bits = p->base64_buffer;
+      if (bits & 0xffff) {
+        gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%04x",
+                bits & 0xffff);
+        return 0;
+      }
+      decoded[0] = (uint8_t)(bits >> 16);
+      append_bytes(str, decoded, 1);
+      break;
+    case B64_BYTE3:
+      bits = p->base64_buffer;
+      if (bits & 0xff) {
+        gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%02x",
+                bits & 0xff);
+        return 0;
+      }
+      decoded[0] = (uint8_t)(bits >> 16);
+      decoded[1] = (uint8_t)(bits >> 8);
+      append_bytes(str, decoded, 2);
+      break;
+  }
+  append_bytes(str, &terminator, 1);
+  p->parsing.str->length--; /* don't actually count the null terminator */
+  return 1;
+}
+
+/* decode a nibble from a huffman encoded stream */
+static int huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t nibble) {
+  int16_t emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble];
+  int16_t next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble];
+  if (emit != -1) {
+    if (emit >= 0 && emit < 256) {
+      uint8_t c = (uint8_t)emit;
+      if (!append_string(p, &c, (&c) + 1)) return 0;
+    } else {
+      assert(emit == 256);
+    }
+  }
+  p->huff_state = next;
+  return 1;
+}
+
+/* decode full bytes from a huffman encoded stream */
+static int add_huff_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                          const uint8_t *end) {
+  for (; cur != end; ++cur) {
+    if (!huff_nibble(p, *cur >> 4) || !huff_nibble(p, *cur & 0xf)) return 0;
+  }
+  return 1;
+}
+
+/* decode some string bytes based on the current decoding mode
+   (huffman or not) */
+static int add_str_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                         const uint8_t *end) {
+  if (p->huff) {
+    return add_huff_bytes(p, cur, end);
+  } else {
+    return append_string(p, cur, end);
+  }
+}
+
+/* parse a string - tries to do large chunks at a time */
+static int parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                        const uint8_t *end) {
+  size_t remaining = p->strlen - p->strgot;
+  size_t given = (size_t)(end - cur);
+  if (remaining <= given) {
+    return add_str_bytes(p, cur, cur + remaining) && finish_str(p) &&
+           parse_next(p, cur + remaining, end);
+  } else {
+    if (!add_str_bytes(p, cur, cur + given)) return 0;
+    GPR_ASSERT(given <= UINT32_MAX - p->strgot);
+    p->strgot += (uint32_t)given;
+    p->state = parse_string;
+    return 1;
+  }
+}
+
+/* begin parsing a string - performs setup, calls parse_string */
+static int begin_parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                              const uint8_t *end, uint8_t binary,
+                              grpc_chttp2_hpack_parser_string *str) {
+  p->strgot = 0;
+  str->length = 0;
+  p->parsing.str = str;
+  p->huff_state = 0;
+  p->binary = binary;
+  return parse_string(p, cur, end);
+}
+
+/* parse the key string */
+static int parse_key_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                            const uint8_t *end) {
+  return begin_parse_string(p, cur, end, NOT_BINARY, &p->key);
+}
+
+/* check if a key represents a binary header or not */
+typedef enum { BINARY_HEADER, PLAINTEXT_HEADER, ERROR_HEADER } is_binary_header;
+
+static is_binary_header is_binary_literal_header(grpc_chttp2_hpack_parser *p) {
+  return grpc_is_binary_header(p->key.str, p->key.length) ? BINARY_HEADER
+                                                          : PLAINTEXT_HEADER;
+}
+
+static is_binary_header is_binary_indexed_header(grpc_chttp2_hpack_parser *p) {
+  grpc_mdelem *elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
+  if (!elem) {
+    if (grpc_http_trace) {
+      gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
+    }
+    return ERROR_HEADER;
+  }
+  return grpc_is_binary_header(
+             (const char *)GPR_SLICE_START_PTR(elem->key->slice),
+             GPR_SLICE_LENGTH(elem->key->slice))
+             ? BINARY_HEADER
+             : PLAINTEXT_HEADER;
+}
+
+/* parse the value string */
+static int parse_value_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+                              const uint8_t *end, is_binary_header type) {
+  switch (type) {
+    case BINARY_HEADER:
+      return begin_parse_string(p, cur, end, B64_BYTE0, &p->value);
+    case PLAINTEXT_HEADER:
+      return begin_parse_string(p, cur, end, NOT_BINARY, &p->value);
+    case ERROR_HEADER:
+      return 0;
+  }
+  /* Add code to prevent return without value error */
+  GPR_UNREACHABLE_CODE(return 0);
+}
+
+static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p,
+                                               const uint8_t *cur,
+                                               const uint8_t *end) {
+  return parse_value_string(p, cur, end, is_binary_indexed_header(p));
+}
+
+static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p,
+                                               const uint8_t *cur,
+                                               const uint8_t *end) {
+  return parse_value_string(p, cur, end, is_binary_literal_header(p));
+}
+
+/* PUBLIC INTERFACE */
+
+static void on_header_not_set(void *user_data, grpc_mdelem *md) {
+  GPR_UNREACHABLE_CODE(return );
+}
+
+void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) {
+  p->on_header = on_header_not_set;
+  p->on_header_user_data = NULL;
+  p->state = parse_begin;
+  p->key.str = NULL;
+  p->key.capacity = 0;
+  p->key.length = 0;
+  p->value.str = NULL;
+  p->value.capacity = 0;
+  p->value.length = 0;
+  p->dynamic_table_update_allowed = 2;
+  grpc_chttp2_hptbl_init(&p->table);
+}
+
+void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) {
+  p->after_prioritization = p->state;
+  p->state = parse_stream_dep0;
+}
+
+void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p) {
+  grpc_chttp2_hptbl_destroy(&p->table);
+  gpr_free(p->key.str);
+  gpr_free(p->value.str);
+}
+
+int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
+                                   const uint8_t *beg, const uint8_t *end) {
+  /* TODO(ctiller): limit the distance of end from beg, and perform multiple
+     steps in the event of a large chunk of data to limit
+     stack space usage when no tail call optimization is
+     available */
+  return p->state(p, beg, end);
+}
+
+grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
+    grpc_exec_ctx *exec_ctx, 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;
+  GPR_TIMER_BEGIN("grpc_chttp2_hpack_parser_parse", 0);
+  if (!grpc_chttp2_hpack_parser_parse(parser, GPR_SLICE_START_PTR(slice),
+                                      GPR_SLICE_END_PTR(slice))) {
+    GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
+    return GRPC_CHTTP2_CONNECTION_ERROR;
+  }
+  if (is_last) {
+    if (parser->is_boundary && parser->state != parse_begin) {
+      gpr_log(GPR_ERROR,
+              "end of header frame not aligned with a hpack record boundary");
+      GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
+      return GRPC_CHTTP2_CONNECTION_ERROR;
+    }
+    /* need to check for null stream: this can occur if we receive an invalid
+       stream id on a header */
+    if (stream_parsing != NULL) {
+      if (parser->is_boundary) {
+        stream_parsing
+            ->got_metadata_on_parse[stream_parsing->header_frames_received] = 1;
+        stream_parsing->header_frames_received++;
+        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;
+    parser->is_eof = 0xde;
+    parser->dynamic_table_update_allowed = 2;
+  }
+  GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
+  return GRPC_CHTTP2_PARSE_OK;
+}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.h b/src/core/ext/transport/chttp2/transport/hpack_parser.h
new file mode 100644
index 0000000..0aaddc8
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.h
@@ -0,0 +1,116 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H
+
+#include <stddef.h>
+
+#include <grpc/support/port_platform.h>
+#include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/ext/transport/chttp2/transport/hpack_table.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/metadata.h"
+
+typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser;
+
+typedef int (*grpc_chttp2_hpack_parser_state)(grpc_chttp2_hpack_parser *p,
+                                              const uint8_t *beg,
+                                              const uint8_t *end);
+
+typedef struct {
+  char *str;
+  uint32_t length;
+  uint32_t capacity;
+} grpc_chttp2_hpack_parser_string;
+
+struct grpc_chttp2_hpack_parser {
+  /* user specified callback for each header output */
+  void (*on_header)(void *user_data, grpc_mdelem *md);
+  void *on_header_user_data;
+
+  /* current parse state - or a function that implements it */
+  grpc_chttp2_hpack_parser_state state;
+  /* future states dependent on the opening op code */
+  const grpc_chttp2_hpack_parser_state *next_state;
+  /* what to do after skipping prioritization data */
+  grpc_chttp2_hpack_parser_state after_prioritization;
+  /* the value we're currently parsing */
+  union {
+    uint32_t *value;
+    grpc_chttp2_hpack_parser_string *str;
+  } parsing;
+  /* string parameters for each chunk */
+  grpc_chttp2_hpack_parser_string key;
+  grpc_chttp2_hpack_parser_string value;
+  /* parsed index */
+  uint32_t index;
+  /* length of source bytes for the currently parsing string */
+  uint32_t strlen;
+  /* number of source bytes read for the currently parsing string */
+  uint32_t strgot;
+  /* huffman decoding state */
+  int16_t huff_state;
+  /* is the string being decoded binary? */
+  uint8_t binary;
+  /* is the current string huffman encoded? */
+  uint8_t huff;
+  /* is a dynamic table update allowed? */
+  uint8_t dynamic_table_update_allowed;
+  /* set by higher layers, used by grpc_chttp2_header_parser_parse to signal
+     it should append a metadata boundary at the end of frame */
+  uint8_t is_boundary;
+  uint8_t is_eof;
+  uint32_t base64_buffer;
+
+  /* hpack table */
+  grpc_chttp2_hptbl table;
+};
+
+void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p);
+void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p);
+
+void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p);
+
+/* returns 1 on success, 0 on error */
+int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
+                                   const uint8_t *beg, const uint8_t *end);
+
+/* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for
+   the transport */
+grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
+    grpc_exec_ctx *exec_ctx, void *hpack_parser,
+    grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.c b/src/core/ext/transport/chttp2/transport/hpack_table.c
new file mode 100644
index 0000000..67cd1bb
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.c
@@ -0,0 +1,369 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/hpack_table.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/support/murmur_hash.h"
+
+extern int grpc_http_trace;
+
+static struct {
+  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", ""},
+};
+
+static uint32_t entries_for_bytes(uint32_t bytes) {
+  return (bytes + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) /
+         GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
+}
+
+void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl) {
+  size_t i;
+
+  memset(tbl, 0, sizeof(*tbl));
+  tbl->current_table_bytes = tbl->max_bytes =
+      GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
+  tbl->max_entries = tbl->cap_entries =
+      entries_for_bytes(tbl->current_table_bytes);
+  tbl->ents = gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries);
+  memset(tbl->ents, 0, sizeof(*tbl->ents) * tbl->cap_entries);
+  for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
+    tbl->static_ents[i - 1] =
+        grpc_mdelem_from_strings(static_table[i].key, static_table[i].value);
+  }
+}
+
+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]);
+  }
+  for (i = 0; i < tbl->num_ents; i++) {
+    GRPC_MDELEM_UNREF(tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]);
+  }
+  gpr_free(tbl->ents);
+}
+
+grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
+                                      uint32_t tbl_index) {
+  /* Static table comes first, just return an entry from it */
+  if (tbl_index <= GRPC_CHTTP2_LAST_STATIC_ENTRY) {
+    return tbl->static_ents[tbl_index - 1];
+  }
+  /* Otherwise, find the value in the list of valid entries */
+  tbl_index -= (GRPC_CHTTP2_LAST_STATIC_ENTRY + 1);
+  if (tbl_index < tbl->num_ents) {
+    uint32_t offset =
+        (tbl->num_ents - 1u - tbl_index + tbl->first_ent) % tbl->cap_entries;
+    return tbl->ents[offset];
+  }
+  /* Invalid entry: return error */
+  return NULL;
+}
+
+/* Evict one element from the table */
+static void evict1(grpc_chttp2_hptbl *tbl) {
+  grpc_mdelem *first_ent = tbl->ents[tbl->first_ent];
+  size_t elem_bytes = GPR_SLICE_LENGTH(first_ent->key->slice) +
+                      GPR_SLICE_LENGTH(first_ent->value->slice) +
+                      GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
+  GPR_ASSERT(elem_bytes <= tbl->mem_used);
+  tbl->mem_used -= (uint32_t)elem_bytes;
+  tbl->first_ent = ((tbl->first_ent + 1) % tbl->cap_entries);
+  tbl->num_ents--;
+  GRPC_MDELEM_UNREF(first_ent);
+}
+
+static void rebuild_ents(grpc_chttp2_hptbl *tbl, uint32_t new_cap) {
+  grpc_mdelem **ents = gpr_malloc(sizeof(*ents) * new_cap);
+  uint32_t i;
+
+  for (i = 0; i < tbl->num_ents; i++) {
+    ents[i] = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
+  }
+  gpr_free(tbl->ents);
+  tbl->ents = ents;
+  tbl->cap_entries = new_cap;
+  tbl->first_ent = 0;
+}
+
+void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
+                                     uint32_t max_bytes) {
+  if (tbl->max_bytes == max_bytes) {
+    return;
+  }
+  gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes);
+  while (tbl->mem_used > max_bytes) {
+    evict1(tbl);
+  }
+  tbl->max_bytes = max_bytes;
+}
+
+int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
+                                             uint32_t bytes) {
+  if (tbl->current_table_bytes == bytes) {
+    return 1;
+  }
+  if (bytes > tbl->max_bytes) {
+    if (grpc_http_trace) {
+      gpr_log(GPR_ERROR,
+              "Attempt to make hpack table %d bytes when max is %d bytes",
+              bytes, tbl->max_bytes);
+    }
+    return 0;
+  }
+  if (grpc_http_trace) {
+    gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes);
+  }
+  while (tbl->mem_used > bytes) {
+    evict1(tbl);
+  }
+  tbl->current_table_bytes = bytes;
+  tbl->max_entries = entries_for_bytes(bytes);
+  if (tbl->max_entries > tbl->cap_entries) {
+    rebuild_ents(tbl, GPR_MAX(tbl->max_entries, 2 * tbl->cap_entries));
+  } else if (tbl->max_entries < tbl->cap_entries / 3) {
+    uint32_t new_cap = GPR_MAX(tbl->max_entries, 16u);
+    if (new_cap != tbl->cap_entries) {
+      rebuild_ents(tbl, new_cap);
+    }
+  }
+  return 1;
+}
+
+int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
+  /* determine how many bytes of buffer this entry represents */
+  size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) +
+                      GPR_SLICE_LENGTH(md->value->slice) +
+                      GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
+
+  if (tbl->current_table_bytes > tbl->max_bytes) {
+    if (grpc_http_trace) {
+      gpr_log(GPR_ERROR,
+              "HPACK max table size reduced to %d but not reflected by hpack "
+              "stream (still at %d)",
+              tbl->max_bytes, tbl->current_table_bytes);
+    }
+    return 0;
+  }
+
+  /* we can't add elements bigger than the max table size */
+  if (elem_bytes > tbl->current_table_bytes) {
+    /* HPACK draft 10 section 4.4 states:
+     * If the size of the new entry is less than or equal to the maximum
+     * size, that entry is added to the table.  It is not an error to
+     * attempt to add an entry that is larger than the maximum size; an
+     * attempt to add an entry larger than the entire table causes
+     * the table
+     * to be emptied of all existing entries, and results in an
+     * empty table.
+     */
+    while (tbl->num_ents) {
+      evict1(tbl);
+    }
+    return 1;
+  }
+
+  /* evict entries to ensure no overflow */
+  while (elem_bytes > (size_t)tbl->current_table_bytes - tbl->mem_used) {
+    evict1(tbl);
+  }
+
+  /* copy the finalized entry in */
+  tbl->ents[(tbl->first_ent + tbl->num_ents) % tbl->cap_entries] =
+      GRPC_MDELEM_REF(md);
+
+  /* update accounting values */
+  tbl->num_ents++;
+  tbl->mem_used += (uint32_t)elem_bytes;
+  return 1;
+}
+
+grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
+    const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
+  grpc_chttp2_hptbl_find_result r = {0, 0};
+  uint32_t i;
+
+  /* See if the string is in the static table */
+  for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
+    grpc_mdelem *ent = tbl->static_ents[i];
+    if (md->key != ent->key) continue;
+    r.index = i + 1u;
+    r.has_value = md->value == ent->value;
+    if (r.has_value) return r;
+  }
+
+  /* Scan the dynamic table */
+  for (i = 0; i < tbl->num_ents; i++) {
+    uint32_t idx =
+        (uint32_t)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
+    grpc_mdelem *ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
+    if (md->key != ent->key) continue;
+    r.index = idx;
+    r.has_value = md->value == ent->value;
+    if (r.has_value) return r;
+  }
+
+  return r;
+}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.h b/src/core/ext/transport/chttp2/transport/hpack_table.h
new file mode 100644
index 0000000..b3475c8
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.h
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_TABLE_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_TABLE_H
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+#include "src/core/lib/transport/metadata.h"
+
+/* HPACK header table */
+
+/* last index in the static table */
+#define GRPC_CHTTP2_LAST_STATIC_ENTRY 61
+
+/* Initial table size as per the spec */
+#define GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE 4096
+/* Maximum table size that we'll use */
+#define GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE
+/* Per entry overhead bytes as per the spec */
+#define GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD 32
+#if 0
+/* Maximum number of entries we could possibly fit in the table, given defined
+   overheads */
+#define GRPC_CHTTP2_MAX_TABLE_COUNT                                            \
+  ((GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / \
+   GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD)
+#endif
+
+/* hpack decoder table */
+typedef struct {
+  /* the first used entry in ents */
+  uint32_t first_ent;
+  /* how many entries are in the table */
+  uint32_t num_ents;
+  /* the amount of memory used by the table, according to the hpack algorithm */
+  uint32_t mem_used;
+  /* the max memory allowed to be used by the table, according to the hpack
+     algorithm */
+  uint32_t max_bytes;
+  /* the currently agreed size of the table, according to the hpack algorithm */
+  uint32_t current_table_bytes;
+  /* Maximum number of entries we could possibly fit in the table, given defined
+     overheads */
+  uint32_t max_entries;
+  /* Number of entries allocated in ents */
+  uint32_t cap_entries;
+  /* a circular buffer of headers - this is stored in the opposite order to
+     what hpack specifies, in order to simplify table management a little...
+     meaning lookups need to SUBTRACT from the end position */
+  grpc_mdelem **ents;
+  grpc_mdelem *static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY];
+} grpc_chttp2_hptbl;
+
+/* initialize a hpack table */
+void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl);
+void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl);
+void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
+                                     uint32_t max_bytes);
+int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
+                                             uint32_t bytes);
+
+/* lookup a table entry based on its hpack index */
+grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
+                                      uint32_t index);
+/* add a table entry to the index */
+int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl,
+                          grpc_mdelem *md) GRPC_MUST_USE_RESULT;
+/* Find a key/value pair in the table... returns the index in the table of the
+   most similar entry, or 0 if the value was not found */
+typedef struct {
+  uint32_t index;
+  int has_value;
+} grpc_chttp2_hptbl_find_result;
+grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
+    const grpc_chttp2_hptbl *tbl, grpc_mdelem *md);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_TABLE_H */
diff --git a/src/core/transport/chttp2/hpack_tables.txt b/src/core/ext/transport/chttp2/transport/hpack_tables.txt
similarity index 100%
rename from src/core/transport/chttp2/hpack_tables.txt
rename to src/core/ext/transport/chttp2/transport/hpack_tables.txt
diff --git a/src/core/ext/transport/chttp2/transport/http2_errors.h b/src/core/ext/transport/chttp2/transport/http2_errors.h
new file mode 100644
index 0000000..85542e2
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/http2_errors.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_ERRORS_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_ERRORS_H
+
+/* error codes for RST_STREAM from http2 draft 14 section 7 */
+typedef enum {
+  GRPC_CHTTP2_NO_ERROR = 0x0,
+  GRPC_CHTTP2_PROTOCOL_ERROR = 0x1,
+  GRPC_CHTTP2_INTERNAL_ERROR = 0x2,
+  GRPC_CHTTP2_FLOW_CONTROL_ERROR = 0x3,
+  GRPC_CHTTP2_SETTINGS_TIMEOUT = 0x4,
+  GRPC_CHTTP2_STREAM_CLOSED = 0x5,
+  GRPC_CHTTP2_FRAME_SIZE_ERROR = 0x6,
+  GRPC_CHTTP2_REFUSED_STREAM = 0x7,
+  GRPC_CHTTP2_CANCEL = 0x8,
+  GRPC_CHTTP2_COMPRESSION_ERROR = 0x9,
+  GRPC_CHTTP2_CONNECT_ERROR = 0xa,
+  GRPC_CHTTP2_ENHANCE_YOUR_CALM = 0xb,
+  GRPC_CHTTP2_INADEQUATE_SECURITY = 0xc,
+  /* force use of a default clause */
+  GRPC_CHTTP2__ERROR_DO_NOT_USE = -1
+} grpc_chttp2_error_code;
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_ERRORS_H */
diff --git a/src/core/ext/transport/chttp2/transport/huffsyms.c b/src/core/ext/transport/chttp2/transport/huffsyms.c
new file mode 100644
index 0000000..91f62bf
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/huffsyms.c
@@ -0,0 +1,105 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/huffsyms.h"
+
+/* Constants pulled from the HPACK spec, and converted to C using the vim
+   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},
+};
diff --git a/src/core/ext/transport/chttp2/transport/huffsyms.h b/src/core/ext/transport/chttp2/transport/huffsyms.h
new file mode 100644
index 0000000..780baea
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/huffsyms.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HUFFSYMS_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HUFFSYMS_H
+
+/* HPACK static huffman table */
+
+#define GRPC_CHTTP2_NUM_HUFFSYMS 257
+
+typedef struct {
+  unsigned bits;
+  unsigned length;
+} grpc_chttp2_huffsym;
+
+extern const grpc_chttp2_huffsym grpc_chttp2_huffsyms[GRPC_CHTTP2_NUM_HUFFSYMS];
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HUFFSYMS_H */
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.c b/src/core/ext/transport/chttp2/transport/incoming_metadata.c
new file mode 100644
index 0000000..ef5fd4f
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.c
@@ -0,0 +1,96 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
+
+#include <string.h>
+
+#include "src/core/ext/transport/chttp2/transport/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;
+  if (!buffer->published) {
+    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) {
+  GPR_ASSERT(!buffer->published);
+  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) {
+  GPR_ASSERT(!buffer->published);
+  buffer->deadline = deadline;
+}
+
+void grpc_chttp2_incoming_metadata_buffer_publish(
+    grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch) {
+  GPR_ASSERT(!buffer->published);
+  buffer->published = 1;
+  if (buffer->count > 0) {
+    size_t i;
+    for (i = 1; i < buffer->count; i++) {
+      buffer->elems[i].prev = &buffer->elems[i - 1];
+    }
+    for (i = 0; i < buffer->count - 1; i++) {
+      buffer->elems[i].next = &buffer->elems[i + 1];
+    }
+    buffer->elems[0].prev = NULL;
+    buffer->elems[buffer->count - 1].next = NULL;
+    batch->list.head = &buffer->elems[0];
+    batch->list.tail = &buffer->elems[buffer->count - 1];
+  } else {
+    batch->list.head = batch->list.tail = NULL;
+  }
+  batch->deadline = buffer->deadline;
+}
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.h b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
new file mode 100644
index 0000000..5e1dc72
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INCOMING_METADATA_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INCOMING_METADATA_H
+
+#include "src/core/lib/transport/transport.h"
+
+typedef struct {
+  grpc_linked_mdelem *elems;
+  size_t count;
+  size_t capacity;
+  gpr_timespec deadline;
+  int published;
+} grpc_chttp2_incoming_metadata_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_publish(
+    grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch);
+
+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);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INCOMING_METADATA_H */
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
new file mode 100644
index 0000000..2fae653
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -0,0 +1,780 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/ext/transport/chttp2/transport/frame_data.h"
+#include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
+#include "src/core/ext/transport/chttp2/transport/frame_ping.h"
+#include "src/core/ext/transport/chttp2/transport/frame_rst_stream.h"
+#include "src/core/ext/transport/chttp2/transport/frame_settings.h"
+#include "src/core/ext/transport/chttp2/transport/frame_window_update.h"
+#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
+#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
+#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
+#include "src/core/ext/transport/chttp2/transport/stream_map.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/transport/connectivity_state.h"
+#include "src/core/lib/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_CHECK_READ_OPS,
+  GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE,
+  GRPC_CHTTP2_LIST_WRITABLE,
+  GRPC_CHTTP2_LIST_WRITING,
+  GRPC_CHTTP2_LIST_WRITTEN,
+  GRPC_CHTTP2_LIST_PARSING_SEEN,
+  GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING,
+  GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING,
+  GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT,
+  /* streams waiting for the outgoing window in the writing path, they will be
+   * merged to the stalled list or writable list under transport lock. */
+  GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT,
+  /** 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 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 {
+  uint8_t id[8];
+  grpc_closure *on_recv;
+  struct grpc_chttp2_outstanding_ping *next;
+  struct grpc_chttp2_outstanding_ping *prev;
+} grpc_chttp2_outstanding_ping;
+
+/* forward declared in frame_data.h */
+struct grpc_chttp2_incoming_byte_stream {
+  grpc_byte_stream base;
+  gpr_refcount refs;
+  struct grpc_chttp2_incoming_byte_stream *next_message;
+  int failed;
+
+  grpc_chttp2_transport *transport;
+  grpc_chttp2_stream *stream;
+  int is_tail;
+  gpr_slice_buffer slices;
+  grpc_closure *on_next;
+  gpr_slice *next;
+};
+
+typedef struct {
+  /** data to write next write */
+  gpr_slice_buffer qbuf;
+
+  /** window available for us to send to peer */
+  int64_t outgoing_window;
+  /** window available to announce to peer */
+  int64_t announce_incoming_window;
+  /** how much window would we like to have for incoming_window */
+  uint32_t connection_window_target;
+
+  /** have we seen a goaway */
+  uint8_t seen_goaway;
+  /** have we sent a goaway */
+  uint8_t sent_goaway;
+
+  /** is this transport a client? */
+  uint8_t is_client;
+  /** are the local settings dirty and need to be sent? */
+  uint8_t dirtied_local_settings;
+  /** have local settings been sent? */
+  uint8_t sent_local_settings;
+  /** bitmask of setting indexes to send out */
+  uint32_t force_send_settings;
+  /** settings values */
+  uint32_t 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 */
+  uint32_t next_stream_id;
+
+  /** how far to lookahead in a stream? */
+  uint32_t stream_lookahead;
+
+  /** last received stream id */
+  uint32_t last_incoming_stream_id;
+
+  /** pings awaiting responses */
+  grpc_chttp2_outstanding_ping pings;
+  /** next payload for an outgoing ping */
+  uint64_t ping_counter;
+
+  /** concurrent stream count: updated when not parsing,
+      so this is a strict over-estimation on the client */
+  uint32_t 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;
+  int64_t outgoing_window;
+  /** is this a client? */
+  uint8_t is_client;
+  /** callback for when writing is done */
+  grpc_closure done_cb;
+} grpc_chttp2_transport_writing;
+
+struct grpc_chttp2_transport_parsing {
+  /** is this transport a client? (boolean) */
+  uint8_t is_client;
+
+  /** were settings updated? */
+  uint8_t settings_updated;
+  /** was a settings ack received? */
+  uint8_t settings_ack_received;
+  /** was a goaway frame received? */
+  uint8_t goaway_received;
+
+  /** the last sent max_table_size setting */
+  uint32_t last_sent_max_table_size;
+
+  /** initial window change */
+  int64_t initial_window_update;
+
+  /** data to write later - after parsing */
+  gpr_slice_buffer qbuf;
+  /** 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 */
+  int64_t incoming_window;
+
+  /** next stream id available at the time of beginning parsing */
+  uint32_t next_stream_id;
+  uint32_t last_incoming_stream_id;
+
+  /* deframing */
+  grpc_chttp2_deframe_transport_state deframe_state;
+  uint8_t incoming_frame_type;
+  uint8_t incoming_frame_flags;
+  uint8_t header_eof;
+  uint32_t expect_continuation_stream_id;
+  uint32_t incoming_frame_size;
+  uint32_t incoming_stream_id;
+
+  /* active parser */
+  void *parser_data;
+  grpc_chttp2_stream_parsing *incoming_stream;
+  grpc_chttp2_parse_error (*parser)(
+      grpc_exec_ctx *exec_ctx, void *parser_user_data,
+      grpc_chttp2_transport_parsing *transport_parsing,
+      grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+
+  /* received settings */
+  uint32_t settings[GRPC_CHTTP2_NUM_SETTINGS];
+
+  /* goaway data */
+  grpc_status_code goaway_error;
+  uint32_t goaway_last_stream_index;
+  gpr_slice goaway_text;
+
+  int64_t outgoing_window;
+};
+
+struct grpc_chttp2_transport {
+  grpc_transport base; /* must be first */
+  grpc_endpoint *ep;
+  gpr_refcount refs;
+  char *peer_string;
+
+  /** when this drops to zero it's safe to shutdown the endpoint */
+  gpr_refcount shutdown_ep_refs;
+
+  gpr_mu mu;
+
+  /** is the transport destroying itself? */
+  uint8_t destroying;
+  /** has the upper layer closed the transport? */
+  uint8_t closed;
+
+  /** is a thread currently writing */
+  uint8_t writing_active;
+  /** is a thread currently parsing */
+  uint8_t parsing_active;
+
+  /** is there a read request to the endpoint outstanding? */
+  uint8_t 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_closure writing_action;
+  /** closure to finish reading from the endpoint */
+  grpc_closure recv_data;
+
+  /** incoming read bytes */
+  gpr_slice_buffer read_buffer;
+
+  /** 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)(grpc_exec_ctx *exec_ctx, 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;
+
+  /** Transport op to be applied post-parsing */
+  grpc_transport_op *post_parsing_op;
+};
+
+typedef struct {
+  /** HTTP2 stream id for this stream, or zero if one has not been assigned */
+  uint32_t id;
+
+  /** window available for us to send to peer */
+  int64_t 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. */
+  uint32_t 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. */
+  uint32_t unannounced_incoming_window_for_parse;
+  uint32_t unannounced_incoming_window_for_writing;
+  /** things the upper layers would like to send */
+  grpc_metadata_batch *send_initial_metadata;
+  grpc_closure *send_initial_metadata_finished;
+  grpc_byte_stream *send_message;
+  grpc_closure *send_message_finished;
+  grpc_metadata_batch *send_trailing_metadata;
+  grpc_closure *send_trailing_metadata_finished;
+
+  grpc_metadata_batch *recv_initial_metadata;
+  grpc_closure *recv_initial_metadata_ready;
+  grpc_byte_stream **recv_message;
+  grpc_closure *recv_message_ready;
+  grpc_metadata_batch *recv_trailing_metadata;
+  grpc_closure *recv_trailing_metadata_finished;
+
+  /** 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' */
+  uint8_t write_closed;
+  /** is this stream reading half-closed (boolean) */
+  uint8_t read_closed;
+  /** is this stream in the stream map? (boolean) */
+  uint8_t in_stream_map;
+  /** has this stream seen an error? if 1, then pending incoming frames
+      can be thrown away */
+  uint8_t seen_error;
+
+  uint8_t published_initial_metadata;
+  uint8_t published_trailing_metadata;
+  uint8_t faked_trailing_metadata;
+
+  grpc_chttp2_incoming_metadata_buffer received_initial_metadata;
+  grpc_chttp2_incoming_metadata_buffer received_trailing_metadata;
+
+  grpc_chttp2_incoming_frame_queue incoming_frames;
+} grpc_chttp2_stream_global;
+
+typedef struct {
+  /** HTTP2 stream id for this stream, or zero if one has not been assigned */
+  uint32_t id;
+  uint8_t fetching;
+  bool sent_initial_metadata;
+  uint8_t sent_message;
+  uint8_t sent_trailing_metadata;
+  uint8_t read_closed;
+  /** send this initial metadata */
+  grpc_metadata_batch *send_initial_metadata;
+  grpc_byte_stream *send_message;
+  grpc_metadata_batch *send_trailing_metadata;
+  int64_t outgoing_window;
+  /** how much window should we announce? */
+  uint32_t announce_window;
+  gpr_slice_buffer flow_controlled_buffer;
+  gpr_slice fetching_slice;
+  size_t stream_fetched;
+  grpc_closure finished_fetch;
+} grpc_chttp2_stream_writing;
+
+struct grpc_chttp2_stream_parsing {
+  /** HTTP2 stream id for this stream, or zero if one has not been assigned */
+  uint32_t id;
+  /** has this stream received a close */
+  uint8_t received_close;
+  /** saw a rst_stream */
+  uint8_t saw_rst_stream;
+  /** how many header frames have we received? */
+  uint8_t header_frames_received;
+  /** which metadata did we get (on this parse) */
+  uint8_t got_metadata_on_parse[2];
+  /** should we raise the seen_error flag in transport_global */
+  uint8_t seen_error;
+  /** window available for peer to send to us */
+  int64_t incoming_window;
+  /** parsing state for data frames */
+  grpc_chttp2_data_parser data_parser;
+  /** reason give to rst_stream */
+  uint32_t rst_stream_reason;
+  /** amount of window given */
+  int64_t outgoing_window;
+  /** number of bytes received - reset at end of parse thread execution */
+  int64_t received_bytes;
+
+  /** incoming metadata */
+  grpc_chttp2_incoming_metadata_buffer metadata_buffer[2];
+};
+
+struct grpc_chttp2_stream {
+  grpc_stream_refcount *refcount;
+  grpc_chttp2_stream_global global;
+  grpc_chttp2_stream_writing writing;
+  grpc_chttp2_stream_parsing parsing;
+
+  grpc_chttp2_stream_link links[STREAM_LIST_COUNT];
+  uint8_t 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_exec_ctx *exec_ctx,
+                                       grpc_chttp2_transport_global *global,
+                                       grpc_chttp2_transport_writing *writing,
+                                       int is_parsing);
+void grpc_chttp2_perform_writes(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
+    grpc_endpoint *endpoint);
+void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
+                                   void *transport_writing, bool success);
+void grpc_chttp2_cleanup_writing(grpc_exec_ctx *exec_ctx,
+                                 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_exec_ctx *exec_ctx,
+                             grpc_chttp2_transport_parsing *transport_parsing,
+                             gpr_slice slice);
+void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_transport_global *global,
+                               grpc_chttp2_transport_parsing *parsing);
+
+bool grpc_chttp2_list_add_writable_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+/** Get a writable stream
+    returns non-zero if there was a stream available */
+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);
+bool grpc_chttp2_list_remove_writable_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) GRPC_MUST_USE_RESULT;
+
+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_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_check_read_ops(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+int grpc_chttp2_list_pop_check_read_ops(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global **stream_global);
+
+void grpc_chttp2_list_add_writing_stalled_by_transport(
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_writing *stream_writing);
+void grpc_chttp2_list_flush_writing_stalled_by_transport(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
+    bool is_window_available);
+
+void grpc_chttp2_list_add_stalled_by_transport(
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_writing *stream_writing);
+int grpc_chttp2_list_pop_stalled_by_transport(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global **stream_global);
+void grpc_chttp2_list_remove_stalled_by_transport(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+
+void grpc_chttp2_list_add_unannounced_incoming_window_available(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+void grpc_chttp2_list_remove_unannounced_incoming_window_available(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+int grpc_chttp2_list_pop_unannounced_incoming_window_available(
+    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_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_closed_waiting_for_writing(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
+int grpc_chttp2_list_pop_closed_waiting_for_writing(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global **stream_global);
+
+grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
+    grpc_chttp2_transport_parsing *transport_parsing, uint32_t id);
+grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+    uint32_t id);
+
+void grpc_chttp2_add_incoming_goaway(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+    uint32_t 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_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
+
+void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
+                                       grpc_closure **pclosure, int success);
+
+#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
+
+typedef enum {
+  GRPC_CHTTP2_FLOWCTL_MOVE,
+  GRPC_CHTTP2_FLOWCTL_CREDIT,
+  GRPC_CHTTP2_FLOWCTL_DEBIT
+} grpc_chttp2_flowctl_op;
+
+#define GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, transport, id1, id2, dst_context, \
+                                     dst_var, src_context, src_var)           \
+  do {                                                                        \
+    assert(id1 == id2);                                                       \
+    if (grpc_flowctl_trace) {                                                 \
+      grpc_chttp2_flowctl_trace(                                              \
+          __FILE__, __LINE__, phase, GRPC_CHTTP2_FLOWCTL_MOVE, #dst_context,  \
+          #dst_var, #src_context, #src_var, transport->is_client, id1,        \
+          dst_context->dst_var, src_context->src_var);                        \
+    }                                                                         \
+    dst_context->dst_var += src_context->src_var;                             \
+    src_context->src_var = 0;                                                 \
+  } while (0)
+
+#define GRPC_CHTTP2_FLOW_MOVE_STREAM(phase, transport, dst_context, dst_var, \
+                                     src_context, src_var)                   \
+  GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, transport, dst_context->id,            \
+                               src_context->id, dst_context, dst_var,        \
+                               src_context, src_var)
+#define GRPC_CHTTP2_FLOW_MOVE_TRANSPORT(phase, dst_context, dst_var,           \
+                                        src_context, src_var)                  \
+  GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, dst_context, 0, 0, dst_context, dst_var, \
+                               src_context, src_var)
+
+#define GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, transport, id, dst_context,      \
+                                       dst_var, amount)                        \
+  do {                                                                         \
+    if (grpc_flowctl_trace) {                                                  \
+      grpc_chttp2_flowctl_trace(__FILE__, __LINE__, phase,                     \
+                                GRPC_CHTTP2_FLOWCTL_CREDIT, #dst_context,      \
+                                #dst_var, NULL, #amount, transport->is_client, \
+                                id, dst_context->dst_var, amount);             \
+    }                                                                          \
+    dst_context->dst_var += amount;                                            \
+  } while (0)
+
+#define GRPC_CHTTP2_FLOW_CREDIT_STREAM(phase, transport, dst_context, dst_var, \
+                                       amount)                                 \
+  GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, transport, dst_context->id,            \
+                                 dst_context, dst_var, amount)
+#define GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT(phase, dst_context, dst_var, amount) \
+  GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, dst_context, 0, dst_context, dst_var,  \
+                                 amount)
+
+#define GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, transport, id, dst_context,       \
+                                      dst_var, amount)                         \
+  do {                                                                         \
+    if (grpc_flowctl_trace) {                                                  \
+      grpc_chttp2_flowctl_trace(__FILE__, __LINE__, phase,                     \
+                                GRPC_CHTTP2_FLOWCTL_DEBIT, #dst_context,       \
+                                #dst_var, NULL, #amount, transport->is_client, \
+                                id, dst_context->dst_var, amount);             \
+    }                                                                          \
+    dst_context->dst_var -= amount;                                            \
+  } while (0)
+
+#define GRPC_CHTTP2_FLOW_DEBIT_STREAM(phase, transport, dst_context, dst_var, \
+                                      amount)                                 \
+  GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, transport, dst_context->id,            \
+                                dst_context, dst_var, amount)
+#define GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT(phase, dst_context, dst_var, amount) \
+  GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, dst_context, 0, dst_context, dst_var,  \
+                                amount)
+
+void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
+                               grpc_chttp2_flowctl_op op, const char *context1,
+                               const char *var1, const char *context2,
+                               const char *var2, int is_client,
+                               uint32_t stream_id, int64_t val1, int64_t val2);
+
+void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
+                             grpc_chttp2_transport_global *transport_global,
+                             grpc_chttp2_stream_global *stream,
+                             grpc_status_code status, gpr_slice *details);
+void grpc_chttp2_mark_stream_closed(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global, int close_reads,
+    int close_writes);
+void grpc_chttp2_start_writing(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_transport_global *transport_global);
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+#define GRPC_CHTTP2_STREAM_REF(stream_global, reason) \
+  grpc_chttp2_stream_ref(stream_global, reason)
+#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, reason) \
+  grpc_chttp2_stream_unref(exec_ctx, stream_global, reason)
+void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global,
+                            const char *reason);
+void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
+                              grpc_chttp2_stream_global *stream_global,
+                              const char *reason);
+#else
+#define GRPC_CHTTP2_STREAM_REF(stream_global, reason) \
+  grpc_chttp2_stream_ref(stream_global)
+#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, reason) \
+  grpc_chttp2_stream_unref(exec_ctx, stream_global)
+void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global);
+void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
+                              grpc_chttp2_stream_global *stream_global);
+#endif
+
+grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size,
+    uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue);
+void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
+                                           grpc_chttp2_incoming_byte_stream *bs,
+                                           gpr_slice slice);
+void grpc_chttp2_incoming_byte_stream_finished(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
+    int from_parsing_thread);
+
+void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
+                          grpc_chttp2_transport_parsing *parsing,
+                          const uint8_t *opaque_8bytes);
+
+/** add a ref to the stream and add it to the writable list;
+    ref will be dropped in writing.c */
+void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
+                                 grpc_chttp2_stream_global *stream_global);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
new file mode 100644
index 0000000..a9f043c
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -0,0 +1,866 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
+#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
+#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+static int init_frame_parser(grpc_exec_ctx *exec_ctx,
+                             grpc_chttp2_transport_parsing *transport_parsing);
+static int init_header_frame_parser(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+    int is_continuation);
+static int init_data_frame_parser(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
+static int init_rst_stream_parser(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
+static int init_settings_frame_parser(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
+static int init_window_update_frame_parser(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
+static int init_ping_parser(grpc_exec_ctx *exec_ctx,
+                            grpc_chttp2_transport_parsing *transport_parsing);
+static int init_goaway_parser(grpc_exec_ctx *exec_ctx,
+                              grpc_chttp2_transport_parsing *transport_parsing);
+static int init_skip_frame_parser(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+    int is_header);
+
+static int parse_frame_slice(grpc_exec_ctx *exec_ctx,
+                             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;
+
+  GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0);
+
+  transport_parsing->next_stream_id = transport_global->next_stream_id;
+  transport_parsing->last_sent_max_table_size =
+      transport_global->settings[GRPC_SENT_SETTINGS]
+                                [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE];
+
+  /* update the parsing view of incoming window */
+  while (grpc_chttp2_list_pop_unannounced_incoming_window_available(
+      transport_global, transport_parsing, &stream_global, &stream_parsing)) {
+    GRPC_CHTTP2_FLOW_MOVE_STREAM("parse", transport_parsing, stream_parsing,
+                                 incoming_window, stream_global,
+                                 unannounced_incoming_window_for_parse);
+  }
+
+  GPR_TIMER_END("grpc_chttp2_prepare_to_read", 0);
+}
+
+void grpc_chttp2_publish_reads(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_parsing *transport_parsing) {
+  grpc_chttp2_stream_global *stream_global;
+  grpc_chttp2_stream_parsing *stream_parsing;
+  int was_zero;
+  int is_zero;
+
+  /* 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;
+  }
+
+  /* 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(uint32_t));
+    transport_parsing->settings_ack_received = 0;
+    transport_global->sent_local_settings = 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(exec_ctx, transport_global,
+                                    (uint32_t)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 */
+  was_zero = transport_global->outgoing_window <= 0;
+  GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("parsed", transport_global, outgoing_window,
+                                  transport_parsing, outgoing_window);
+  is_zero = transport_global->outgoing_window <= 0;
+  if (was_zero && !is_zero) {
+    while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
+                                                     &stream_global)) {
+      grpc_chttp2_become_writable(transport_global, stream_global);
+    }
+  }
+
+  if (transport_parsing->incoming_window <
+      transport_global->connection_window_target * 3 / 4) {
+    int64_t announce_bytes = transport_global->connection_window_target -
+                             transport_parsing->incoming_window;
+    GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_global,
+                                      announce_incoming_window, announce_bytes);
+    GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing,
+                                      incoming_window, announce_bytes);
+  }
+
+  /* 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)) {
+    if (stream_parsing->seen_error) {
+      stream_global->seen_error = 1;
+      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+    }
+
+    /* update outgoing flow control window */
+    was_zero = stream_global->outgoing_window <= 0;
+    GRPC_CHTTP2_FLOW_MOVE_STREAM("parsed", transport_global, stream_global,
+                                 outgoing_window, stream_parsing,
+                                 outgoing_window);
+    is_zero = stream_global->outgoing_window <= 0;
+    if (was_zero && !is_zero) {
+      grpc_chttp2_become_writable(transport_global, stream_global);
+    }
+
+    stream_global->max_recv_bytes -= (uint32_t)GPR_MIN(
+        stream_global->max_recv_bytes, stream_parsing->received_bytes);
+    stream_parsing->received_bytes = 0;
+
+    /* publish incoming stream ops */
+    if (stream_global->incoming_frames.tail != NULL) {
+      stream_global->incoming_frames.tail->is_tail = 0;
+    }
+    if (stream_parsing->data_parser.incoming_frames.head != NULL) {
+      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+    }
+    grpc_chttp2_incoming_frame_queue_merge(
+        &stream_global->incoming_frames,
+        &stream_parsing->data_parser.incoming_frames);
+    if (stream_global->incoming_frames.tail != NULL) {
+      stream_global->incoming_frames.tail->is_tail = 1;
+    }
+
+    if (!stream_global->published_initial_metadata &&
+        stream_parsing->got_metadata_on_parse[0]) {
+      stream_parsing->got_metadata_on_parse[0] = 0;
+      stream_global->published_initial_metadata = 1;
+      GPR_SWAP(grpc_chttp2_incoming_metadata_buffer,
+               stream_parsing->metadata_buffer[0],
+               stream_global->received_initial_metadata);
+      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+    }
+    if (!stream_global->published_trailing_metadata &&
+        stream_parsing->got_metadata_on_parse[1]) {
+      stream_parsing->got_metadata_on_parse[1] = 0;
+      stream_global->published_trailing_metadata = 1;
+      GPR_SWAP(grpc_chttp2_incoming_metadata_buffer,
+               stream_parsing->metadata_buffer[1],
+               stream_global->received_trailing_metadata);
+      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+    }
+
+    if (stream_parsing->saw_rst_stream) {
+      if (stream_parsing->rst_stream_reason != GRPC_CHTTP2_NO_ERROR) {
+        grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status(
+            (grpc_chttp2_error_code)stream_parsing->rst_stream_reason);
+        char *status_details;
+        gpr_slice slice_details;
+        gpr_asprintf(&status_details, "Received RST_STREAM err=%d",
+                     stream_parsing->rst_stream_reason);
+        slice_details = gpr_slice_from_copied_string(status_details);
+        gpr_free(status_details);
+        grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global,
+                                status_code, &slice_details);
+      }
+      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
+                                     1, 1);
+    }
+
+    if (stream_parsing->received_close) {
+      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
+                                     1, 0);
+    }
+  }
+}
+
+int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
+                             grpc_chttp2_transport_parsing *transport_parsing,
+                             gpr_slice slice) {
+  uint8_t *beg = GPR_SLICE_START_PTR(slice);
+  uint8_t *end = GPR_SLICE_END_PTR(slice);
+  uint8_t *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)(uint8_t)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 = ((uint32_t)*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 |= ((uint32_t)*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 = (((uint32_t)*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 |= ((uint32_t)*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 |= ((uint32_t)*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 |= ((uint32_t)*cur);
+      transport_parsing->deframe_state = GRPC_DTS_FRAME;
+      if (!init_frame_parser(exec_ctx, 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(exec_ctx, 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 ((uint32_t)(end - cur) == transport_parsing->incoming_frame_size) {
+        if (!parse_frame_slice(exec_ctx, transport_parsing,
+                               gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
+                                                    (size_t)(end - beg)),
+                               1)) {
+          return 0;
+        }
+        transport_parsing->deframe_state = GRPC_DTS_FH_0;
+        transport_parsing->incoming_stream = NULL;
+        return 1;
+      } else if ((uint32_t)(end - cur) >
+                 transport_parsing->incoming_frame_size) {
+        size_t cur_offset = (size_t)(cur - beg);
+        if (!parse_frame_slice(
+                exec_ctx, transport_parsing,
+                gpr_slice_sub_no_ref(
+                    slice, cur_offset,
+                    cur_offset + transport_parsing->incoming_frame_size),
+                1)) {
+          return 0;
+        }
+        cur += transport_parsing->incoming_frame_size;
+        transport_parsing->incoming_stream = NULL;
+        goto dts_fh_0; /* loop */
+      } else {
+        if (!parse_frame_slice(exec_ctx, transport_parsing,
+                               gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
+                                                    (size_t)(end - beg)),
+                               0)) {
+          return 0;
+        }
+        transport_parsing->incoming_frame_size -= (uint32_t)(end - cur);
+        return 1;
+      }
+      GPR_UNREACHABLE_CODE(return 0);
+  }
+
+  GPR_UNREACHABLE_CODE(return 0);
+}
+
+static int init_frame_parser(grpc_exec_ctx *exec_ctx,
+                             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(exec_ctx, transport_parsing, 1);
+  }
+  switch (transport_parsing->incoming_frame_type) {
+    case GRPC_CHTTP2_FRAME_DATA:
+      return init_data_frame_parser(exec_ctx, transport_parsing);
+    case GRPC_CHTTP2_FRAME_HEADER:
+      return init_header_frame_parser(exec_ctx, 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(exec_ctx, transport_parsing);
+    case GRPC_CHTTP2_FRAME_SETTINGS:
+      return init_settings_frame_parser(exec_ctx, transport_parsing);
+    case GRPC_CHTTP2_FRAME_WINDOW_UPDATE:
+      return init_window_update_frame_parser(exec_ctx, transport_parsing);
+    case GRPC_CHTTP2_FRAME_PING:
+      return init_ping_parser(exec_ctx, transport_parsing);
+    case GRPC_CHTTP2_FRAME_GOAWAY:
+      return init_goaway_parser(exec_ctx, transport_parsing);
+    default:
+      gpr_log(GPR_ERROR, "Unknown frame type %02x",
+              transport_parsing->incoming_frame_type);
+      return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
+  }
+}
+
+static grpc_chttp2_parse_error skip_parser(
+    grpc_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+    int is_header) {
+  if (is_header) {
+    uint8_t 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 =
+        (uint8_t)(is_eoh ? transport_parsing->header_eof : 0);
+  } else {
+    transport_parsing->parser = skip_parser;
+  }
+  return 1;
+}
+
+void grpc_chttp2_parsing_become_skip_parser(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
+  init_skip_frame_parser(
+      exec_ctx, transport_parsing,
+      transport_parsing->parser == grpc_chttp2_header_parser_parse);
+}
+
+static grpc_chttp2_parse_error update_incoming_window(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+    grpc_chttp2_stream_parsing *stream_parsing) {
+  uint32_t incoming_frame_size = transport_parsing->incoming_frame_size;
+  if (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 (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_FLOW_DEBIT_TRANSPORT("parse", transport_parsing, incoming_window,
+                                   incoming_frame_size);
+  GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", transport_parsing, stream_parsing,
+                                incoming_window, incoming_frame_size);
+  stream_parsing->received_bytes += 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_exec_ctx *exec_ctx, 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(exec_ctx, transport_parsing, 0);
+  if (err == GRPC_CHTTP2_PARSE_OK) {
+    err = update_incoming_window(exec_ctx, 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(exec_ctx, transport_parsing, 0);
+    case GRPC_CHTTP2_CONNECTION_ERROR:
+      return 0;
+  }
+  GPR_UNREACHABLE_CODE(return 0);
+}
+
+static void free_timeout(void *p) { gpr_free(p); }
+
+static void on_initial_header(void *tp, grpc_mdelem *md) {
+  grpc_chttp2_transport_parsing *transport_parsing = tp;
+  grpc_chttp2_stream_parsing *stream_parsing =
+      transport_parsing->incoming_stream;
+
+  GPR_TIMER_BEGIN("on_initial_header", 0);
+
+  GPR_ASSERT(stream_parsing);
+
+  GRPC_CHTTP2_IF_TRACING(gpr_log(
+      GPR_INFO, "HTTP:%d:HDR:%s: %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 == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
+    /* TODO(ctiller): check for a status like " 0" */
+    stream_parsing->seen_error = 1;
+  }
+
+  if (md->key == GRPC_MDSTR_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_TIMESPAN);
+      }
+      grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
+    }
+    grpc_chttp2_incoming_metadata_buffer_set_deadline(
+        &stream_parsing->metadata_buffer[0],
+        gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout));
+    GRPC_MDELEM_UNREF(md);
+  } else {
+    grpc_chttp2_incoming_metadata_buffer_add(
+        &stream_parsing->metadata_buffer[0], md);
+  }
+
+  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
+
+  GPR_TIMER_END("on_initial_header", 0);
+}
+
+static void on_trailing_header(void *tp, grpc_mdelem *md) {
+  grpc_chttp2_transport_parsing *transport_parsing = tp;
+  grpc_chttp2_stream_parsing *stream_parsing =
+      transport_parsing->incoming_stream;
+
+  GPR_TIMER_BEGIN("on_trailing_header", 0);
+
+  GPR_ASSERT(stream_parsing);
+
+  GRPC_CHTTP2_IF_TRACING(gpr_log(
+      GPR_INFO, "HTTP:%d:TRL:%s: %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 == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
+    /* TODO(ctiller): check for a status like " 0" */
+    stream_parsing->seen_error = 1;
+  }
+
+  grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->metadata_buffer[1],
+                                           md);
+
+  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
+
+  GPR_TIMER_END("on_trailing_header", 0);
+}
+
+static int init_header_frame_parser(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+    int is_continuation) {
+  uint8_t is_eoh = (transport_parsing->incoming_frame_flags &
+                    GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0;
+  int via_accept = 0;
+  grpc_chttp2_stream_parsing *stream_parsing;
+
+  /* TODO(ctiller): when to increment header_frames_received? */
+
+  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(exec_ctx, 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(exec_ctx, 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(exec_ctx, 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(exec_ctx, transport_parsing, 1);
+    }
+    stream_parsing = transport_parsing->incoming_stream =
+        grpc_chttp2_parsing_accept_stream(
+            exec_ctx, 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(exec_ctx, 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(exec_ctx, transport_parsing, 1);
+  }
+  transport_parsing->parser = grpc_chttp2_header_parser_parse;
+  transport_parsing->parser_data = &transport_parsing->hpack_parser;
+  switch (stream_parsing->header_frames_received) {
+    case 0:
+      transport_parsing->hpack_parser.on_header = on_initial_header;
+      break;
+    case 1:
+      transport_parsing->hpack_parser.on_header = on_trailing_header;
+      break;
+    case 2:
+      gpr_log(GPR_ERROR, "too many header frames received");
+      return init_skip_frame_parser(exec_ctx, transport_parsing, 1);
+  }
+  transport_parsing->hpack_parser.on_header_user_data = transport_parsing;
+  transport_parsing->hpack_parser.is_boundary = is_eoh;
+  transport_parsing->hpack_parser.is_eof =
+      (uint8_t)(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_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx,
+                            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_exec_ctx *exec_ctx, 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(exec_ctx, 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_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx, 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;
+    grpc_chttp2_hptbl_set_max_bytes(
+        &transport_parsing->hpack_parser.table,
+        transport_parsing->last_sent_max_table_size);
+  }
+  transport_parsing->parser = grpc_chttp2_settings_parser_parse;
+  transport_parsing->parser_data = &transport_parsing->simple.settings;
+  return ok;
+}
+
+/*
+static int is_window_update_legal(int64_t window_update, int64_t window) {
+  return window + window_update < MAX_WINDOW;
+}
+*/
+
+static int parse_frame_slice(grpc_exec_ctx *exec_ctx,
+                             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(exec_ctx, 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(exec_ctx, 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_UNREACHABLE_CODE(return 0);
+}
diff --git a/src/core/ext/transport/chttp2/transport/status_conversion.c b/src/core/ext/transport/chttp2/transport/status_conversion.c
new file mode 100644
index 0000000..5a79579
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/status_conversion.c
@@ -0,0 +1,109 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
+
+int grpc_chttp2_grpc_status_to_http2_error(grpc_status_code status) {
+  switch (status) {
+    case GRPC_STATUS_OK:
+      return GRPC_CHTTP2_NO_ERROR;
+    case GRPC_STATUS_CANCELLED:
+      return GRPC_CHTTP2_CANCEL;
+    case GRPC_STATUS_RESOURCE_EXHAUSTED:
+      return GRPC_CHTTP2_ENHANCE_YOUR_CALM;
+    case GRPC_STATUS_PERMISSION_DENIED:
+      return GRPC_CHTTP2_INADEQUATE_SECURITY;
+    case GRPC_STATUS_UNAVAILABLE:
+      return GRPC_CHTTP2_REFUSED_STREAM;
+    default:
+      return GRPC_CHTTP2_INTERNAL_ERROR;
+  }
+}
+
+grpc_status_code grpc_chttp2_http2_error_to_grpc_status(
+    grpc_chttp2_error_code error) {
+  switch (error) {
+    case GRPC_CHTTP2_NO_ERROR:
+      /* should never be received */
+      return GRPC_STATUS_INTERNAL;
+    case GRPC_CHTTP2_CANCEL:
+      return GRPC_STATUS_CANCELLED;
+    case GRPC_CHTTP2_ENHANCE_YOUR_CALM:
+      return GRPC_STATUS_RESOURCE_EXHAUSTED;
+    case GRPC_CHTTP2_INADEQUATE_SECURITY:
+      return GRPC_STATUS_PERMISSION_DENIED;
+    case GRPC_CHTTP2_REFUSED_STREAM:
+      return GRPC_STATUS_UNAVAILABLE;
+    default:
+      return GRPC_STATUS_INTERNAL;
+  }
+}
+
+grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status) {
+  switch (status) {
+    /* these HTTP2 status codes are called out explicitly in status.proto */
+    case 200:
+      return GRPC_STATUS_OK;
+    case 400:
+      return GRPC_STATUS_INVALID_ARGUMENT;
+    case 401:
+      return GRPC_STATUS_UNAUTHENTICATED;
+    case 403:
+      return GRPC_STATUS_PERMISSION_DENIED;
+    case 404:
+      return GRPC_STATUS_NOT_FOUND;
+    case 409:
+      return GRPC_STATUS_ABORTED;
+    case 412:
+      return GRPC_STATUS_FAILED_PRECONDITION;
+    case 429:
+      return GRPC_STATUS_RESOURCE_EXHAUSTED;
+    case 499:
+      return GRPC_STATUS_CANCELLED;
+    case 500:
+      return GRPC_STATUS_UNKNOWN;
+    case 501:
+      return GRPC_STATUS_UNIMPLEMENTED;
+    case 503:
+      return GRPC_STATUS_UNAVAILABLE;
+    case 504:
+      return GRPC_STATUS_DEADLINE_EXCEEDED;
+    /* everything else is unknown */
+    default:
+      return GRPC_STATUS_UNKNOWN;
+  }
+}
+
+int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status) {
+  return 200;
+}
diff --git a/src/core/ext/transport/chttp2/transport/status_conversion.h b/src/core/ext/transport/chttp2/transport/status_conversion.h
new file mode 100644
index 0000000..e92a5f6
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/status_conversion.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STATUS_CONVERSION_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STATUS_CONVERSION_H
+
+#include <grpc/grpc.h>
+#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
+
+/* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */
+grpc_chttp2_error_code grpc_chttp2_grpc_status_to_http2_error(
+    grpc_status_code status);
+grpc_status_code grpc_chttp2_http2_error_to_grpc_status(
+    grpc_chttp2_error_code error);
+
+/* Conversion of HTTP status codes (:status) to grpc status codes */
+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_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STATUS_CONVERSION_H */
diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.c b/src/core/ext/transport/chttp2/transport/stream_lists.c
new file mode 100644
index 0000000..01ed49b
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/stream_lists.c
@@ -0,0 +1,442 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/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 bool 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);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+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 {
+    t->lists[id].head = s;
+  }
+  t->lists[id].tail = s;
+  s->included[id] = 1;
+}
+
+static bool stream_list_add(grpc_chttp2_transport *t, grpc_chttp2_stream *s,
+                            grpc_chttp2_stream_list_id id) {
+  if (s->included[id]) {
+    return false;
+  }
+  stream_list_add_tail(t, s, id);
+  return true;
+}
+
+/* wrappers for specializations */
+
+bool grpc_chttp2_list_add_writable_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  GPR_ASSERT(stream_global->id != 0);
+  return 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);
+  if (r != 0) {
+    *stream_global = &stream->global;
+    *stream_writing = &stream->writing;
+  }
+  return r;
+}
+
+bool grpc_chttp2_list_remove_writable_stream(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
+                                  STREAM_FROM_GLOBAL(stream_global),
+                                  GRPC_CHTTP2_LIST_WRITABLE);
+}
+
+void grpc_chttp2_list_add_writing_stream(
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_writing *stream_writing) {
+  GPR_ASSERT(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);
+  if (r != 0) {
+    *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);
+  if (r != 0) {
+    *stream_global = &stream->global;
+    *stream_writing = &stream->writing;
+  }
+  return r;
+}
+
+void grpc_chttp2_list_add_unannounced_incoming_window_available(
+    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_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE);
+}
+
+void grpc_chttp2_list_remove_unannounced_incoming_window_available(
+    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_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE);
+}
+
+int grpc_chttp2_list_pop_unannounced_incoming_window_available(
+    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_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE);
+  if (r != 0) {
+    *stream_global = &stream->global;
+    *stream_parsing = &stream->parsing;
+  }
+  return r;
+}
+
+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);
+  if (r != 0) {
+    *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);
+  if (r != 0) {
+    *stream_global = &stream->global;
+  }
+  return r;
+}
+
+void grpc_chttp2_list_add_check_read_ops(
+    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_CHECK_READ_OPS);
+}
+
+int grpc_chttp2_list_pop_check_read_ops(
+    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_CHECK_READ_OPS);
+  if (r != 0) {
+    *stream_global = &stream->global;
+  }
+  return r;
+}
+
+void grpc_chttp2_list_add_writing_stalled_by_transport(
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_chttp2_stream_writing *stream_writing) {
+  grpc_chttp2_stream *stream = STREAM_FROM_WRITING(stream_writing);
+  if (!stream->included[GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT]) {
+    GRPC_CHTTP2_STREAM_REF(&stream->global, "chttp2_writing_stalled");
+  }
+  stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), stream,
+                  GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT);
+}
+
+void grpc_chttp2_list_flush_writing_stalled_by_transport(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
+    bool is_window_available) {
+  grpc_chttp2_stream *stream;
+  grpc_chttp2_transport *transport = TRANSPORT_FROM_WRITING(transport_writing);
+  while (stream_list_pop(transport, &stream,
+                         GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) {
+    if (is_window_available) {
+      grpc_chttp2_become_writable(&transport->global, &stream->global);
+    } else {
+      grpc_chttp2_list_add_stalled_by_transport(transport_writing,
+                                                &stream->writing);
+    }
+    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &stream->global,
+                             "chttp2_writing_stalled");
+  }
+}
+
+void grpc_chttp2_list_add_stalled_by_transport(
+    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_STALLED_BY_TRANSPORT);
+}
+
+int grpc_chttp2_list_pop_stalled_by_transport(
+    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_STALLED_BY_TRANSPORT);
+  if (r != 0) {
+    *stream_global = &stream->global;
+  }
+  return r;
+}
+
+void grpc_chttp2_list_remove_stalled_by_transport(
+    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_STALLED_BY_TRANSPORT);
+}
+
+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);
+  if (r != 0) {
+    *stream_global = &stream->global;
+  }
+  return r;
+}
+
+void grpc_chttp2_list_add_closed_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_CLOSED_WAITING_FOR_WRITING);
+}
+
+int grpc_chttp2_list_pop_closed_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_CLOSED_WAITING_FOR_WRITING);
+  if (r != 0) {
+    *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/ext/transport/chttp2/transport/stream_map.c b/src/core/ext/transport/chttp2/transport/stream_map.c
new file mode 100644
index 0000000..3fb1389
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/stream_map.c
@@ -0,0 +1,197 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/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) {
+  GPR_ASSERT(initial_capacity > 1);
+  map->keys = gpr_malloc(sizeof(uint32_t) * initial_capacity);
+  map->values = gpr_malloc(sizeof(void *) * initial_capacity);
+  map->count = 0;
+  map->free = 0;
+  map->capacity = initial_capacity;
+}
+
+void grpc_chttp2_stream_map_destroy(grpc_chttp2_stream_map *map) {
+  gpr_free(map->keys);
+  gpr_free(map->values);
+}
+
+static size_t compact(uint32_t *keys, void **values, size_t count) {
+  size_t i, out;
+
+  for (i = 0, out = 0; i < count; i++) {
+    if (values[i]) {
+      keys[out] = keys[i];
+      values[out] = values[i];
+      out++;
+    }
+  }
+
+  return out;
+}
+
+void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, uint32_t key,
+                                void *value) {
+  size_t count = map->count;
+  size_t capacity = map->capacity;
+  uint32_t *keys = map->keys;
+  void **values = map->values;
+
+  GPR_ASSERT(count == 0 || keys[count - 1] < key);
+  GPR_ASSERT(value);
+
+  if (count == capacity) {
+    if (map->free > capacity / 4) {
+      count = compact(keys, values, count);
+      map->free = 0;
+    } else {
+      /* resize when less than 25% of the table is free, because compaction
+         won't help much */
+      map->capacity = capacity = 3 * capacity / 2;
+      map->keys = keys = gpr_realloc(keys, capacity * sizeof(uint32_t));
+      map->values = values = gpr_realloc(values, capacity * sizeof(void *));
+    }
+  }
+
+  keys[count] = key;
+  values[count] = value;
+  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(uint32_t));
+    dst->values = gpr_realloc(dst->values, dst->capacity * sizeof(void *));
+  }
+  memcpy(dst->keys + dst->count, src->keys, src->count * sizeof(uint32_t));
+  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, uint32_t key) {
+  size_t min_idx = 0;
+  size_t max_idx = map->count;
+  size_t mid_idx;
+  uint32_t *keys = map->keys;
+  void **values = map->values;
+  uint32_t mid_key;
+
+  if (max_idx == 0) return NULL;
+
+  while (min_idx < max_idx) {
+    /* find the midpoint, avoiding overflow */
+    mid_idx = min_idx + ((max_idx - min_idx) / 2);
+    mid_key = keys[mid_idx];
+
+    if (mid_key < key) {
+      min_idx = mid_idx + 1;
+    } else if (mid_key > key) {
+      max_idx = mid_idx;
+    } else /* mid_key == key */
+    {
+      return &values[mid_idx];
+    }
+  }
+
+  return NULL;
+}
+
+void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, uint32_t key) {
+  void **pvalue = find(map, key);
+  void *out = NULL;
+  if (pvalue != NULL) {
+    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;
+}
+
+void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, uint32_t key) {
+  void **pvalue = find(map, key);
+  return pvalue != NULL ? *pvalue : NULL;
+}
+
+size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map) {
+  return map->count - map->free;
+}
+
+void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map,
+                                     void (*f)(void *user_data, uint32_t key,
+                                               void *value),
+                                     void *user_data) {
+  size_t i;
+
+  for (i = 0; i < map->count; i++) {
+    if (map->values[i]) {
+      f(user_data, map->keys[i], map->values[i]);
+    }
+  }
+}
diff --git a/src/core/ext/transport/chttp2/transport/stream_map.h b/src/core/ext/transport/chttp2/transport/stream_map.h
new file mode 100644
index 0000000..4e8586f
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/stream_map.h
@@ -0,0 +1,84 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STREAM_MAP_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STREAM_MAP_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stddef.h>
+
+/* Data structure to map a uint32_t to a data object (represented by a void*)
+
+   Represented as a sorted array of keys, and a corresponding array of values.
+   Lookups are performed with binary search.
+   Adds are restricted to strictly higher keys than previously seen (this is
+   guaranteed by http2). */
+typedef struct {
+  uint32_t *keys;
+  void **values;
+  size_t count;
+  size_t free;
+  size_t capacity;
+} grpc_chttp2_stream_map;
+
+void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map *map,
+                                 size_t initial_capacity);
+void grpc_chttp2_stream_map_destroy(grpc_chttp2_stream_map *map);
+
+/* Add a new key: given http2 semantics, new keys must always be greater than
+   existing keys - this is asserted */
+void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, uint32_t key,
+                                void *value);
+
+/* Delete an existing key - returns the previous value of the key if it existed,
+   or NULL otherwise */
+void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, uint32_t 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, uint32_t key);
+
+/* How many (populated) entries are in the stream map? */
+size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map);
+
+/* Callback on each stream */
+void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map,
+                                     void (*f)(void *user_data, uint32_t key,
+                                               void *value),
+                                     void *user_data);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STREAM_MAP_H */
diff --git a/src/core/ext/transport/chttp2/transport/timeout_encoding.c b/src/core/ext/transport/chttp2/transport/timeout_encoding.c
new file mode 100644
index 0000000..d5b9da9
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/timeout_encoding.c
@@ -0,0 +1,188 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/port_platform.h>
+#include "src/core/lib/support/string.h"
+
+static int64_t round_up(int64_t x, int64_t divisor) {
+  return (x / divisor + (x % divisor != 0)) * divisor;
+}
+
+/* round an integer up to the next value with three significant figures */
+static int64_t round_up_to_three_sig_figs(int64_t x) {
+  if (x < 1000) return x;
+  if (x < 10000) return round_up(x, 10);
+  if (x < 100000) return round_up(x, 100);
+  if (x < 1000000) return round_up(x, 1000);
+  if (x < 10000000) return round_up(x, 10000);
+  if (x < 100000000) return round_up(x, 100000);
+  if (x < 1000000000) return round_up(x, 1000000);
+  return round_up(x, 10000000);
+}
+
+/* encode our minimum viable timeout value */
+static void enc_tiny(char *buffer) { memcpy(buffer, "1n", 3); }
+
+static void enc_ext(char *buffer, int64_t value, char ext) {
+  int n = int64_ttoa(value, buffer);
+  buffer[n] = ext;
+  buffer[n + 1] = 0;
+}
+
+static void enc_seconds(char *buffer, int64_t sec) {
+  if (sec % 3600 == 0) {
+    enc_ext(buffer, sec / 3600, 'H');
+  } else if (sec % 60 == 0) {
+    enc_ext(buffer, sec / 60, 'M');
+  } else {
+    enc_ext(buffer, sec, 'S');
+  }
+}
+
+static void enc_nanos(char *buffer, int64_t x) {
+  x = round_up_to_three_sig_figs(x);
+  if (x < 100000) {
+    if (x % 1000 == 0) {
+      enc_ext(buffer, x / 1000, 'u');
+    } else {
+      enc_ext(buffer, x, 'n');
+    }
+  } else if (x < 100000000) {
+    if (x % 1000000 == 0) {
+      enc_ext(buffer, x / 1000000, 'm');
+    } else {
+      enc_ext(buffer, x / 1000, 'u');
+    }
+  } else if (x < 1000000000) {
+    enc_ext(buffer, x / 1000000, 'm');
+  } else {
+    /* note that this is only ever called with times of less than one second,
+       so if we reach here the time must have been rounded up to a whole second
+       (and no more) */
+    memcpy(buffer, "1S", 3);
+  }
+}
+
+static void enc_micros(char *buffer, int64_t x) {
+  x = round_up_to_three_sig_figs(x);
+  if (x < 100000) {
+    if (x % 1000 == 0) {
+      enc_ext(buffer, x / 1000, 'm');
+    } else {
+      enc_ext(buffer, x, 'u');
+    }
+  } else if (x < 100000000) {
+    if (x % 1000000 == 0) {
+      enc_ext(buffer, x / 1000000, 'S');
+    } else {
+      enc_ext(buffer, x / 1000, 'm');
+    }
+  } else {
+    enc_ext(buffer, x / 1000000, 'S');
+  }
+}
+
+void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer) {
+  if (timeout.tv_sec < 0) {
+    enc_tiny(buffer);
+  } else if (timeout.tv_sec == 0) {
+    enc_nanos(buffer, timeout.tv_nsec);
+  } else if (timeout.tv_sec < 1000 && timeout.tv_nsec != 0) {
+    enc_micros(buffer,
+               (int64_t)(timeout.tv_sec * 1000000) +
+                   (timeout.tv_nsec / 1000 + (timeout.tv_nsec % 1000 != 0)));
+  } else {
+    enc_seconds(buffer, timeout.tv_sec + (timeout.tv_nsec != 0));
+  }
+}
+
+static int is_all_whitespace(const char *p) {
+  while (*p == ' ') p++;
+  return *p == 0;
+}
+
+int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout) {
+  int32_t x = 0;
+  const uint8_t *p = (const uint8_t *)buffer;
+  int have_digit = 0;
+  /* skip whitespace */
+  for (; *p == ' '; p++)
+    ;
+  /* decode numeric part */
+  for (; *p >= '0' && *p <= '9'; p++) {
+    int32_t digit = (int32_t)(*p - (uint8_t)'0');
+    have_digit = 1;
+    /* spec allows max. 8 digits, but we allow values up to 1,000,000,000 */
+    if (x >= (100 * 1000 * 1000)) {
+      if (x != (100 * 1000 * 1000) || digit != 0) {
+        *timeout = gpr_inf_future(GPR_TIMESPAN);
+        return 1;
+      }
+    }
+    x = x * 10 + digit;
+  }
+  if (!have_digit) return 0;
+  /* skip whitespace */
+  for (; *p == ' '; p++)
+    ;
+  /* decode unit specifier */
+  switch (*p) {
+    case 'n':
+      *timeout = gpr_time_from_nanos(x, GPR_TIMESPAN);
+      break;
+    case 'u':
+      *timeout = gpr_time_from_micros(x, GPR_TIMESPAN);
+      break;
+    case 'm':
+      *timeout = gpr_time_from_millis(x, GPR_TIMESPAN);
+      break;
+    case 'S':
+      *timeout = gpr_time_from_seconds(x, GPR_TIMESPAN);
+      break;
+    case 'M':
+      *timeout = gpr_time_from_minutes(x, GPR_TIMESPAN);
+      break;
+    case 'H':
+      *timeout = gpr_time_from_hours(x, GPR_TIMESPAN);
+      break;
+    default:
+      return 0;
+  }
+  p++;
+  return is_all_whitespace((const char *)p);
+}
diff --git a/src/core/ext/transport/chttp2/transport/timeout_encoding.h b/src/core/ext/transport/chttp2/transport/timeout_encoding.h
new file mode 100644
index 0000000..dc64f9c
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/timeout_encoding.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
+
+#include <grpc/support/time.h>
+#include "src/core/lib/support/string.h"
+
+#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
+
+/* Encode/decode timeouts to the GRPC over HTTP2 format;
+   encoding may round up arbitrarily */
+void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);
+int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H */
diff --git a/src/core/ext/transport/chttp2/transport/varint.c b/src/core/ext/transport/chttp2/transport/varint.c
new file mode 100644
index 0000000..6721d04
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/varint.c
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/varint.h"
+
+uint32_t grpc_chttp2_hpack_varint_length(uint32_t tail_value) {
+  if (tail_value < (1 << 7)) {
+    return 2;
+  } else if (tail_value < (1 << 14)) {
+    return 3;
+  } else if (tail_value < (1 << 21)) {
+    return 4;
+  } else if (tail_value < (1 << 28)) {
+    return 5;
+  } else {
+    return 6;
+  }
+}
+
+void grpc_chttp2_hpack_write_varint_tail(uint32_t tail_value, uint8_t* target,
+                                         uint32_t tail_length) {
+  switch (tail_length) {
+    case 5:
+      target[4] = (uint8_t)((tail_value >> 28) | 0x80);
+    case 4:
+      target[3] = (uint8_t)((tail_value >> 21) | 0x80);
+    case 3:
+      target[2] = (uint8_t)((tail_value >> 14) | 0x80);
+    case 2:
+      target[1] = (uint8_t)((tail_value >> 7) | 0x80);
+    case 1:
+      target[0] = (uint8_t)((tail_value) | 0x80);
+  }
+  target[tail_length - 1] &= 0x7f;
+}
diff --git a/src/core/ext/transport/chttp2/transport/varint.h b/src/core/ext/transport/chttp2/transport/varint.h
new file mode 100644
index 0000000..6442ea3
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/varint.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_VARINT_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_VARINT_H
+
+#include <grpc/support/port_platform.h>
+
+/* Helpers for hpack varint encoding */
+
+/* length of a value that needs varint tail encoding (it's bigger than can be
+   bitpacked into the opcode byte) - returned value includes the length of the
+   opcode byte */
+uint32_t grpc_chttp2_hpack_varint_length(uint32_t tail_value);
+
+void grpc_chttp2_hpack_write_varint_tail(uint32_t tail_value, uint8_t* target,
+                                         uint32_t tail_length);
+
+/* maximum value that can be bitpacked with the opcode if the opcode has a
+   prefix
+   of length prefix_bits */
+#define GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits) \
+  ((uint32_t)((1 << (8 - (prefix_bits))) - 1))
+
+/* length required to bitpack a value */
+#define GRPC_CHTTP2_VARINT_LENGTH(n, prefix_bits) \
+  ((n) < GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits)   \
+       ? 1u                                       \
+       : grpc_chttp2_hpack_varint_length(         \
+             (n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits)))
+
+#define GRPC_CHTTP2_WRITE_VARINT(n, prefix_bits, prefix_or, target, length)   \
+  do {                                                                        \
+    uint8_t* tgt = target;                                                    \
+    if ((length) == 1u) {                                                     \
+      (tgt)[0] = (uint8_t)((prefix_or) | (n));                                \
+    } else {                                                                  \
+      (tgt)[0] =                                                              \
+          (prefix_or) | (uint8_t)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_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_VARINT_H */
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
new file mode 100644
index 0000000..8d5886f
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -0,0 +1,350 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/internal.h"
+
+#include <limits.h>
+
+#include <grpc/support/log.h>
+
+#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
+#include "src/core/lib/profiling/timers.h"
+
+static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
+                            grpc_chttp2_transport_writing *transport_writing);
+
+int grpc_chttp2_unlocking_check_writes(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_transport_writing *transport_writing, int is_parsing) {
+  grpc_chttp2_stream_global *stream_global;
+  grpc_chttp2_stream_writing *stream_writing;
+
+  GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0);
+
+  /* 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);
+
+  grpc_chttp2_hpack_compressor_set_max_table_size(
+      &transport_writing->hpack_compressor,
+      transport_global->settings[GRPC_PEER_SETTINGS]
+                                [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
+
+  if (transport_global->dirtied_local_settings &&
+      !transport_global->sent_local_settings && !is_parsing) {
+    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;
+  }
+
+  GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
+                                  transport_global, outgoing_window);
+  bool is_window_available = transport_writing->outgoing_window > 0;
+  grpc_chttp2_list_flush_writing_stalled_by_transport(
+      exec_ctx, transport_writing, is_window_available);
+
+  /* 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)) {
+    bool sent_initial_metadata = stream_writing->sent_initial_metadata;
+    bool become_writable = false;
+
+    stream_writing->id = stream_global->id;
+    stream_writing->read_closed = stream_global->read_closed;
+
+    GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_writing, stream_writing,
+                                 outgoing_window, stream_global,
+                                 outgoing_window);
+
+    if (!sent_initial_metadata && stream_global->send_initial_metadata) {
+      stream_writing->send_initial_metadata =
+          stream_global->send_initial_metadata;
+      stream_global->send_initial_metadata = NULL;
+      become_writable = true;
+      sent_initial_metadata = true;
+    }
+    if (sent_initial_metadata) {
+      if (stream_global->send_message != NULL) {
+        gpr_slice hdr = gpr_slice_malloc(5);
+        uint8_t *p = GPR_SLICE_START_PTR(hdr);
+        uint32_t len = stream_global->send_message->length;
+        GPR_ASSERT(stream_writing->send_message == NULL);
+        p[0] = (stream_global->send_message->flags &
+                GRPC_WRITE_INTERNAL_COMPRESS) != 0;
+        p[1] = (uint8_t)(len >> 24);
+        p[2] = (uint8_t)(len >> 16);
+        p[3] = (uint8_t)(len >> 8);
+        p[4] = (uint8_t)(len);
+        gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, hdr);
+        if (stream_global->send_message->length > 0) {
+          stream_writing->send_message = stream_global->send_message;
+        } else {
+          stream_writing->send_message = NULL;
+        }
+        stream_writing->stream_fetched = 0;
+        stream_global->send_message = NULL;
+      }
+      if ((stream_writing->send_message != NULL ||
+           stream_writing->flow_controlled_buffer.length > 0) &&
+          stream_writing->outgoing_window > 0) {
+        if (transport_writing->outgoing_window > 0) {
+          become_writable = true;
+        } else {
+          grpc_chttp2_list_add_stalled_by_transport(transport_writing,
+                                                    stream_writing);
+        }
+      }
+      if (stream_global->send_trailing_metadata) {
+        stream_writing->send_trailing_metadata =
+            stream_global->send_trailing_metadata;
+        stream_global->send_trailing_metadata = NULL;
+        become_writable = true;
+      }
+    }
+
+    if (!stream_global->read_closed &&
+        stream_global->unannounced_incoming_window_for_writing > 1024) {
+      GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing,
+                                   announce_window, stream_global,
+                                   unannounced_incoming_window_for_writing);
+      become_writable = true;
+    }
+
+    if (become_writable) {
+      grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
+    } else {
+      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_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->announce_incoming_window > 0) {
+    uint32_t announced = (uint32_t)GPR_MIN(
+        transport_global->announce_incoming_window, UINT32_MAX);
+    GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_global,
+                                     announce_incoming_window, announced);
+    gpr_slice_buffer_add(&transport_writing->outbuf,
+                         grpc_chttp2_window_update_create(0, announced));
+  }
+
+  GPR_TIMER_END("grpc_chttp2_unlocking_check_writes", 0);
+
+  return transport_writing->outbuf.count > 0 ||
+         grpc_chttp2_list_have_writing_streams(transport_writing);
+}
+
+void grpc_chttp2_perform_writes(
+    grpc_exec_ctx *exec_ctx, 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(exec_ctx, transport_writing);
+
+  GPR_ASSERT(endpoint);
+
+  if (transport_writing->outbuf.count > 0) {
+    grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf,
+                        &transport_writing->done_cb);
+  } else {
+    grpc_exec_ctx_enqueue(exec_ctx, &transport_writing->done_cb, true, NULL);
+  }
+}
+
+static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
+                            grpc_chttp2_transport_writing *transport_writing) {
+  grpc_chttp2_stream_writing *stream_writing;
+
+  GPR_TIMER_BEGIN("finalize_outbuf", 0);
+
+  while (
+      grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) {
+    uint32_t max_outgoing =
+        (uint32_t)GPR_MIN(GRPC_CHTTP2_MAX_PAYLOAD_LENGTH,
+                          GPR_MIN(stream_writing->outgoing_window,
+                                  transport_writing->outgoing_window));
+    /* send initial metadata if it's available */
+    if (stream_writing->send_initial_metadata != NULL) {
+      grpc_chttp2_encode_header(
+          &transport_writing->hpack_compressor, stream_writing->id,
+          stream_writing->send_initial_metadata, 0, &transport_writing->outbuf);
+      stream_writing->send_initial_metadata = NULL;
+      stream_writing->sent_initial_metadata = 1;
+    }
+    /* send any window updates */
+    if (stream_writing->announce_window > 0 &&
+        stream_writing->send_initial_metadata == NULL) {
+      uint32_t announce = stream_writing->announce_window;
+      gpr_slice_buffer_add(
+          &transport_writing->outbuf,
+          grpc_chttp2_window_update_create(stream_writing->id,
+                                           stream_writing->announce_window));
+      GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing, stream_writing,
+                                    announce_window, announce);
+      stream_writing->announce_window = 0;
+    }
+    /* fetch any body bytes */
+    while (!stream_writing->fetching && stream_writing->send_message &&
+           stream_writing->flow_controlled_buffer.length < max_outgoing &&
+           stream_writing->stream_fetched <
+               stream_writing->send_message->length) {
+      if (grpc_byte_stream_next(exec_ctx, stream_writing->send_message,
+                                &stream_writing->fetching_slice, max_outgoing,
+                                &stream_writing->finished_fetch)) {
+        stream_writing->stream_fetched +=
+            GPR_SLICE_LENGTH(stream_writing->fetching_slice);
+        if (stream_writing->stream_fetched ==
+            stream_writing->send_message->length) {
+          stream_writing->send_message = NULL;
+        }
+        gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer,
+                             stream_writing->fetching_slice);
+      } else {
+        stream_writing->fetching = 1;
+      }
+    }
+    /* send any body bytes */
+    if (stream_writing->flow_controlled_buffer.length > 0) {
+      if (max_outgoing > 0) {
+        uint32_t send_bytes = (uint32_t)GPR_MIN(
+            max_outgoing, stream_writing->flow_controlled_buffer.length);
+        int is_last_data_frame =
+            stream_writing->send_message == NULL &&
+            send_bytes == stream_writing->flow_controlled_buffer.length;
+        int is_last_frame = is_last_data_frame &&
+                            stream_writing->send_trailing_metadata != NULL &&
+                            grpc_metadata_batch_is_empty(
+                                stream_writing->send_trailing_metadata);
+        grpc_chttp2_encode_data(
+            stream_writing->id, &stream_writing->flow_controlled_buffer,
+            send_bytes, is_last_frame, &transport_writing->outbuf);
+        GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing,
+                                      stream_writing, outgoing_window,
+                                      send_bytes);
+        GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_writing,
+                                         outgoing_window, send_bytes);
+        if (is_last_frame) {
+          stream_writing->send_trailing_metadata = NULL;
+          stream_writing->sent_trailing_metadata = 1;
+        }
+        if (is_last_data_frame) {
+          GPR_ASSERT(stream_writing->send_message == NULL);
+          stream_writing->sent_message = 1;
+        }
+      } else if (transport_writing->outgoing_window == 0) {
+        grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
+                                                          stream_writing);
+        grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
+      }
+    }
+    /* send trailing metadata if it's available and we're ready for it */
+    if (stream_writing->send_message == NULL &&
+        stream_writing->flow_controlled_buffer.length == 0 &&
+        stream_writing->send_trailing_metadata != NULL) {
+      if (grpc_metadata_batch_is_empty(
+              stream_writing->send_trailing_metadata)) {
+        grpc_chttp2_encode_data(stream_writing->id,
+                                &stream_writing->flow_controlled_buffer, 0, 1,
+                                &transport_writing->outbuf);
+      } else {
+        grpc_chttp2_encode_header(&transport_writing->hpack_compressor,
+                                  stream_writing->id,
+                                  stream_writing->send_trailing_metadata, 1,
+                                  &transport_writing->outbuf);
+      }
+      if (!transport_writing->is_client && !stream_writing->read_closed) {
+        gpr_slice_buffer_add(&transport_writing->outbuf,
+                             grpc_chttp2_rst_stream_create(
+                                 stream_writing->id, GRPC_CHTTP2_NO_ERROR));
+      }
+      stream_writing->send_trailing_metadata = NULL;
+      stream_writing->sent_trailing_metadata = 1;
+    }
+    /* if there's more to write, then loop, otherwise prepare to finish the
+     * write */
+    if ((stream_writing->flow_controlled_buffer.length > 0 ||
+         (stream_writing->send_message && !stream_writing->fetching)) &&
+        stream_writing->outgoing_window > 0) {
+      if (transport_writing->outgoing_window > 0) {
+        grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
+      } else {
+        grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
+                                                          stream_writing);
+        grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
+      }
+    } else {
+      grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
+    }
+  }
+
+  GPR_TIMER_END("finalize_outbuf", 0);
+}
+
+void grpc_chttp2_cleanup_writing(
+    grpc_exec_ctx *exec_ctx, 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_writing->sent_initial_metadata) {
+      grpc_chttp2_complete_closure_step(
+          exec_ctx, &stream_global->send_initial_metadata_finished, 1);
+    }
+    if (stream_writing->sent_message) {
+      GPR_ASSERT(stream_writing->send_message == NULL);
+      grpc_chttp2_complete_closure_step(
+          exec_ctx, &stream_global->send_message_finished, 1);
+      stream_writing->sent_message = 0;
+    }
+    if (stream_writing->sent_trailing_metadata) {
+      grpc_chttp2_complete_closure_step(
+          exec_ctx, &stream_global->send_trailing_metadata_finished, 1);
+    }
+    if (stream_writing->sent_trailing_metadata) {
+      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
+                                     !transport_global->is_client, 1);
+    }
+    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
+  }
+  gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf);
+}
diff --git a/src/core/httpcli/format_request.c b/src/core/httpcli/format_request.c
deleted file mode 100644
index 04f2a2d..0000000
--- a/src/core/httpcli/format_request.c
+++ /dev/null
@@ -1,120 +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/httpcli/format_request.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
-
-static void fill_common_header(const grpc_httpcli_request *request,
-                               gpr_strvec *buf) {
-  size_t i;
-  gpr_strvec_add(buf, gpr_strdup(request->path));
-  gpr_strvec_add(buf, gpr_strdup(" HTTP/1.0\r\n"));
-  /* just in case some crazy server really expects HTTP/1.1 */
-  gpr_strvec_add(buf, gpr_strdup("Host: "));
-  gpr_strvec_add(buf, gpr_strdup(request->host));
-  gpr_strvec_add(buf, gpr_strdup("\r\n"));
-  gpr_strvec_add(buf, gpr_strdup("Connection: close\r\n"));
-  gpr_strvec_add(buf,
-                 gpr_strdup("User-Agent: " GRPC_HTTPCLI_USER_AGENT "\r\n"));
-  /* user supplied headers */
-  for (i = 0; i < request->hdr_count; i++) {
-    gpr_strvec_add(buf, gpr_strdup(request->hdrs[i].key));
-    gpr_strvec_add(buf, gpr_strdup(": "));
-    gpr_strvec_add(buf, gpr_strdup(request->hdrs[i].value));
-    gpr_strvec_add(buf, gpr_strdup("\r\n"));
-  }
-}
-
-gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request) {
-  gpr_strvec out;
-  char *flat;
-  size_t flat_len;
-
-  gpr_strvec_init(&out);
-  gpr_strvec_add(&out, gpr_strdup("GET "));
-  fill_common_header(request, &out);
-  gpr_strvec_add(&out, gpr_strdup("\r\n"));
-
-  flat = gpr_strvec_flatten(&out, &flat_len);
-  gpr_strvec_destroy(&out);
-
-  return gpr_slice_new(flat, flat_len, gpr_free);
-}
-
-gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
-                                           const char *body_bytes,
-                                           size_t body_size) {
-  gpr_strvec out;
-  char *tmp;
-  size_t out_len;
-  size_t i;
-
-  gpr_strvec_init(&out);
-
-  gpr_strvec_add(&out, gpr_strdup("POST "));
-  fill_common_header(request, &out);
-  if (body_bytes) {
-    uint8_t has_content_type = 0;
-    for (i = 0; i < request->hdr_count; i++) {
-      if (strcmp(request->hdrs[i].key, "Content-Type") == 0) {
-        has_content_type = 1;
-        break;
-      }
-    }
-    if (!has_content_type) {
-      gpr_strvec_add(&out, gpr_strdup("Content-Type: text/plain\r\n"));
-    }
-    gpr_asprintf(&tmp, "Content-Length: %lu\r\n", (unsigned long)body_size);
-    gpr_strvec_add(&out, tmp);
-  }
-  gpr_strvec_add(&out, gpr_strdup("\r\n"));
-  tmp = gpr_strvec_flatten(&out, &out_len);
-  gpr_strvec_destroy(&out);
-
-  if (body_bytes) {
-    tmp = gpr_realloc(tmp, out_len + body_size);
-    memcpy(tmp + out_len, body_bytes, body_size);
-    out_len += body_size;
-  }
-
-  return gpr_slice_new(tmp, out_len, gpr_free);
-}
diff --git a/src/core/httpcli/format_request.h b/src/core/httpcli/format_request.h
deleted file mode 100644
index c8dc8f7..0000000
--- a/src/core/httpcli/format_request.h
+++ /dev/null
@@ -1,45 +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_HTTPCLI_FORMAT_REQUEST_H
-#define GRPC_INTERNAL_CORE_HTTPCLI_FORMAT_REQUEST_H
-
-#include "src/core/httpcli/httpcli.h"
-#include <grpc/support/slice.h>
-
-gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request);
-gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
-                                           const char *body_bytes,
-                                           size_t body_size);
-
-#endif /* GRPC_INTERNAL_CORE_HTTPCLI_FORMAT_REQUEST_H */
diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c
deleted file mode 100644
index 1219c44..0000000
--- a/src/core/httpcli/httpcli.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/httpcli/httpcli.h"
-#include "src/core/iomgr/sockaddr.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/httpcli/format_request.h"
-#include "src/core/httpcli/parser.h"
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/resolve_address.h"
-#include "src/core/iomgr/tcp_client.h"
-#include "src/core/support/string.h"
-
-typedef struct {
-  gpr_slice request_text;
-  grpc_httpcli_parser parser;
-  grpc_resolved_addresses *addresses;
-  size_t next_address;
-  grpc_endpoint *ep;
-  char *host;
-  char *ssl_host_override;
-  gpr_timespec deadline;
-  int have_read_byte;
-  const grpc_httpcli_handshaker *handshaker;
-  grpc_httpcli_response_cb on_response;
-  void *user_data;
-  grpc_httpcli_context *context;
-  grpc_pollset *pollset;
-  grpc_iomgr_object iomgr_obj;
-  gpr_slice_buffer incoming;
-  gpr_slice_buffer outgoing;
-  grpc_closure on_read;
-  grpc_closure done_write;
-  grpc_closure connected;
-} internal_request;
-
-static grpc_httpcli_get_override g_get_override = NULL;
-static grpc_httpcli_post_override g_post_override = NULL;
-
-static void plaintext_handshake(grpc_exec_ctx *exec_ctx, void *arg,
-                                grpc_endpoint *endpoint, const char *host,
-                                void (*on_done)(grpc_exec_ctx *exec_ctx,
-                                                void *arg,
-                                                grpc_endpoint *endpoint)) {
-  on_done(exec_ctx, arg, endpoint);
-}
-
-const grpc_httpcli_handshaker grpc_httpcli_plaintext = {"http",
-                                                        plaintext_handshake};
-
-void grpc_httpcli_context_init(grpc_httpcli_context *context) {
-  context->pollset_set = grpc_pollset_set_create();
-}
-
-void grpc_httpcli_context_destroy(grpc_httpcli_context *context) {
-  grpc_pollset_set_destroy(context->pollset_set);
-}
-
-static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req);
-
-static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
-                   int success) {
-  grpc_pollset_set_del_pollset(exec_ctx, req->context->pollset_set,
-                               req->pollset);
-  req->on_response(exec_ctx, req->user_data, success ? &req->parser.r : NULL);
-  grpc_httpcli_parser_destroy(&req->parser);
-  if (req->addresses != NULL) {
-    grpc_resolved_addresses_destroy(req->addresses);
-  }
-  if (req->ep != NULL) {
-    grpc_endpoint_destroy(exec_ctx, req->ep);
-  }
-  gpr_slice_unref(req->request_text);
-  gpr_free(req->host);
-  gpr_free(req->ssl_host_override);
-  grpc_iomgr_unregister_object(&req->iomgr_obj);
-  gpr_slice_buffer_destroy(&req->incoming);
-  gpr_slice_buffer_destroy(&req->outgoing);
-  gpr_free(req);
-}
-
-static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success);
-
-static void do_read(grpc_exec_ctx *exec_ctx, internal_request *req) {
-  grpc_endpoint_read(exec_ctx, req->ep, &req->incoming, &req->on_read);
-}
-
-static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
-  internal_request *req = user_data;
-  size_t i;
-
-  for (i = 0; i < req->incoming.count; i++) {
-    if (GPR_SLICE_LENGTH(req->incoming.slices[i])) {
-      req->have_read_byte = 1;
-      if (!grpc_httpcli_parser_parse(&req->parser, req->incoming.slices[i])) {
-        finish(exec_ctx, req, 0);
-        return;
-      }
-    }
-  }
-
-  if (success) {
-    do_read(exec_ctx, req);
-  } else if (!req->have_read_byte) {
-    next_address(exec_ctx, req);
-  } else {
-    finish(exec_ctx, req, grpc_httpcli_parser_eof(&req->parser));
-  }
-}
-
-static void on_written(grpc_exec_ctx *exec_ctx, internal_request *req) {
-  do_read(exec_ctx, req);
-}
-
-static void done_write(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  internal_request *req = arg;
-  if (success) {
-    on_written(exec_ctx, req);
-  } else {
-    next_address(exec_ctx, req);
-  }
-}
-
-static void start_write(grpc_exec_ctx *exec_ctx, internal_request *req) {
-  gpr_slice_ref(req->request_text);
-  gpr_slice_buffer_add(&req->outgoing, req->request_text);
-  grpc_endpoint_write(exec_ctx, req->ep, &req->outgoing, &req->done_write);
-}
-
-static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
-                              grpc_endpoint *ep) {
-  internal_request *req = arg;
-
-  if (!ep) {
-    next_address(exec_ctx, req);
-    return;
-  }
-
-  req->ep = ep;
-  start_write(exec_ctx, req);
-}
-
-static void on_connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  internal_request *req = arg;
-
-  if (!req->ep) {
-    next_address(exec_ctx, req);
-    return;
-  }
-  req->handshaker->handshake(
-      exec_ctx, req, req->ep,
-      req->ssl_host_override ? req->ssl_host_override : req->host,
-      on_handshake_done);
-}
-
-static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) {
-  grpc_resolved_address *addr;
-  if (req->next_address == req->addresses->naddrs) {
-    finish(exec_ctx, req, 0);
-    return;
-  }
-  addr = &req->addresses->addrs[req->next_address++];
-  grpc_closure_init(&req->connected, on_connected, req);
-  grpc_tcp_client_connect(
-      exec_ctx, &req->connected, &req->ep, req->context->pollset_set,
-      (struct sockaddr *)&addr->addr, addr->len, req->deadline);
-}
-
-static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
-                        grpc_resolved_addresses *addresses) {
-  internal_request *req = arg;
-  if (!addresses) {
-    finish(exec_ctx, req, 0);
-    return;
-  }
-  req->addresses = addresses;
-  req->next_address = 0;
-  next_address(exec_ctx, req);
-}
-
-static void internal_request_begin(
-    grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
-    grpc_pollset *pollset, const grpc_httpcli_request *request,
-    gpr_timespec deadline, grpc_httpcli_response_cb on_response,
-    void *user_data, const char *name, gpr_slice request_text) {
-  internal_request *req = gpr_malloc(sizeof(internal_request));
-  memset(req, 0, sizeof(*req));
-  req->request_text = request_text;
-  grpc_httpcli_parser_init(&req->parser);
-  req->on_response = on_response;
-  req->user_data = user_data;
-  req->deadline = deadline;
-  req->handshaker =
-      request->handshaker ? request->handshaker : &grpc_httpcli_plaintext;
-  req->context = context;
-  req->pollset = pollset;
-  grpc_closure_init(&req->on_read, on_read, req);
-  grpc_closure_init(&req->done_write, done_write, req);
-  gpr_slice_buffer_init(&req->incoming);
-  gpr_slice_buffer_init(&req->outgoing);
-  grpc_iomgr_register_object(&req->iomgr_obj, name);
-  req->host = gpr_strdup(request->host);
-  req->ssl_host_override = gpr_strdup(request->ssl_host_override);
-
-  grpc_pollset_set_add_pollset(exec_ctx, req->context->pollset_set,
-                               req->pollset);
-  grpc_resolve_address(request->host, req->handshaker->default_port,
-                       on_resolved, req);
-}
-
-void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
-                      grpc_pollset *pollset,
-                      const grpc_httpcli_request *request,
-                      gpr_timespec deadline,
-                      grpc_httpcli_response_cb on_response, void *user_data) {
-  char *name;
-  if (g_get_override &&
-      g_get_override(exec_ctx, request, deadline, on_response, user_data)) {
-    return;
-  }
-  gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path);
-  internal_request_begin(exec_ctx, context, pollset, request, deadline,
-                         on_response, user_data, name,
-                         grpc_httpcli_format_get_request(request));
-  gpr_free(name);
-}
-
-void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, 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) {
-  char *name;
-  if (g_post_override &&
-      g_post_override(exec_ctx, request, body_bytes, body_size, deadline,
-                      on_response, user_data)) {
-    return;
-  }
-  gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->path);
-  internal_request_begin(
-      exec_ctx, context, pollset, request, deadline, on_response, user_data,
-      name, grpc_httpcli_format_post_request(request, body_bytes, body_size));
-  gpr_free(name);
-}
-
-void grpc_httpcli_set_override(grpc_httpcli_get_override get,
-                               grpc_httpcli_post_override post) {
-  g_get_override = get;
-  g_post_override = post;
-}
diff --git a/src/core/httpcli/httpcli.h b/src/core/httpcli/httpcli.h
deleted file mode 100644
index c9cd987..0000000
--- a/src/core/httpcli/httpcli.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_H
-#define GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_H
-
-#include <stddef.h>
-
-#include <grpc/support/time.h>
-
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/iomgr/iomgr_internal.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' */
-#define GRPC_HTTPCLI_MAX_HEADER_LENGTH 4096
-
-/* A single header to be passed in a request */
-typedef struct grpc_httpcli_header {
-  char *key;
-  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;
-
-typedef struct {
-  const char *default_port;
-  void (*handshake)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint,
-                    const char *host,
-                    void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
-                                    grpc_endpoint *endpoint));
-} grpc_httpcli_handshaker;
-
-extern const grpc_httpcli_handshaker grpc_httpcli_plaintext;
-extern const grpc_httpcli_handshaker grpc_httpcli_ssl;
-
-/* A request */
-typedef struct grpc_httpcli_request {
-  /* The host name to connect to */
-  char *host;
-  /* The host to verify in the SSL handshake (or NULL) */
-  char *ssl_host_override;
-  /* The path of the resource to fetch */
-  char *path;
-  /* Additional headers: count and key/values; the following are supplied
-     automatically and MUST NOT be set here:
-     Host, Connection, User-Agent */
-  size_t hdr_count;
-  grpc_httpcli_header *hdrs;
-  /* handshaker to use ssl for the request */
-  const grpc_httpcli_handshaker *handshaker;
-} grpc_httpcli_request;
-
-/* A response */
-typedef struct grpc_httpcli_response {
-  /* HTTP status code */
-  int status;
-  /* Headers: count and key/values */
-  size_t hdr_count;
-  grpc_httpcli_header *hdrs;
-  /* Body: length and contents; contents are NOT null-terminated */
-  size_t body_length;
-  char *body;
-} grpc_httpcli_response;
-
-/* Callback for grpc_httpcli_get and grpc_httpcli_post. */
-typedef void (*grpc_httpcli_response_cb)(grpc_exec_ctx *exec_ctx,
-                                         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)
-   '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(grpc_exec_ctx *exec_ctx, 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.
-   '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(grpc_exec_ctx *exec_ctx, 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);
-
-/* override functions return 1 if they handled the request, 0 otherwise */
-typedef int (*grpc_httpcli_get_override)(grpc_exec_ctx *exec_ctx,
-                                         const grpc_httpcli_request *request,
-                                         gpr_timespec deadline,
-                                         grpc_httpcli_response_cb on_response,
-                                         void *user_data);
-typedef int (*grpc_httpcli_post_override)(
-    grpc_exec_ctx *exec_ctx, 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);
-
-void grpc_httpcli_set_override(grpc_httpcli_get_override get,
-                               grpc_httpcli_post_override post);
-
-#endif /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_H */
diff --git a/src/core/httpcli/httpcli_security_connector.c b/src/core/httpcli/httpcli_security_connector.c
deleted file mode 100644
index 156961a..0000000
--- a/src/core/httpcli/httpcli_security_connector.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/httpcli/httpcli.h"
-
-#include <string.h>
-
-#include "src/core/security/handshake.h"
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include "src/core/tsi/ssl_transport_security.h"
-
-typedef struct {
-  grpc_channel_security_connector base;
-  tsi_ssl_handshaker_factory *handshaker_factory;
-  char *secure_peer_name;
-} grpc_httpcli_ssl_channel_security_connector;
-
-static void httpcli_ssl_destroy(grpc_security_connector *sc) {
-  grpc_httpcli_ssl_channel_security_connector *c =
-      (grpc_httpcli_ssl_channel_security_connector *)sc;
-  if (c->handshaker_factory != NULL) {
-    tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
-  }
-  if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name);
-  gpr_free(sc);
-}
-
-static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
-                                     grpc_channel_security_connector *sc,
-                                     grpc_endpoint *nonsecure_endpoint,
-                                     grpc_security_handshake_done_cb cb,
-                                     void *user_data) {
-  grpc_httpcli_ssl_channel_security_connector *c =
-      (grpc_httpcli_ssl_channel_security_connector *)sc;
-  tsi_result result = TSI_OK;
-  tsi_handshaker *handshaker;
-  if (c->handshaker_factory == NULL) {
-    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
-    return;
-  }
-  result = tsi_ssl_handshaker_factory_create_handshaker(
-      c->handshaker_factory, c->secure_peer_name, &handshaker);
-  if (result != TSI_OK) {
-    gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
-            tsi_result_to_string(result));
-    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
-  } else {
-    grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
-                               nonsecure_endpoint, cb, user_data);
-  }
-}
-
-static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx,
-                                   grpc_security_connector *sc, tsi_peer peer,
-                                   grpc_security_peer_check_cb cb,
-                                   void *user_data) {
-  grpc_httpcli_ssl_channel_security_connector *c =
-      (grpc_httpcli_ssl_channel_security_connector *)sc;
-  grpc_security_status status = GRPC_SECURITY_OK;
-
-  /* Check the peer name. */
-  if (c->secure_peer_name != NULL &&
-      !tsi_ssl_peer_matches_name(&peer, c->secure_peer_name)) {
-    gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate",
-            c->secure_peer_name);
-    status = GRPC_SECURITY_ERROR;
-  }
-  cb(exec_ctx, user_data, status, NULL);
-  tsi_peer_destruct(&peer);
-}
-
-static grpc_security_connector_vtable httpcli_ssl_vtable = {
-    httpcli_ssl_destroy, httpcli_ssl_check_peer};
-
-static grpc_security_status httpcli_ssl_channel_security_connector_create(
-    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
-    const char *secure_peer_name, grpc_channel_security_connector **sc) {
-  tsi_result result = TSI_OK;
-  grpc_httpcli_ssl_channel_security_connector *c;
-
-  if (secure_peer_name != NULL && pem_root_certs == NULL) {
-    gpr_log(GPR_ERROR,
-            "Cannot assert a secure peer name without a trust root.");
-    return GRPC_SECURITY_ERROR;
-  }
-
-  c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_connector));
-  memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector));
-
-  gpr_ref_init(&c->base.base.refcount, 1);
-  c->base.base.vtable = &httpcli_ssl_vtable;
-  if (secure_peer_name != NULL) {
-    c->secure_peer_name = gpr_strdup(secure_peer_name);
-  }
-  result = tsi_create_ssl_client_handshaker_factory(
-      NULL, 0, NULL, 0, pem_root_certs, pem_root_certs_size, NULL, NULL, NULL,
-      0, &c->handshaker_factory);
-  if (result != TSI_OK) {
-    gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
-            tsi_result_to_string(result));
-    httpcli_ssl_destroy(&c->base.base);
-    *sc = NULL;
-    return GRPC_SECURITY_ERROR;
-  }
-  c->base.do_handshake = httpcli_ssl_do_handshake;
-  *sc = &c->base;
-  return GRPC_SECURITY_OK;
-}
-
-/* handshaker */
-
-typedef struct {
-  void (*func)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint);
-  void *arg;
-} on_done_closure;
-
-static void on_secure_transport_setup_done(grpc_exec_ctx *exec_ctx, void *rp,
-                                           grpc_security_status status,
-                                           grpc_endpoint *secure_endpoint,
-                                           grpc_auth_context *auth_context) {
-  on_done_closure *c = rp;
-  if (status != GRPC_SECURITY_OK) {
-    gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status);
-    c->func(exec_ctx, c->arg, NULL);
-  } else {
-    c->func(exec_ctx, c->arg, secure_endpoint);
-  }
-  gpr_free(c);
-}
-
-static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
-                          grpc_endpoint *tcp, const char *host,
-                          void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
-                                          grpc_endpoint *endpoint)) {
-  grpc_channel_security_connector *sc = NULL;
-  const unsigned char *pem_root_certs = NULL;
-  on_done_closure *c = gpr_malloc(sizeof(*c));
-  size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
-  if (pem_root_certs == NULL || pem_root_certs_size == 0) {
-    gpr_log(GPR_ERROR, "Could not get default pem root certs.");
-    on_done(exec_ctx, arg, NULL);
-    gpr_free(c);
-    return;
-  }
-  c->func = on_done;
-  c->arg = arg;
-  GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
-                 pem_root_certs, pem_root_certs_size, host, &sc) ==
-             GRPC_SECURITY_OK);
-  grpc_channel_security_connector_do_handshake(
-      exec_ctx, sc, tcp, on_secure_transport_setup_done, c);
-  GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
-}
-
-const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake};
diff --git a/src/core/httpcli/parser.c b/src/core/httpcli/parser.c
deleted file mode 100644
index c314f02..0000000
--- a/src/core/httpcli/parser.c
+++ /dev/null
@@ -1,211 +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/httpcli/parser.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-static int handle_response_line(grpc_httpcli_parser *parser) {
-  uint8_t *beg = parser->cur_line;
-  uint8_t *cur = beg;
-  uint8_t *end = beg + parser->cur_line_length;
-
-  if (cur == end || *cur++ != 'H') goto error;
-  if (cur == end || *cur++ != 'T') goto error;
-  if (cur == end || *cur++ != 'T') goto error;
-  if (cur == end || *cur++ != 'P') goto error;
-  if (cur == end || *cur++ != '/') goto error;
-  if (cur == end || *cur++ != '1') goto error;
-  if (cur == end || *cur++ != '.') goto error;
-  if (cur == end || *cur < '0' || *cur++ > '1') goto error;
-  if (cur == end || *cur++ != ' ') goto error;
-  if (cur == end || *cur < '1' || *cur++ > '9') goto error;
-  if (cur == end || *cur < '0' || *cur++ > '9') goto error;
-  if (cur == end || *cur < '0' || *cur++ > '9') goto error;
-  parser->r.status =
-      (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
-  if (cur == end || *cur++ != ' ') goto error;
-
-  /* we don't really care about the status code message */
-
-  return 1;
-
-error:
-  gpr_log(GPR_ERROR, "Failed parsing response line");
-  return 0;
-}
-
-static char *buf2str(void *buffer, size_t length) {
-  char *out = gpr_malloc(length + 1);
-  memcpy(out, buffer, length);
-  out[length] = 0;
-  return out;
-}
-
-static int add_header(grpc_httpcli_parser *parser) {
-  uint8_t *beg = parser->cur_line;
-  uint8_t *cur = beg;
-  uint8_t *end = beg + parser->cur_line_length;
-  grpc_httpcli_header hdr = {NULL, NULL};
-
-  GPR_ASSERT(cur != end);
-
-  if (*cur == ' ' || *cur == '\t') {
-    gpr_log(GPR_ERROR, "Continued header lines not supported yet");
-    goto error;
-  }
-
-  while (cur != end && *cur != ':') {
-    cur++;
-  }
-  if (cur == end) {
-    gpr_log(GPR_ERROR, "Didn't find ':' in header string");
-    goto error;
-  }
-  GPR_ASSERT(cur >= beg);
-  hdr.key = buf2str(beg, (size_t)(cur - beg));
-  cur++; /* skip : */
-
-  while (cur != end && (*cur == ' ' || *cur == '\t')) {
-    cur++;
-  }
-  GPR_ASSERT(end - cur >= 2);
-  hdr.value = buf2str(cur, (size_t)(end - cur) - 2);
-
-  if (parser->r.hdr_count == parser->hdr_capacity) {
-    parser->hdr_capacity =
-        GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2);
-    parser->r.hdrs = gpr_realloc(
-        parser->r.hdrs, parser->hdr_capacity * sizeof(*parser->r.hdrs));
-  }
-  parser->r.hdrs[parser->r.hdr_count++] = hdr;
-  return 1;
-
-error:
-  gpr_free(hdr.key);
-  gpr_free(hdr.value);
-  return 0;
-}
-
-static int finish_line(grpc_httpcli_parser *parser) {
-  switch (parser->state) {
-    case GRPC_HTTPCLI_INITIAL_RESPONSE:
-      if (!handle_response_line(parser)) {
-        return 0;
-      }
-      parser->state = GRPC_HTTPCLI_HEADERS;
-      break;
-    case GRPC_HTTPCLI_HEADERS:
-      if (parser->cur_line_length == 2) {
-        parser->state = GRPC_HTTPCLI_BODY;
-        break;
-      }
-      if (!add_header(parser)) {
-        return 0;
-      }
-      break;
-    case GRPC_HTTPCLI_BODY:
-      GPR_UNREACHABLE_CODE(return 0);
-  }
-
-  parser->cur_line_length = 0;
-  return 1;
-}
-
-static int addbyte(grpc_httpcli_parser *parser, uint8_t byte) {
-  switch (parser->state) {
-    case GRPC_HTTPCLI_INITIAL_RESPONSE:
-    case GRPC_HTTPCLI_HEADERS:
-      if (parser->cur_line_length >= GRPC_HTTPCLI_MAX_HEADER_LENGTH) {
-        gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded",
-                GRPC_HTTPCLI_MAX_HEADER_LENGTH);
-        return 0;
-      }
-      parser->cur_line[parser->cur_line_length] = byte;
-      parser->cur_line_length++;
-      if (parser->cur_line_length >= 2 &&
-          parser->cur_line[parser->cur_line_length - 2] == '\r' &&
-          parser->cur_line[parser->cur_line_length - 1] == '\n') {
-        return finish_line(parser);
-      } else {
-        return 1;
-      }
-      GPR_UNREACHABLE_CODE(return 0);
-    case GRPC_HTTPCLI_BODY:
-      if (parser->r.body_length == parser->body_capacity) {
-        parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2);
-        parser->r.body =
-            gpr_realloc((void *)parser->r.body, parser->body_capacity);
-      }
-      parser->r.body[parser->r.body_length] = (char)byte;
-      parser->r.body_length++;
-      return 1;
-  }
-  GPR_UNREACHABLE_CODE(return 0);
-}
-
-void grpc_httpcli_parser_init(grpc_httpcli_parser *parser) {
-  memset(parser, 0, sizeof(*parser));
-  parser->state = GRPC_HTTPCLI_INITIAL_RESPONSE;
-  parser->r.status = 500;
-}
-
-void grpc_httpcli_parser_destroy(grpc_httpcli_parser *parser) {
-  size_t i;
-  gpr_free(parser->r.body);
-  for (i = 0; i < parser->r.hdr_count; i++) {
-    gpr_free(parser->r.hdrs[i].key);
-    gpr_free(parser->r.hdrs[i].value);
-  }
-  gpr_free(parser->r.hdrs);
-}
-
-int grpc_httpcli_parser_parse(grpc_httpcli_parser *parser, gpr_slice slice) {
-  size_t i;
-
-  for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) {
-    if (!addbyte(parser, GPR_SLICE_START_PTR(slice)[i])) {
-      return 0;
-    }
-  }
-
-  return 1;
-}
-
-int grpc_httpcli_parser_eof(grpc_httpcli_parser *parser) {
-  return parser->state == GRPC_HTTPCLI_BODY;
-}
diff --git a/src/core/httpcli/parser.h b/src/core/httpcli/parser.h
deleted file mode 100644
index cd03836..0000000
--- a/src/core/httpcli/parser.h
+++ /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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_HTTPCLI_PARSER_H
-#define GRPC_INTERNAL_CORE_HTTPCLI_PARSER_H
-
-#include "src/core/httpcli/httpcli.h"
-#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-
-typedef enum {
-  GRPC_HTTPCLI_INITIAL_RESPONSE,
-  GRPC_HTTPCLI_HEADERS,
-  GRPC_HTTPCLI_BODY
-} grpc_httpcli_parser_state;
-
-typedef struct {
-  grpc_httpcli_parser_state state;
-
-  grpc_httpcli_response r;
-  size_t body_capacity;
-  size_t hdr_capacity;
-
-  uint8_t cur_line[GRPC_HTTPCLI_MAX_HEADER_LENGTH];
-  size_t cur_line_length;
-} grpc_httpcli_parser;
-
-void grpc_httpcli_parser_init(grpc_httpcli_parser* parser);
-void grpc_httpcli_parser_destroy(grpc_httpcli_parser* parser);
-
-int grpc_httpcli_parser_parse(grpc_httpcli_parser* parser, gpr_slice slice);
-int grpc_httpcli_parser_eof(grpc_httpcli_parser* parser);
-
-#endif /* GRPC_INTERNAL_CORE_HTTPCLI_PARSER_H */
diff --git a/src/core/iomgr/closure.c b/src/core/iomgr/closure.c
deleted file mode 100644
index 3a96f73..0000000
--- a/src/core/iomgr/closure.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/iomgr/closure.h"
-
-#include <grpc/support/alloc.h>
-
-void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
-                       void *cb_arg) {
-  closure->cb = cb;
-  closure->cb_arg = cb_arg;
-  closure->final_data = 0;
-}
-
-void grpc_closure_list_add(grpc_closure_list *closure_list,
-                           grpc_closure *closure, bool success) {
-  if (closure == NULL) return;
-  closure->final_data = (success != 0);
-  if (closure_list->head == NULL) {
-    closure_list->head = closure;
-  } else {
-    closure_list->tail->final_data |= (uintptr_t)closure;
-  }
-  closure_list->tail = closure;
-}
-
-bool grpc_closure_list_empty(grpc_closure_list closure_list) {
-  return closure_list.head == NULL;
-}
-
-void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst) {
-  if (src->head == NULL) {
-    return;
-  }
-  if (dst->head == NULL) {
-    *dst = *src;
-  } else {
-    dst->tail->final_data |= (uintptr_t)src->head;
-    dst->tail = src->tail;
-  }
-  src->head = src->tail = NULL;
-}
-
-typedef struct {
-  grpc_iomgr_cb_func cb;
-  void *cb_arg;
-  grpc_closure wrapper;
-} wrapped_closure;
-
-static void closure_wrapper(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  wrapped_closure *wc = arg;
-  grpc_iomgr_cb_func cb = wc->cb;
-  void *cb_arg = wc->cb_arg;
-  gpr_free(wc);
-  cb(exec_ctx, cb_arg, success);
-}
-
-grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) {
-  wrapped_closure *wc = gpr_malloc(sizeof(*wc));
-  wc->cb = cb;
-  wc->cb_arg = cb_arg;
-  grpc_closure_init(&wc->wrapper, closure_wrapper, wc);
-  return &wc->wrapper;
-}
-
-grpc_closure *grpc_closure_next(grpc_closure *closure) {
-  return (grpc_closure *)(closure->final_data & ~(uintptr_t)1);
-}
diff --git a/src/core/iomgr/closure.h b/src/core/iomgr/closure.h
deleted file mode 100644
index ea96c19..0000000
--- a/src/core/iomgr/closure.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_CLOSURE_H
-#define GRPC_INTERNAL_CORE_IOMGR_CLOSURE_H
-
-#include <grpc/support/port_platform.h>
-#include <stdbool.h>
-
-struct grpc_closure;
-typedef struct grpc_closure grpc_closure;
-
-/* forward declaration for exec_ctx.h */
-struct grpc_exec_ctx;
-typedef struct grpc_exec_ctx grpc_exec_ctx;
-
-typedef struct grpc_closure_list {
-  grpc_closure *head;
-  grpc_closure *tail;
-} grpc_closure_list;
-
-/** gRPC Callback definition.
- *
- * \param arg Arbitrary input.
- * \param success An indication on the state of the iomgr. On false, cleanup
- * actions should be taken (eg, shutdown). */
-typedef void (*grpc_iomgr_cb_func)(grpc_exec_ctx *exec_ctx, void *arg,
-                                   bool success);
-
-/** A closure over a grpc_iomgr_cb_func. */
-struct grpc_closure {
-  /** Bound callback. */
-  grpc_iomgr_cb_func cb;
-
-  /** Arguments to be passed to "cb". */
-  void *cb_arg;
-
-  /** Once enqueued, contains in the lower bit the success of the closure,
-      and in the upper bits the pointer to the next closure in the list.
-      Before enqueing for execution, this is usable for scratch data. */
-  uintptr_t final_data;
-};
-
-/** Initializes \a closure with \a cb and \a cb_arg. */
-void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
-                       void *cb_arg);
-
-/* Create a heap allocated closure: try to avoid except for very rare events */
-grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg);
-
-#define GRPC_CLOSURE_LIST_INIT \
-  { NULL, NULL }
-
-/** add \a closure to the end of \a list and set \a closure's success to \a
- * success */
-void grpc_closure_list_add(grpc_closure_list *list, grpc_closure *closure,
-                           bool success);
-
-/** append all closures from \a src to \a dst and empty \a src. */
-void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst);
-
-/** return whether \a list is empty. */
-bool grpc_closure_list_empty(grpc_closure_list list);
-
-/** return the next pointer for a queued closure list */
-grpc_closure *grpc_closure_next(grpc_closure *closure);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_CLOSURE_H */
diff --git a/src/core/iomgr/endpoint.c b/src/core/iomgr/endpoint.c
deleted file mode 100644
index bd64707..0000000
--- a/src/core/iomgr/endpoint.c
+++ /dev/null
@@ -1,67 +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/iomgr/endpoint.h"
-
-void grpc_endpoint_read(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep,
-                        gpr_slice_buffer* slices, grpc_closure* cb) {
-  ep->vtable->read(exec_ctx, ep, slices, cb);
-}
-
-void grpc_endpoint_write(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep,
-                         gpr_slice_buffer* slices, grpc_closure* cb) {
-  ep->vtable->write(exec_ctx, ep, slices, cb);
-}
-
-void grpc_endpoint_add_to_pollset(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep,
-                                  grpc_pollset* pollset) {
-  ep->vtable->add_to_pollset(exec_ctx, ep, pollset);
-}
-
-void grpc_endpoint_add_to_pollset_set(grpc_exec_ctx* exec_ctx,
-                                      grpc_endpoint* ep,
-                                      grpc_pollset_set* pollset_set) {
-  ep->vtable->add_to_pollset_set(exec_ctx, ep, pollset_set);
-}
-
-void grpc_endpoint_shutdown(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) {
-  ep->vtable->shutdown(exec_ctx, ep);
-}
-
-void grpc_endpoint_destroy(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) {
-  ep->vtable->destroy(exec_ctx, ep);
-}
-
-char* grpc_endpoint_get_peer(grpc_endpoint* ep) {
-  return ep->vtable->get_peer(ep);
-}
diff --git a/src/core/iomgr/endpoint.h b/src/core/iomgr/endpoint.h
deleted file mode 100644
index cbdc947..0000000
--- a/src/core/iomgr/endpoint.h
+++ /dev/null
@@ -1,102 +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_ENDPOINT_H
-#define GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_H
-
-#include "src/core/iomgr/pollset.h"
-#include "src/core/iomgr/pollset_set.h"
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
-#include <grpc/support/time.h>
-
-/* An endpoint caps a streaming channel between two communicating processes.
-   Examples may be: a tcp socket, <stdin+stdout>, or some shared memory. */
-
-typedef struct grpc_endpoint grpc_endpoint;
-typedef struct grpc_endpoint_vtable grpc_endpoint_vtable;
-
-struct grpc_endpoint_vtable {
-  void (*read)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-               gpr_slice_buffer *slices, grpc_closure *cb);
-  void (*write)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                gpr_slice_buffer *slices, grpc_closure *cb);
-  void (*add_to_pollset)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                         grpc_pollset *pollset);
-  void (*add_to_pollset_set)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                             grpc_pollset_set *pollset);
-  void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
-  void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
-  char *(*get_peer)(grpc_endpoint *ep);
-};
-
-/* When data is available on the connection, calls the callback with slices.
-   Callback success indicates that the endpoint can accept more reads, failure
-   indicates the endpoint is closed.
-   Valid slices may be placed into \a slices even on callback success == 0. */
-void grpc_endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                        gpr_slice_buffer *slices, grpc_closure *cb);
-
-char *grpc_endpoint_get_peer(grpc_endpoint *ep);
-
-/* Write slices out to the socket.
-
-   If the connection is ready for more data after the end of the call, it
-   returns GRPC_ENDPOINT_DONE.
-   Otherwise it returns GRPC_ENDPOINT_PENDING and calls cb when the
-   connection is ready for more data.
-   \a slices may be mutated at will by the endpoint until cb is called.
-   No guarantee is made to the content of slices after a write EXCEPT that
-   it is a valid slice buffer.
-   */
-void grpc_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                         gpr_slice_buffer *slices, grpc_closure *cb);
-
-/* Causes any pending read/write callbacks to run immediately with
-   success==0 */
-void grpc_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
-void grpc_endpoint_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
-
-/* Add an endpoint to a pollset, so that when the pollset is polled, events from
-   this endpoint are considered */
-void grpc_endpoint_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                                  grpc_pollset *pollset);
-void grpc_endpoint_add_to_pollset_set(grpc_exec_ctx *exec_ctx,
-                                      grpc_endpoint *ep,
-                                      grpc_pollset_set *pollset_set);
-
-struct grpc_endpoint {
-  const grpc_endpoint_vtable *vtable;
-};
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_H */
diff --git a/src/core/iomgr/endpoint_pair.h b/src/core/iomgr/endpoint_pair.h
deleted file mode 100644
index 095ec5f..0000000
--- a/src/core/iomgr/endpoint_pair.h
+++ /dev/null
@@ -1,47 +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_ENDPOINT_PAIR_H
-#define GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_PAIR_H
-
-#include "src/core/iomgr/endpoint.h"
-
-typedef struct {
-  grpc_endpoint *client;
-  grpc_endpoint *server;
-} grpc_endpoint_pair;
-
-grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
-                                                   size_t read_slice_size);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_ENDPOINT_PAIR_H */
diff --git a/src/core/iomgr/endpoint_pair_posix.c b/src/core/iomgr/endpoint_pair_posix.c
deleted file mode 100644
index 56f6f14..0000000
--- a/src/core/iomgr/endpoint_pair_posix.c
+++ /dev/null
@@ -1,82 +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/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/iomgr/endpoint_pair.h"
-#include "src/core/iomgr/socket_utils_posix.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include "src/core/iomgr/tcp_posix.h"
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-static void create_sockets(int sv[2]) {
-  int flags;
-  GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
-  flags = fcntl(sv[0], F_GETFL, 0);
-  GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0);
-  flags = fcntl(sv[1], F_GETFL, 0);
-  GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
-  GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[0]));
-  GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1]));
-}
-
-grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
-                                                   size_t read_slice_size) {
-  int sv[2];
-  grpc_endpoint_pair p;
-  char *final_name;
-  create_sockets(sv);
-
-  gpr_asprintf(&final_name, "%s:client", name);
-  p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), read_slice_size,
-                             "socketpair-server");
-  gpr_free(final_name);
-  gpr_asprintf(&final_name, "%s:server", name);
-  p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), read_slice_size,
-                             "socketpair-client");
-  gpr_free(final_name);
-  return p;
-}
-
-#endif
diff --git a/src/core/iomgr/endpoint_pair_windows.c b/src/core/iomgr/endpoint_pair_windows.c
deleted file mode 100644
index db9d092..0000000
--- a/src/core/iomgr/endpoint_pair_windows.c
+++ /dev/null
@@ -1,97 +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/support/port_platform.h>
-
-#ifdef GPR_WINSOCK_SOCKET
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/iomgr/endpoint_pair.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include "src/core/iomgr/tcp_windows.h"
-#include "src/core/iomgr/socket_windows.h"
-#include <grpc/support/log.h>
-
-static void create_sockets(SOCKET sv[2]) {
-  SOCKET svr_sock = INVALID_SOCKET;
-  SOCKET lst_sock = INVALID_SOCKET;
-  SOCKET cli_sock = INVALID_SOCKET;
-  SOCKADDR_IN addr;
-  int addr_len = sizeof(addr);
-
-  lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
-                       WSA_FLAG_OVERLAPPED);
-  GPR_ASSERT(lst_sock != INVALID_SOCKET);
-
-  memset(&addr, 0, sizeof(addr));
-  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-  addr.sin_family = AF_INET;
-  GPR_ASSERT(bind(lst_sock, (struct sockaddr *)&addr, sizeof(addr)) !=
-             SOCKET_ERROR);
-  GPR_ASSERT(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR);
-  GPR_ASSERT(getsockname(lst_sock, (struct sockaddr *)&addr, &addr_len) !=
-             SOCKET_ERROR);
-
-  cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
-                       WSA_FLAG_OVERLAPPED);
-  GPR_ASSERT(cli_sock != INVALID_SOCKET);
-
-  GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr *)&addr, addr_len, NULL,
-                        NULL, NULL, NULL) == 0);
-  svr_sock = accept(lst_sock, (struct sockaddr *)&addr, &addr_len);
-  GPR_ASSERT(svr_sock != INVALID_SOCKET);
-
-  closesocket(lst_sock);
-  grpc_tcp_prepare_socket(cli_sock);
-  grpc_tcp_prepare_socket(svr_sock);
-
-  sv[1] = cli_sock;
-  sv[0] = svr_sock;
-}
-
-grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
-                                                   size_t read_slice_size) {
-  SOCKET sv[2];
-  grpc_endpoint_pair p;
-  create_sockets(sv);
-  p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"),
-                             "endpoint:server");
-  p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"),
-                             "endpoint:client");
-  return p;
-}
-
-#endif
diff --git a/src/core/iomgr/exec_ctx.c b/src/core/iomgr/exec_ctx.c
deleted file mode 100644
index 1fd79f6..0000000
--- a/src/core/iomgr/exec_ctx.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/iomgr/exec_ctx.h"
-
-#include <grpc/support/log.h>
-
-#include "src/core/profiling/timers.h"
-
-bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) {
-  bool did_something = 0;
-  GPR_TIMER_BEGIN("grpc_exec_ctx_flush", 0);
-  while (!grpc_closure_list_empty(exec_ctx->closure_list)) {
-    grpc_closure *c = exec_ctx->closure_list.head;
-    exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL;
-    while (c != NULL) {
-      bool success = (bool)(c->final_data & 1);
-      grpc_closure *next = (grpc_closure *)(c->final_data & ~(uintptr_t)1);
-      did_something = true;
-      GPR_TIMER_BEGIN("grpc_exec_ctx_flush.cb", 0);
-      c->cb(exec_ctx, c->cb_arg, success);
-      GPR_TIMER_END("grpc_exec_ctx_flush.cb", 0);
-      c = next;
-    }
-  }
-  GPR_TIMER_END("grpc_exec_ctx_flush", 0);
-  return did_something;
-}
-
-void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {
-  grpc_exec_ctx_flush(exec_ctx);
-}
-
-void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
-                           bool success,
-                           grpc_workqueue *offload_target_or_null) {
-  GPR_ASSERT(offload_target_or_null == NULL);
-  grpc_closure_list_add(&exec_ctx->closure_list, closure, success);
-}
-
-void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
-                                grpc_closure_list *list,
-                                grpc_workqueue *offload_target_or_null) {
-  GPR_ASSERT(offload_target_or_null == NULL);
-  grpc_closure_list_move(list, &exec_ctx->closure_list);
-}
diff --git a/src/core/iomgr/exec_ctx.h b/src/core/iomgr/exec_ctx.h
deleted file mode 100644
index 9a9b2e5..0000000
--- a/src/core/iomgr/exec_ctx.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_EXEC_CTX_H
-#define GRPC_INTERNAL_CORE_IOMGR_EXEC_CTX_H
-
-#include "src/core/iomgr/closure.h"
-
-/** Execution context.
- *  A bag of data that collects information along a callstack.
- *  Generally created at public API entry points, and passed down as
- *  pointer to child functions that manipulate it.
- *
- *  Specific responsibilities (this may grow in the future):
- *  - track a list of work that needs to be delayed until the top of the
- *    call stack (this provides a convenient mechanism to run callbacks
- *    without worrying about locking issues)
- *
- *  CONVENTIONS:
- *  Instance of this must ALWAYS be constructed on the stack, never
- *  heap allocated. Instances and pointers to them must always be called
- *  exec_ctx. Instances are always passed as the first argument
- *  to a function that takes it, and always as a pointer (grpc_exec_ctx
- *  is never copied).
- */
-struct grpc_exec_ctx {
-  grpc_closure_list closure_list;
-};
-
-/** A workqueue represents a list of work to be executed asynchronously.
-    Forward declared here to avoid a circular dependency with workqueue.h. */
-struct grpc_workqueue;
-typedef struct grpc_workqueue grpc_workqueue;
-
-#define GRPC_EXEC_CTX_INIT \
-  { GRPC_CLOSURE_LIST_INIT }
-
-/** Flush any work that has been enqueued onto this grpc_exec_ctx.
- *  Caller must guarantee that no interfering locks are held.
- *  Returns true if work was performed, false otherwise. */
-bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx);
-/** Finish any pending work for a grpc_exec_ctx. Must be called before
- *  the instance is destroyed, or work may be lost. */
-void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx);
-/** Add a closure to be executed at the next flush/finish point */
-void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
-                           bool success,
-                           grpc_workqueue *offload_target_or_null);
-/** Add a list of closures to be executed at the next flush/finish point.
- *  Leaves \a list empty. */
-void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
-                                grpc_closure_list *list,
-                                grpc_workqueue *offload_target_or_null);
-
-#endif
diff --git a/src/core/iomgr/executor.c b/src/core/iomgr/executor.c
deleted file mode 100644
index f22d8f3..0000000
--- a/src/core/iomgr/executor.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/iomgr/executor.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include "src/core/iomgr/exec_ctx.h"
-
-typedef struct grpc_executor_data {
-  int busy;          /**< is the thread currently running? */
-  int shutting_down; /**< has \a grpc_shutdown() been invoked? */
-  int pending_join;  /**< has the thread finished but not been joined? */
-  grpc_closure_list closures; /**< collection of pending work */
-  gpr_thd_id tid; /**< thread id of the thread, only valid if \a busy or \a
-                     pending_join are true */
-  gpr_thd_options options;
-  gpr_mu mu;
-} grpc_executor;
-
-static grpc_executor g_executor;
-
-void grpc_executor_init() {
-  memset(&g_executor, 0, sizeof(grpc_executor));
-  gpr_mu_init(&g_executor.mu);
-  g_executor.options = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&g_executor.options);
-}
-
-/* thread body */
-static void closure_exec_thread_func(void *ignored) {
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  while (1) {
-    gpr_mu_lock(&g_executor.mu);
-    if (g_executor.shutting_down != 0) {
-      gpr_mu_unlock(&g_executor.mu);
-      break;
-    }
-    if (grpc_closure_list_empty(g_executor.closures)) {
-      /* no more work, time to die */
-      GPR_ASSERT(g_executor.busy == 1);
-      g_executor.busy = 0;
-      gpr_mu_unlock(&g_executor.mu);
-      break;
-    } else {
-      grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL);
-    }
-    gpr_mu_unlock(&g_executor.mu);
-    grpc_exec_ctx_flush(&exec_ctx);
-  }
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-/* Spawn the thread if new work has arrived a no thread is up */
-static void maybe_spawn_locked() {
-  if (grpc_closure_list_empty(g_executor.closures) == 1) {
-    return;
-  }
-  if (g_executor.shutting_down == 1) {
-    return;
-  }
-
-  if (g_executor.busy != 0) {
-    /* Thread still working. New work will be picked up by already running
-     * thread. Not spawning anything. */
-    return;
-  } else if (g_executor.pending_join != 0) {
-    /* Pickup the remains of the previous incarnations of the thread. */
-    gpr_thd_join(g_executor.tid);
-    g_executor.pending_join = 0;
-  }
-
-  /* All previous instances of the thread should have been joined at this point.
-   * Spawn time! */
-  g_executor.busy = 1;
-  gpr_thd_new(&g_executor.tid, closure_exec_thread_func, NULL,
-              &g_executor.options);
-  g_executor.pending_join = 1;
-}
-
-void grpc_executor_enqueue(grpc_closure *closure, bool success) {
-  gpr_mu_lock(&g_executor.mu);
-  if (g_executor.shutting_down == 0) {
-    grpc_closure_list_add(&g_executor.closures, closure, success);
-    maybe_spawn_locked();
-  }
-  gpr_mu_unlock(&g_executor.mu);
-}
-
-void grpc_executor_shutdown() {
-  int pending_join;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  gpr_mu_lock(&g_executor.mu);
-  pending_join = g_executor.pending_join;
-  g_executor.shutting_down = 1;
-  gpr_mu_unlock(&g_executor.mu);
-  /* we can release the lock at this point despite the access to the closure
-   * list below because we aren't accepting new work */
-
-  /* Execute pending callbacks, some may be performing cleanups */
-  grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL);
-  grpc_exec_ctx_finish(&exec_ctx);
-  GPR_ASSERT(grpc_closure_list_empty(g_executor.closures));
-  if (pending_join) {
-    gpr_thd_join(g_executor.tid);
-  }
-  gpr_mu_destroy(&g_executor.mu);
-}
diff --git a/src/core/iomgr/executor.h b/src/core/iomgr/executor.h
deleted file mode 100644
index aac057d..0000000
--- a/src/core/iomgr/executor.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_EXECUTOR_H
-#define GRPC_INTERNAL_CORE_IOMGR_EXECUTOR_H
-
-#include "src/core/iomgr/closure.h"
-
-/** Initialize the global executor.
- *
- * This mechanism is meant to outsource work (grpc_closure instances) to a
- * thread, for those cases where blocking isn't an option but there isn't a
- * non-blocking solution available. */
-void grpc_executor_init();
-
-/** Enqueue \a closure for its eventual execution of \a f(arg) on a separate
- * thread */
-void grpc_executor_enqueue(grpc_closure *closure, bool success);
-
-/** Shutdown the executor, running all pending work as part of the call */
-void grpc_executor_shutdown();
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_EXECUTOR_H */
diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c
deleted file mode 100644
index 4ba7c5d..0000000
--- a/src/core/iomgr/fd_posix.c
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/iomgr/fd_posix.h"
-
-#include <assert.h>
-#include <sys/socket.h>
-#include <unistd.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/iomgr/pollset_posix.h"
-
-#define CLOSURE_NOT_READY ((grpc_closure *)0)
-#define CLOSURE_READY ((grpc_closure *)1)
-
-/* We need to keep a freelist not because of any concerns of malloc performance
- * but instead so that implementations with multiple threads in (for example)
- * epoll_wait deal with the race between pollset removal and incoming poll
- * notifications.
- *
- * The problem is that the poller ultimately holds a reference to this
- * object, so it is very difficult to know when is safe to free it, at least
- * without some expensive synchronization.
- *
- * If we keep the object freelisted, in the worst case losing this race just
- * becomes a spurious read notification on a reused fd.
- */
-/* TODO(klempner): We could use some form of polling generation count to know
- * when these are safe to free. */
-/* TODO(klempner): Consider disabling freelisting if we don't have multiple
- * threads in poll on the same fd */
-/* TODO(klempner): Batch these allocations to reduce fragmentation */
-static grpc_fd *fd_freelist = NULL;
-static gpr_mu fd_freelist_mu;
-
-static void freelist_fd(grpc_fd *fd) {
-  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);
-}
-
-static grpc_fd *alloc_fd(int fd) {
-  grpc_fd *r = NULL;
-  gpr_mu_lock(&fd_freelist_mu);
-  if (fd_freelist != NULL) {
-    r = fd_freelist;
-    fd_freelist = fd_freelist->freelist_next;
-  }
-  gpr_mu_unlock(&fd_freelist_mu);
-  if (r == NULL) {
-    r = gpr_malloc(sizeof(grpc_fd));
-    gpr_mu_init(&r->mu);
-  }
-
-  gpr_atm_rel_store(&r->refst, 1);
-  r->shutdown = 0;
-  r->read_closure = CLOSURE_NOT_READY;
-  r->write_closure = CLOSURE_NOT_READY;
-  r->fd = fd;
-  r->inactive_watcher_root.next = r->inactive_watcher_root.prev =
-      &r->inactive_watcher_root;
-  r->freelist_next = NULL;
-  r->read_watcher = r->write_watcher = NULL;
-  r->on_done_closure = NULL;
-  r->closed = 0;
-  r->released = 0;
-  return r;
-}
-
-static void destroy(grpc_fd *fd) {
-  gpr_mu_destroy(&fd->mu);
-  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;
-#endif
-  old = gpr_atm_full_fetch_add(&fd->refst, -n);
-  if (old == n) {
-    freelist_fd(fd);
-  } else {
-    GPR_ASSERT(old > n);
-  }
-}
-
-void grpc_fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); }
-
-void grpc_fd_global_shutdown(void) {
-  gpr_mu_lock(&fd_freelist_mu);
-  gpr_mu_unlock(&fd_freelist_mu);
-  while (fd_freelist != NULL) {
-    grpc_fd *fd = fd_freelist;
-    fd_freelist = fd_freelist->freelist_next;
-    destroy(fd);
-  }
-  gpr_mu_destroy(&fd_freelist_mu);
-}
-
-grpc_fd *grpc_fd_create(int fd, const char *name) {
-  grpc_fd *r = alloc_fd(fd);
-  char *name2;
-  gpr_asprintf(&name2, "%s fd=%d", name, fd);
-  grpc_iomgr_register_object(&r->iomgr_object, name2);
-  gpr_free(name2);
-#ifdef GRPC_FD_REF_COUNT_DEBUG
-  gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, r, name);
-#endif
-  return r;
-}
-
-int grpc_fd_is_orphaned(grpc_fd *fd) {
-  return (gpr_atm_acq_load(&fd->refst) & 1) == 0;
-}
-
-static void pollset_kick_locked(grpc_fd_watcher *watcher) {
-  gpr_mu_lock(&watcher->pollset->mu);
-  GPR_ASSERT(watcher->worker);
-  grpc_pollset_kick_ext(watcher->pollset, watcher->worker,
-                        GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
-  gpr_mu_unlock(&watcher->pollset->mu);
-}
-
-static void maybe_wake_one_watcher_locked(grpc_fd *fd) {
-  if (fd->inactive_watcher_root.next != &fd->inactive_watcher_root) {
-    pollset_kick_locked(fd->inactive_watcher_root.next);
-  } else if (fd->read_watcher) {
-    pollset_kick_locked(fd->read_watcher);
-  } else if (fd->write_watcher) {
-    pollset_kick_locked(fd->write_watcher);
-  }
-}
-
-static void wake_all_watchers_locked(grpc_fd *fd) {
-  grpc_fd_watcher *watcher;
-  for (watcher = fd->inactive_watcher_root.next;
-       watcher != &fd->inactive_watcher_root; watcher = watcher->next) {
-    pollset_kick_locked(watcher);
-  }
-  if (fd->read_watcher) {
-    pollset_kick_locked(fd->read_watcher);
-  }
-  if (fd->write_watcher && fd->write_watcher != fd->read_watcher) {
-    pollset_kick_locked(fd->write_watcher);
-  }
-}
-
-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;
-}
-
-static void close_fd_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
-  fd->closed = 1;
-  if (!fd->released) {
-    close(fd->fd);
-  } else {
-    grpc_remove_fd_from_all_epoll_sets(fd->fd);
-  }
-  grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, true, NULL);
-}
-
-int grpc_fd_wrapped_fd(grpc_fd *fd) {
-  if (fd->released || fd->closed) {
-    return -1;
-  } else {
-    return fd->fd;
-  }
-}
-
-void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
-                    int *release_fd, const char *reason) {
-  fd->on_done_closure = on_done;
-  fd->released = release_fd != NULL;
-  if (!fd->released) {
-    shutdown(fd->fd, SHUT_RDWR);
-  } else {
-    *release_fd = fd->fd;
-  }
-  gpr_mu_lock(&fd->mu);
-  REF_BY(fd, 1, reason); /* remove active status, but keep referenced */
-  if (!has_watchers(fd)) {
-    close_fd_locked(exec_ctx, fd);
-  } else {
-    wake_all_watchers_locked(fd);
-  }
-  gpr_mu_unlock(&fd->mu);
-  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 notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
-                             grpc_closure **st, grpc_closure *closure) {
-  if (*st == CLOSURE_NOT_READY) {
-    /* not ready ==> switch to a waiting state by setting the closure */
-    *st = closure;
-  } else if (*st == CLOSURE_READY) {
-    /* already ready ==> queue the closure to run immediately */
-    *st = CLOSURE_NOT_READY;
-    grpc_exec_ctx_enqueue(exec_ctx, closure, !fd->shutdown, NULL);
-    maybe_wake_one_watcher_locked(fd);
-  } else {
-    /* upcallptr was set to a different closure.  This is an error! */
-    gpr_log(GPR_ERROR,
-            "User called a notify_on function with a previous callback still "
-            "pending");
-    abort();
-  }
-}
-
-/* returns 1 if state becomes not ready */
-static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
-                            grpc_closure **st) {
-  if (*st == CLOSURE_READY) {
-    /* duplicate ready ==> ignore */
-    return 0;
-  } else if (*st == CLOSURE_NOT_READY) {
-    /* not ready, and not waiting ==> flag ready */
-    *st = CLOSURE_READY;
-    return 0;
-  } else {
-    /* waiting ==> queue closure */
-    grpc_exec_ctx_enqueue(exec_ctx, *st, !fd->shutdown, NULL);
-    *st = CLOSURE_NOT_READY;
-    return 1;
-  }
-}
-
-static void set_ready(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure **st) {
-  /* only one set_ready can be active at once (but there may be a racing
-     notify_on) */
-  gpr_mu_lock(&fd->mu);
-  set_ready_locked(exec_ctx, fd, st);
-  gpr_mu_unlock(&fd->mu);
-}
-
-void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
-  gpr_mu_lock(&fd->mu);
-  GPR_ASSERT(!fd->shutdown);
-  fd->shutdown = 1;
-  set_ready_locked(exec_ctx, fd, &fd->read_closure);
-  set_ready_locked(exec_ctx, fd, &fd->write_closure);
-  gpr_mu_unlock(&fd->mu);
-}
-
-void grpc_fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
-                            grpc_closure *closure) {
-  gpr_mu_lock(&fd->mu);
-  notify_on_locked(exec_ctx, fd, &fd->read_closure, closure);
-  gpr_mu_unlock(&fd->mu);
-}
-
-void grpc_fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
-                             grpc_closure *closure) {
-  gpr_mu_lock(&fd->mu);
-  notify_on_locked(exec_ctx, fd, &fd->write_closure, closure);
-  gpr_mu_unlock(&fd->mu);
-}
-
-uint32_t grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
-                            grpc_pollset_worker *worker, uint32_t read_mask,
-                            uint32_t write_mask, grpc_fd_watcher *watcher) {
-  uint32_t mask = 0;
-  grpc_closure *cur;
-  int requested;
-  /* keep track of pollers that have requested our events, in case they change
-   */
-  GRPC_FD_REF(fd, "poll");
-
-  gpr_mu_lock(&fd->mu);
-
-  /* if we are shutdown, then don't add to the watcher set */
-  if (fd->shutdown) {
-    watcher->fd = NULL;
-    watcher->pollset = NULL;
-    watcher->worker = NULL;
-    gpr_mu_unlock(&fd->mu);
-    GRPC_FD_UNREF(fd, "poll");
-    return 0;
-  }
-
-  /* if there is nobody polling for read, but we need to, then start doing so */
-  cur = fd->read_closure;
-  requested = cur != CLOSURE_READY;
-  if (read_mask && fd->read_watcher == NULL && requested) {
-    fd->read_watcher = watcher;
-    mask |= read_mask;
-  }
-  /* if there is nobody polling for write, but we need to, then start doing so
-   */
-  cur = fd->write_closure;
-  requested = cur != CLOSURE_READY;
-  if (write_mask && fd->write_watcher == NULL && requested) {
-    fd->write_watcher = watcher;
-    mask |= write_mask;
-  }
-  /* if not polling, remember this watcher in case we need someone to later */
-  if (mask == 0 && worker != NULL) {
-    watcher->next = &fd->inactive_watcher_root;
-    watcher->prev = watcher->next->prev;
-    watcher->next->prev = watcher->prev->next = watcher;
-  }
-  watcher->pollset = pollset;
-  watcher->worker = worker;
-  watcher->fd = fd;
-  gpr_mu_unlock(&fd->mu);
-
-  return mask;
-}
-
-void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher,
-                      int got_read, int got_write) {
-  int was_polling = 0;
-  int kick = 0;
-  grpc_fd *fd = watcher->fd;
-
-  if (fd == NULL) {
-    return;
-  }
-
-  gpr_mu_lock(&fd->mu);
-
-  if (watcher == fd->read_watcher) {
-    /* remove read watcher, kick if we still need a read */
-    was_polling = 1;
-    if (!got_read) {
-      kick = 1;
-    }
-    fd->read_watcher = NULL;
-  }
-  if (watcher == fd->write_watcher) {
-    /* remove write watcher, kick if we still need a write */
-    was_polling = 1;
-    if (!got_write) {
-      kick = 1;
-    }
-    fd->write_watcher = NULL;
-  }
-  if (!was_polling && watcher->worker != NULL) {
-    /* remove from inactive list */
-    watcher->next->prev = watcher->prev;
-    watcher->prev->next = watcher->next;
-  }
-  if (got_read) {
-    if (set_ready_locked(exec_ctx, fd, &fd->read_closure)) {
-      kick = 1;
-    }
-  }
-  if (got_write) {
-    if (set_ready_locked(exec_ctx, fd, &fd->write_closure)) {
-      kick = 1;
-    }
-  }
-  if (kick) {
-    maybe_wake_one_watcher_locked(fd);
-  }
-  if (grpc_fd_is_orphaned(fd) && !has_watchers(fd) && !fd->closed) {
-    close_fd_locked(exec_ctx, fd);
-  }
-  gpr_mu_unlock(&fd->mu);
-
-  GRPC_FD_UNREF(fd, "poll");
-}
-
-void grpc_fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
-  set_ready(exec_ctx, fd, &fd->read_closure);
-}
-
-void grpc_fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
-  set_ready(exec_ctx, fd, &fd->write_closure);
-}
-
-#endif
diff --git a/src/core/iomgr/fd_posix.h b/src/core/iomgr/fd_posix.h
deleted file mode 100644
index 17e7de8..0000000
--- a/src/core/iomgr/fd_posix.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_FD_POSIX_H
-#define GRPC_INTERNAL_CORE_IOMGR_FD_POSIX_H
-
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/pollset.h"
-#include <grpc/support/atm.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/time.h>
-
-typedef struct grpc_fd grpc_fd;
-
-typedef struct grpc_fd_watcher {
-  struct grpc_fd_watcher *next;
-  struct grpc_fd_watcher *prev;
-  grpc_pollset *pollset;
-  grpc_pollset_worker *worker;
-  grpc_fd *fd;
-} grpc_fd_watcher;
-
-struct grpc_fd {
-  int fd;
-  /* refst format:
-     bit0:   1=active/0=orphaned
-     bit1-n: refcount
-     meaning that mostly we ref by two to avoid altering the orphaned bit,
-     and just unref by 1 when we're ready to flag the object as orphaned */
-  gpr_atm refst;
-
-  gpr_mu mu;
-  int shutdown;
-  int closed;
-  int released;
-
-  /* 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.
-
-     If a watcher is asked to poll for reads or writes, the read_watcher
-     or write_watcher fields are set respectively. A watcher may be asked
-     to poll for both, in which case both fields will be set.
-
-     read_watcher and write_watcher may be NULL if no watcher has been
-     asked to poll for reads or writes.
-
-     If an fd_watcher is not asked to poll for reads or writes, it's added
-     to a linked list of inactive watchers, rooted at inactive_watcher_root.
-     If at a later time there becomes need of a poller to poll, one of
-     the inactive pollers may be kicked out of their poll loops to take
-     that responsibility. */
-  grpc_fd_watcher inactive_watcher_root;
-  grpc_fd_watcher *read_watcher;
-  grpc_fd_watcher *write_watcher;
-
-  grpc_closure *read_closure;
-  grpc_closure *write_closure;
-
-  struct grpc_fd *freelist_next;
-
-  grpc_closure *on_done_closure;
-
-  grpc_iomgr_object iomgr_object;
-};
-
-/* Create a wrapped file descriptor.
-   Requires fd is a non-blocking file descriptor.
-   This takes ownership of closing fd. */
-grpc_fd *grpc_fd_create(int fd, const char *name);
-
-/* Return the wrapped fd, or -1 if it has been released or closed. */
-int grpc_fd_wrapped_fd(grpc_fd *fd);
-
-/* Releases fd to be asynchronously destroyed.
-   on_done is called when the underlying file descriptor is definitely close()d.
-   If on_done is NULL, no callback will be made.
-   If release_fd is not NULL, it's set to fd and fd will not be closed.
-   Requires: *fd initialized; no outstanding notify_on_read or
-   notify_on_write.
-   MUST NOT be called with a pollset lock taken */
-void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
-                    int *release_fd, const char *reason);
-
-/* Begin polling on an fd.
-   Registers that the given pollset is interested in this fd - so that if read
-   or writability interest changes, the pollset can be kicked to pick up that
-   new interest.
-   Return value is:
-     (fd_needs_read? read_mask : 0) | (fd_needs_write? write_mask : 0)
-   i.e. a combination of read_mask and write_mask determined by the fd's current
-   interest in said events.
-   Polling strategies that do not need to alter their behavior depending on the
-   fd's current interest (such as epoll) do not need to call this function.
-   MUST NOT be called with a pollset lock taken */
-uint32_t grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
-                            grpc_pollset_worker *worker, uint32_t read_mask,
-                            uint32_t write_mask, grpc_fd_watcher *rec);
-/* Complete polling previously started with grpc_fd_begin_poll
-   MUST NOT be called with a pollset lock taken
-   if got_read or got_write are 1, also does the become_{readable,writable} as
-   appropriate. */
-void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *rec,
-                      int got_read, int got_write);
-
-/* Return 1 if this fd is orphaned, 0 otherwise */
-int grpc_fd_is_orphaned(grpc_fd *fd);
-
-/* Cause any current callbacks to error out with GRPC_CALLBACK_CANCELLED. */
-void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
-
-/* Register read interest, causing read_cb to be called once when fd becomes
-   readable, on deadline specified by deadline, or on shutdown triggered by
-   grpc_fd_shutdown.
-   read_cb will be called with read_cb_arg when *fd becomes readable.
-   read_cb is Called with status of GRPC_CALLBACK_SUCCESS if readable,
-   GRPC_CALLBACK_TIMED_OUT if the call timed out,
-   and CANCELLED if the call was cancelled.
-
-   Requires:This method must not be called before the read_cb for any previous
-   call runs. Edge triggered events are used whenever they are supported by the
-   underlying platform. This means that users must drain fd in read_cb before
-   calling notify_on_read again. Users are also expected to handle spurious
-   events, i.e read_cb is called while nothing can be readable from fd  */
-void grpc_fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
-                            grpc_closure *closure);
-
-/* Exactly the same semantics as above, except based on writable events.  */
-void grpc_fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
-                             grpc_closure *closure);
-
-/* Notification from the poller to an fd that it has become readable or
-   writable.
-   If allow_synchronous_callback is 1, allow running the fd callback inline
-   in this callstack, otherwise register an asynchronous callback and return */
-void grpc_fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
-void grpc_fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
-
-/* Reference counting for fds */
-/*#define GRPC_FD_REF_COUNT_DEBUG*/
-#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 */
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
deleted file mode 100644
index fa87e52..0000000
--- a/src/core/iomgr/iocp_windows.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WINSOCK_SOCKET
-
-#include <winsock2.h>
-
-#include <grpc/support/log.h>
-#include <grpc/support/log_win32.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/thd.h>
-
-#include "src/core/iomgr/timer.h"
-#include "src/core/iomgr/iocp_windows.h"
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/socket_windows.h"
-
-static ULONG g_iocp_kick_token;
-static OVERLAPPED g_iocp_custom_overlap;
-
-static gpr_atm g_custom_events = 0;
-
-static HANDLE g_iocp;
-
-static DWORD deadline_to_millis_timeout(gpr_timespec deadline,
-                                        gpr_timespec now) {
-  gpr_timespec timeout;
-  static const int64_t max_spin_polling_us = 10;
-  if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
-    return INFINITE;
-  }
-  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 (DWORD)gpr_time_to_millis(gpr_time_add(
-      timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN)));
-}
-
-grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx,
-                                     gpr_timespec deadline) {
-  BOOL success;
-  DWORD bytes = 0;
-  DWORD flags = 0;
-  ULONG_PTR completion_key;
-  LPOVERLAPPED overlapped;
-  grpc_winsocket *socket;
-  grpc_winsocket_callback_info *info;
-  grpc_closure *closure = NULL;
-  success = GetQueuedCompletionStatus(
-      g_iocp, &bytes, &completion_key, &overlapped,
-      deadline_to_millis_timeout(deadline, gpr_now(deadline.clock_type)));
-  if (success == 0 && overlapped == NULL) {
-    return GRPC_IOCP_WORK_TIMEOUT;
-  }
-  GPR_ASSERT(completion_key && overlapped);
-  if (overlapped == &g_iocp_custom_overlap) {
-    gpr_atm_full_fetch_add(&g_custom_events, -1);
-    if (completion_key == (ULONG_PTR)&g_iocp_kick_token) {
-      /* We were awoken from a kick. */
-      return GRPC_IOCP_WORK_KICK;
-    }
-    gpr_log(GPR_ERROR, "Unknown custom completion key.");
-    abort();
-  }
-
-  socket = (grpc_winsocket *)completion_key;
-  if (overlapped == &socket->write_info.overlapped) {
-    info = &socket->write_info;
-  } else if (overlapped == &socket->read_info.overlapped) {
-    info = &socket->read_info;
-  } else {
-    gpr_log(GPR_ERROR, "Unknown IOCP operation");
-    abort();
-  }
-  success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes,
-                                   FALSE, &flags);
-  info->bytes_transfered = bytes;
-  info->wsa_error = success ? 0 : WSAGetLastError();
-  GPR_ASSERT(overlapped == &info->overlapped);
-  GPR_ASSERT(!info->has_pending_iocp);
-  gpr_mu_lock(&socket->state_mu);
-  if (info->closure) {
-    closure = info->closure;
-    info->closure = NULL;
-  } else {
-    info->has_pending_iocp = 1;
-  }
-  gpr_mu_unlock(&socket->state_mu);
-  grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
-  return GRPC_IOCP_WORK_WORK;
-}
-
-void grpc_iocp_init(void) {
-  g_iocp =
-      CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0);
-  GPR_ASSERT(g_iocp);
-}
-
-void grpc_iocp_kick(void) {
-  BOOL success;
-
-  gpr_atm_full_fetch_add(&g_custom_events, 1);
-  success = PostQueuedCompletionStatus(g_iocp, 0, (ULONG_PTR)&g_iocp_kick_token,
-                                       &g_iocp_custom_overlap);
-  GPR_ASSERT(success);
-}
-
-void grpc_iocp_flush(void) {
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_iocp_work_status work_status;
-
-  do {
-    work_status = grpc_iocp_work(&exec_ctx, gpr_inf_past(GPR_CLOCK_MONOTONIC));
-  } while (work_status == GRPC_IOCP_WORK_KICK ||
-           grpc_exec_ctx_flush(&exec_ctx));
-}
-
-void grpc_iocp_shutdown(void) {
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  while (gpr_atm_acq_load(&g_custom_events)) {
-    grpc_iocp_work(&exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC));
-    grpc_exec_ctx_flush(&exec_ctx);
-  }
-  grpc_exec_ctx_finish(&exec_ctx);
-  GPR_ASSERT(CloseHandle(g_iocp));
-}
-
-void grpc_iocp_add_socket(grpc_winsocket *socket) {
-  HANDLE ret;
-  if (socket->added_to_iocp) return;
-  ret = CreateIoCompletionPort((HANDLE)socket->socket, g_iocp,
-                               (uintptr_t)socket, 0);
-  if (!ret) {
-    char *utf8_message = gpr_format_message(WSAGetLastError());
-    gpr_log(GPR_ERROR, "Unable to add socket to iocp: %s", utf8_message);
-    gpr_free(utf8_message);
-    __debugbreak();
-    abort();
-  }
-  socket->added_to_iocp = 1;
-  GPR_ASSERT(ret == g_iocp);
-}
-
-/* Calling notify_on_read or write means either of two things:
-   -) The IOCP already completed in the background, and we need to call
-   the callback now.
-   -) The IOCP hasn't completed yet, and we're queuing it for later. */
-static void socket_notify_on_iocp(grpc_exec_ctx *exec_ctx,
-                                  grpc_winsocket *socket, grpc_closure *closure,
-                                  grpc_winsocket_callback_info *info) {
-  GPR_ASSERT(info->closure == NULL);
-  gpr_mu_lock(&socket->state_mu);
-  if (info->has_pending_iocp) {
-    info->has_pending_iocp = 0;
-    grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
-  } else {
-    info->closure = closure;
-  }
-  gpr_mu_unlock(&socket->state_mu);
-}
-
-void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx,
-                                 grpc_winsocket *socket,
-                                 grpc_closure *closure) {
-  socket_notify_on_iocp(exec_ctx, socket, closure, &socket->write_info);
-}
-
-void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
-                                grpc_closure *closure) {
-  socket_notify_on_iocp(exec_ctx, socket, closure, &socket->read_info);
-}
-
-#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/iocp_windows.h b/src/core/iomgr/iocp_windows.h
deleted file mode 100644
index 8b2b1ae..0000000
--- a/src/core/iomgr/iocp_windows.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H
-#define GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H
-
-#include <grpc/support/sync.h>
-
-#include "src/core/iomgr/socket_windows.h"
-
-typedef enum {
-  GRPC_IOCP_WORK_WORK,
-  GRPC_IOCP_WORK_TIMEOUT,
-  GRPC_IOCP_WORK_KICK
-} grpc_iocp_work_status;
-
-grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx,
-                                     gpr_timespec deadline);
-void grpc_iocp_init(void);
-void grpc_iocp_kick(void);
-void grpc_iocp_flush(void);
-void grpc_iocp_shutdown(void);
-void grpc_iocp_add_socket(grpc_winsocket *);
-
-void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx,
-                                 grpc_winsocket *winsocket,
-                                 grpc_closure *closure);
-
-void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx,
-                                grpc_winsocket *winsocket,
-                                grpc_closure *closure);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_IOCP_WINDOWS_H */
diff --git a/src/core/iomgr/iomgr.c b/src/core/iomgr/iomgr.c
deleted file mode 100644
index 9c89c2c..0000000
--- a/src/core/iomgr/iomgr.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/iomgr/iomgr.h"
-
-#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/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/timer.h"
-#include "src/core/support/env.h"
-#include "src/core/support/string.h"
-
-static gpr_mu g_mu;
-static gpr_cv g_rcv;
-static int g_shutdown;
-static grpc_iomgr_object g_root_object;
-
-void grpc_iomgr_init(void) {
-  g_shutdown = 0;
-  gpr_mu_init(&g_mu);
-  gpr_cv_init(&g_rcv);
-  grpc_timer_list_init(gpr_now(GPR_CLOCK_MONOTONIC));
-  g_root_object.next = g_root_object.prev = &g_root_object;
-  g_root_object.name = "root";
-  grpc_iomgr_platform_init();
-  grpc_pollset_global_init();
-}
-
-static size_t count_objects(void) {
-  grpc_iomgr_object *obj;
-  size_t n = 0;
-  for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) {
-    n++;
-  }
-  return n;
-}
-
-static void dump_objects(const char *kind) {
-  grpc_iomgr_object *obj;
-  for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) {
-    gpr_log(GPR_DEBUG, "%s OBJECT: %s %p", kind, obj->name, obj);
-  }
-}
-
-void grpc_iomgr_shutdown(void) {
-  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);
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  grpc_iomgr_platform_flush();
-
-  gpr_mu_lock(&g_mu);
-  g_shutdown = 1;
-  while (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_root_object.next != &g_root_object) {
-        gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed",
-                count_objects());
-      }
-      last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
-    }
-    if (grpc_timer_check(&exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC),
-                         NULL)) {
-      gpr_mu_unlock(&g_mu);
-      grpc_exec_ctx_flush(&exec_ctx);
-      gpr_mu_lock(&g_mu);
-      continue;
-    }
-    if (g_root_object.next != &g_root_object) {
-      gpr_timespec short_deadline = gpr_time_add(
-          gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100, GPR_TIMESPAN));
-      if (gpr_cv_wait(&g_rcv, &g_mu, short_deadline)) {
-        if (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), shutdown_deadline) > 0) {
-          if (g_root_object.next != &g_root_object) {
-            gpr_log(GPR_DEBUG,
-                    "Failed to free %d iomgr objects before shutdown deadline: "
-                    "memory leaks are likely",
-                    count_objects());
-            dump_objects("LEAKED");
-            if (grpc_iomgr_abort_on_leaks()) {
-              abort();
-            }
-          }
-          break;
-        }
-      }
-    }
-  }
-  gpr_mu_unlock(&g_mu);
-
-  grpc_timer_list_shutdown(&exec_ctx);
-  grpc_exec_ctx_finish(&exec_ctx);
-
-  /* ensure all threads have left g_mu */
-  gpr_mu_lock(&g_mu);
-  gpr_mu_unlock(&g_mu);
-
-  grpc_pollset_global_shutdown();
-  grpc_iomgr_platform_shutdown();
-  gpr_mu_destroy(&g_mu);
-  gpr_cv_destroy(&g_rcv);
-}
-
-void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name) {
-  obj->name = gpr_strdup(name);
-  gpr_mu_lock(&g_mu);
-  obj->next = &g_root_object;
-  obj->prev = g_root_object.prev;
-  obj->next->prev = obj->prev->next = obj;
-  gpr_mu_unlock(&g_mu);
-}
-
-void grpc_iomgr_unregister_object(grpc_iomgr_object *obj) {
-  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);
-}
-
-bool grpc_iomgr_abort_on_leaks(void) {
-  char *env = gpr_getenv("GRPC_ABORT_ON_LEAKS");
-  if (env == NULL) return false;
-  static const char *truthy[] = {"yes",  "Yes",  "YES", "true",
-                                 "True", "TRUE", "1"};
-  for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
-    if (0 == strcmp(env, truthy[i])) return true;
-  }
-  return false;
-}
diff --git a/src/core/iomgr/iomgr.h b/src/core/iomgr/iomgr.h
deleted file mode 100644
index c9ea84c..0000000
--- a/src/core/iomgr/iomgr.h
+++ /dev/null
@@ -1,43 +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_IOMGR_H
-#define GRPC_INTERNAL_CORE_IOMGR_IOMGR_H
-
-/** Initializes the iomgr. */
-void grpc_iomgr_init(void);
-
-/** Signals the intention to shutdown the iomgr. */
-void grpc_iomgr_shutdown(void);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_H */
diff --git a/src/core/iomgr/iomgr_internal.h b/src/core/iomgr/iomgr_internal.h
deleted file mode 100644
index ac2c46e..0000000
--- a/src/core/iomgr/iomgr_internal.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H
-#define GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H
-
-#include <stdbool.h>
-
-#include "src/core/iomgr/iomgr.h"
-#include <grpc/support/sync.h>
-
-typedef struct grpc_iomgr_object {
-  char *name;
-  struct grpc_iomgr_object *next;
-  struct grpc_iomgr_object *prev;
-} grpc_iomgr_object;
-
-void grpc_pollset_global_init(void);
-void grpc_pollset_global_shutdown(void);
-
-void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name);
-void grpc_iomgr_unregister_object(grpc_iomgr_object *obj);
-
-void grpc_iomgr_platform_init(void);
-/** flush any globally queued work from iomgr */
-void grpc_iomgr_platform_flush(void);
-/** tear down all platform specific global iomgr structures */
-void grpc_iomgr_platform_shutdown(void);
-
-bool grpc_iomgr_abort_on_leaks(void);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H */
diff --git a/src/core/iomgr/iomgr_posix.c b/src/core/iomgr/iomgr_posix.c
deleted file mode 100644
index fecb7b9..0000000
--- a/src/core/iomgr/iomgr_posix.c
+++ /dev/null
@@ -1,52 +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/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/iomgr/iomgr_posix.h"
-#include "src/core/debug/trace.h"
-#include "src/core/iomgr/fd_posix.h"
-#include "src/core/iomgr/tcp_posix.h"
-
-void grpc_iomgr_platform_init(void) {
-  grpc_fd_global_init();
-  grpc_register_tracer("tcp", &grpc_tcp_trace);
-}
-
-void grpc_iomgr_platform_flush(void) {}
-
-void grpc_iomgr_platform_shutdown(void) { grpc_fd_global_shutdown(); }
-
-#endif /* GRPC_POSIX_SOCKET */
diff --git a/src/core/iomgr/iomgr_posix.h b/src/core/iomgr/iomgr_posix.h
deleted file mode 100644
index 068a5c6..0000000
--- a/src/core/iomgr/iomgr_posix.h
+++ /dev/null
@@ -1,39 +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_IOMGR_POSIX_H
-#define GRPC_INTERNAL_CORE_IOMGR_IOMGR_POSIX_H
-
-#include "src/core/iomgr/iomgr_internal.h"
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_POSIX_H */
diff --git a/src/core/iomgr/iomgr_windows.c b/src/core/iomgr/iomgr_windows.c
deleted file mode 100644
index 1477551..0000000
--- a/src/core/iomgr/iomgr_windows.c
+++ /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.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WINSOCK_SOCKET
-
-#include "src/core/iomgr/sockaddr_win32.h"
-
-#include <grpc/support/log.h>
-
-#include "src/core/iomgr/socket_windows.h"
-#include "src/core/iomgr/iocp_windows.h"
-#include "src/core/iomgr/iomgr.h"
-
-/* Windows' io manager is going to be fully designed using IO completion
-   ports. All of what we're doing here is basically make sure that
-   Windows sockets are initialized in and out. */
-
-static void winsock_init(void) {
-  WSADATA wsaData;
-  int status = WSAStartup(MAKEWORD(2, 0), &wsaData);
-  GPR_ASSERT(status == 0);
-}
-
-static void winsock_shutdown(void) {
-  int status = WSACleanup();
-  GPR_ASSERT(status == 0);
-}
-
-void grpc_iomgr_platform_init(void) {
-  winsock_init();
-  grpc_iocp_init();
-}
-
-void grpc_iomgr_platform_flush(void) { grpc_iocp_flush(); }
-
-void grpc_iomgr_platform_shutdown(void) {
-  grpc_iocp_shutdown();
-  winsock_shutdown();
-}
-
-#endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/pollset.h b/src/core/iomgr/pollset.h
deleted file mode 100644
index 92a0374..0000000
--- a/src/core/iomgr/pollset.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_H
-#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_H
-
-#include <grpc/support/port_platform.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/time.h>
-
-#include "src/core/iomgr/exec_ctx.h"
-
-#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1)
-
-/* A grpc_pollset is a set of file descriptors that a higher level item is
-   interested in. For example:
-    - a server will typically keep a pollset containing all connected channels,
-      so that it can find new calls to service
-    - a completion queue might keep a pollset with an entry for each transport
-      that is servicing a call that it's tracking */
-
-typedef struct grpc_pollset grpc_pollset;
-typedef struct grpc_pollset_worker grpc_pollset_worker;
-
-size_t grpc_pollset_size(void);
-void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu);
-/* Begin shutting down the pollset, and call closure when done.
- * GRPC_POLLSET_MU(pollset) must be held */
-void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                           grpc_closure *closure);
-/** Reset the pollset to its initial state (perhaps with some cached objects);
- *  must have been previously shutdown */
-void grpc_pollset_reset(grpc_pollset *pollset);
-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.
-
-   worker is a (platform-specific) handle that can be used to wake up
-   from grpc_pollset_work before any events are received and before the timeout
-   has expired. It is both initialized and destroyed by grpc_pollset_work.
-   Initialization of worker is guaranteed to occur BEFORE the
-   GRPC_POLLSET_MU(pollset) is released for the first time by
-   grpc_pollset_work, and it is guaranteed that GRPC_POLLSET_MU(pollset) will
-   not be released by grpc_pollset_work AFTER worker has been destroyed.
-
-   Tries not to block past deadline.
-   May call grpc_closure_list_run on grpc_closure_list, without holding the
-   pollset
-   lock */
-void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                       grpc_pollset_worker **worker, gpr_timespec now,
-                       gpr_timespec deadline);
-
-/* Break one polling thread out of polling work for this pollset.
-   If specific_worker is GRPC_POLLSET_KICK_BROADCAST, kick ALL the workers.
-   Otherwise, if specific_worker is non-NULL, then kick that worker. */
-void grpc_pollset_kick(grpc_pollset *pollset,
-                       grpc_pollset_worker *specific_worker);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_H */
diff --git a/src/core/iomgr/pollset_multipoller_with_epoll.c b/src/core/iomgr/pollset_multipoller_with_epoll.c
deleted file mode 100644
index 2e0f27f..0000000
--- a/src/core/iomgr/pollset_multipoller_with_epoll.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_LINUX_MULTIPOLL_WITH_EPOLL
-
-#include <errno.h>
-#include <poll.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <unistd.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-#include "src/core/iomgr/fd_posix.h"
-#include "src/core/iomgr/pollset_posix.h"
-#include "src/core/profiling/timers.h"
-#include "src/core/support/block_annotate.h"
-
-struct epoll_fd_list {
-  int *epoll_fds;
-  size_t count;
-  size_t capacity;
-};
-
-static struct epoll_fd_list epoll_fd_global_list;
-static gpr_once init_epoll_fd_list_mu = GPR_ONCE_INIT;
-static gpr_mu epoll_fd_list_mu;
-
-static void init_mu(void) { gpr_mu_init(&epoll_fd_list_mu); }
-
-static void add_epoll_fd_to_global_list(int epoll_fd) {
-  gpr_once_init(&init_epoll_fd_list_mu, init_mu);
-
-  gpr_mu_lock(&epoll_fd_list_mu);
-  if (epoll_fd_global_list.count == epoll_fd_global_list.capacity) {
-    epoll_fd_global_list.capacity =
-        GPR_MAX((size_t)8, epoll_fd_global_list.capacity * 2);
-    epoll_fd_global_list.epoll_fds =
-        gpr_realloc(epoll_fd_global_list.epoll_fds,
-                    epoll_fd_global_list.capacity * sizeof(int));
-  }
-  epoll_fd_global_list.epoll_fds[epoll_fd_global_list.count++] = epoll_fd;
-  gpr_mu_unlock(&epoll_fd_list_mu);
-}
-
-static void remove_epoll_fd_from_global_list(int epoll_fd) {
-  gpr_mu_lock(&epoll_fd_list_mu);
-  GPR_ASSERT(epoll_fd_global_list.count > 0);
-  for (size_t i = 0; i < epoll_fd_global_list.count; i++) {
-    if (epoll_fd == epoll_fd_global_list.epoll_fds[i]) {
-      epoll_fd_global_list.epoll_fds[i] =
-          epoll_fd_global_list.epoll_fds[--(epoll_fd_global_list.count)];
-      break;
-    }
-  }
-  gpr_mu_unlock(&epoll_fd_list_mu);
-}
-
-void grpc_remove_fd_from_all_epoll_sets(int fd) {
-  int err;
-  gpr_once_init(&init_epoll_fd_list_mu, init_mu);
-  gpr_mu_lock(&epoll_fd_list_mu);
-  if (epoll_fd_global_list.count == 0) {
-    gpr_mu_unlock(&epoll_fd_list_mu);
-    return;
-  }
-  for (size_t i = 0; i < epoll_fd_global_list.count; i++) {
-    err = epoll_ctl(epoll_fd_global_list.epoll_fds[i], EPOLL_CTL_DEL, fd, NULL);
-    if (err < 0 && errno != ENOENT) {
-      gpr_log(GPR_ERROR, "epoll_ctl del for %d failed: %s", fd,
-              strerror(errno));
-    }
-  }
-  gpr_mu_unlock(&epoll_fd_list_mu);
-}
-
-typedef struct {
-  grpc_pollset *pollset;
-  grpc_fd *fd;
-  grpc_closure closure;
-} delayed_add;
-
-typedef struct { int epoll_fd; } pollset_hdr;
-
-static void finally_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                           grpc_fd *fd) {
-  pollset_hdr *h = pollset->data.ptr;
-  struct epoll_event ev;
-  int err;
-  grpc_fd_watcher watcher;
-
-  /* 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, NULL, 0, 0, &watcher) == 0);
-  if (watcher.fd != NULL) {
-    ev.events = (uint32_t)(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(exec_ctx, &watcher, 0, 0);
-}
-
-static void perform_delayed_add(grpc_exec_ctx *exec_ctx, void *arg,
-                                bool iomgr_status) {
-  delayed_add *da = arg;
-
-  if (!grpc_fd_is_orphaned(da->fd)) {
-    finally_add_fd(exec_ctx, da->pollset, da->fd);
-  }
-
-  gpr_mu_lock(&da->pollset->mu);
-  da->pollset->in_flight_cbs--;
-  if (da->pollset->shutting_down) {
-    /* We don't care about this pollset anymore. */
-    if (da->pollset->in_flight_cbs == 0 && !da->pollset->called_shutdown) {
-      da->pollset->called_shutdown = 1;
-      grpc_exec_ctx_enqueue(exec_ctx, da->pollset->shutdown_done, true, NULL);
-    }
-  }
-  gpr_mu_unlock(&da->pollset->mu);
-
-  GRPC_FD_UNREF(da->fd, "delayed_add");
-
-  gpr_free(da);
-}
-
-static void multipoll_with_epoll_pollset_add_fd(grpc_exec_ctx *exec_ctx,
-                                                grpc_pollset *pollset,
-                                                grpc_fd *fd,
-                                                int and_unlock_pollset) {
-  if (and_unlock_pollset) {
-    gpr_mu_unlock(&pollset->mu);
-    finally_add_fd(exec_ctx, pollset, fd);
-  } else {
-    delayed_add *da = gpr_malloc(sizeof(*da));
-    da->pollset = pollset;
-    da->fd = fd;
-    GRPC_FD_REF(fd, "delayed_add");
-    grpc_closure_init(&da->closure, perform_delayed_add, da);
-    pollset->in_flight_cbs++;
-    grpc_exec_ctx_enqueue(exec_ctx, &da->closure, true, NULL);
-  }
-}
-
-/* TODO(klempner): We probably want to turn this down a bit */
-#define GRPC_EPOLL_MAX_EVENTS 1000
-
-static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
-    grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
-    gpr_timespec deadline, gpr_timespec now) {
-  struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS];
-  int ep_rv;
-  int poll_rv;
-  pollset_hdr *h = pollset->data.ptr;
-  int timeout_ms;
-  struct pollfd pfds[2];
-
-  /* If you want to ignore epoll's ability to sanely handle parallel pollers,
-   * for a more apples-to-apples performance comparison with poll, add a
-   * if (pollset->counter != 0) { return 0; }
-   * here.
-   */
-
-  gpr_mu_unlock(&pollset->mu);
-
-  timeout_ms = grpc_poll_deadline_to_millis_timeout(deadline, now);
-
-  pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd);
-  pfds[0].events = POLLIN;
-  pfds[0].revents = 0;
-  pfds[1].fd = h->epoll_fd;
-  pfds[1].events = POLLIN;
-  pfds[1].revents = 0;
-
-  /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid
-     even going into the blocking annotation if possible */
-  GPR_TIMER_BEGIN("poll", 0);
-  GRPC_SCHEDULING_START_BLOCKING_REGION;
-  poll_rv = grpc_poll_function(pfds, 2, timeout_ms);
-  GRPC_SCHEDULING_END_BLOCKING_REGION;
-  GPR_TIMER_END("poll", 0);
-
-  if (poll_rv < 0) {
-    if (errno != EINTR) {
-      gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
-    }
-  } else if (poll_rv == 0) {
-    /* do nothing */
-  } else {
-    if (pfds[0].revents) {
-      grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd);
-    }
-    if (pfds[1].revents) {
-      do {
-        /* The following epoll_wait never blocks; it has a timeout of 0 */
-        ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0);
-        if (ep_rv < 0) {
-          if (errno != EINTR) {
-            gpr_log(GPR_ERROR, "epoll_wait() failed: %s", strerror(errno));
-          }
-        } else {
-          int i;
-          for (i = 0; i < ep_rv; ++i) {
-            grpc_fd *fd = ep_ev[i].data.ptr;
-            /* TODO(klempner): We might want to consider making err and pri
-             * separate events */
-            int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP);
-            int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI);
-            int write_ev = ep_ev[i].events & EPOLLOUT;
-            if (fd == NULL) {
-              grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
-            } else {
-              if (read_ev || cancel) {
-                grpc_fd_become_readable(exec_ctx, fd);
-              }
-              if (write_ev || cancel) {
-                grpc_fd_become_writable(exec_ctx, fd);
-              }
-            }
-          }
-        }
-      } while (ep_rv == GRPC_EPOLL_MAX_EVENTS);
-    }
-  }
-}
-
-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;
-  close(h->epoll_fd);
-  remove_epoll_fd_from_global_list(h->epoll_fd);
-  gpr_free(h);
-}
-
-static const grpc_pollset_vtable multipoll_with_epoll_pollset = {
-    multipoll_with_epoll_pollset_add_fd,
-    multipoll_with_epoll_pollset_maybe_work_and_unlock,
-    multipoll_with_epoll_pollset_finish_shutdown,
-    multipoll_with_epoll_pollset_destroy};
-
-static void epoll_become_multipoller(grpc_exec_ctx *exec_ctx,
-                                     grpc_pollset *pollset, grpc_fd **fds,
-                                     size_t nfds) {
-  size_t i;
-  pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr));
-  struct epoll_event ev;
-  int err;
-
-  pollset->vtable = &multipoll_with_epoll_pollset;
-  pollset->data.ptr = h;
-  h->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
-  if (h->epoll_fd < 0) {
-    /* TODO(klempner): Fall back to poll here, especially on ENOSYS */
-    gpr_log(GPR_ERROR, "epoll_create1 failed: %s", strerror(errno));
-    abort();
-  }
-  add_epoll_fd_to_global_list(h->epoll_fd);
-
-  ev.events = (uint32_t)(EPOLLIN | EPOLLET);
-  ev.data.ptr = NULL;
-  err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD,
-                  GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd), &ev);
-  if (err < 0) {
-    gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s",
-            GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd),
-            strerror(errno));
-  }
-
-  for (i = 0; i < nfds; i++) {
-    multipoll_with_epoll_pollset_add_fd(exec_ctx, pollset, fds[i], 0);
-  }
-}
-
-grpc_platform_become_multipoller_type grpc_platform_become_multipoller =
-    epoll_become_multipoller;
-
-#else /* GPR_LINUX_MULTIPOLL_WITH_EPOLL */
-
-void grpc_remove_fd_from_all_epoll_sets(int fd) {}
-
-#endif /* GPR_LINUX_MULTIPOLL_WITH_EPOLL */
diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
deleted file mode 100644
index 92d6fb7..0000000
--- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/iomgr/pollset_posix.h"
-
-#include <errno.h>
-#include <poll.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/iomgr/fd_posix.h"
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/pollset_posix.h"
-#include "src/core/support/block_annotate.h"
-
-typedef struct {
-  /* all polled fds */
-  size_t fd_count;
-  size_t fd_capacity;
-  grpc_fd **fds;
-  /* fds that have been removed from the pollset explicitly */
-  size_t del_count;
-  size_t del_capacity;
-  grpc_fd **dels;
-} pollset_hdr;
-
-static void multipoll_with_poll_pollset_add_fd(grpc_exec_ctx *exec_ctx,
-                                               grpc_pollset *pollset,
-                                               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) 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, "multipoller");
-exit:
-  if (and_unlock_pollset) {
-    gpr_mu_unlock(&pollset->mu);
-  }
-}
-
-static void multipoll_with_poll_pollset_maybe_work_and_unlock(
-    grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
-    gpr_timespec deadline, gpr_timespec now) {
-#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
-#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR)
-
-  int timeout;
-  int r;
-  size_t i, j, fd_count;
-  nfds_t pfd_count;
-  pollset_hdr *h;
-  /* TODO(ctiller): inline some elements to avoid an allocation */
-  grpc_fd_watcher *watchers;
-  struct pollfd *pfds;
-
-  h = pollset->data.ptr;
-  timeout = grpc_poll_deadline_to_millis_timeout(deadline, now);
-  /* TODO(ctiller): perform just one malloc here if we exceed the inline case */
-  pfds = gpr_malloc(sizeof(*pfds) * (h->fd_count + 2));
-  watchers = gpr_malloc(sizeof(*watchers) * (h->fd_count + 2));
-  fd_count = 0;
-  pfd_count = 2;
-  pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd);
-  pfds[0].events = POLLIN;
-  pfds[0].revents = 0;
-  pfds[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd);
-  pfds[1].events = POLLIN;
-  pfds[1].revents = 0;
-  for (i = 0; i < h->fd_count; i++) {
-    int remove = grpc_fd_is_orphaned(h->fds[i]);
-    for (j = 0; !remove && j < h->del_count; j++) {
-      if (h->fds[i] == h->dels[j]) remove = 1;
-    }
-    if (remove) {
-      GRPC_FD_UNREF(h->fds[i], "multipoller");
-    } else {
-      h->fds[fd_count++] = h->fds[i];
-      watchers[pfd_count].fd = h->fds[i];
-      GRPC_FD_REF(watchers[pfd_count].fd, "multipoller_start");
-      pfds[pfd_count].fd = h->fds[i]->fd;
-      pfds[pfd_count].revents = 0;
-      pfd_count++;
-    }
-  }
-  for (j = 0; j < h->del_count; j++) {
-    GRPC_FD_UNREF(h->dels[j], "multipoller_del");
-  }
-  h->del_count = 0;
-  h->fd_count = fd_count;
-  gpr_mu_unlock(&pollset->mu);
-
-  for (i = 2; i < pfd_count; i++) {
-    grpc_fd *fd = watchers[i].fd;
-    pfds[i].events = (short)grpc_fd_begin_poll(fd, pollset, worker, POLLIN,
-                                               POLLOUT, &watchers[i]);
-    GRPC_FD_UNREF(fd, "multipoller_start");
-  }
-
-  /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid
-     even going into the blocking annotation if possible */
-  GRPC_SCHEDULING_START_BLOCKING_REGION;
-  r = grpc_poll_function(pfds, pfd_count, timeout);
-  GRPC_SCHEDULING_END_BLOCKING_REGION;
-
-  if (r < 0) {
-    if (errno != EINTR) {
-      gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
-    }
-    for (i = 2; i < pfd_count; i++) {
-      grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0);
-    }
-  } else if (r == 0) {
-    for (i = 2; i < pfd_count; i++) {
-      grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0);
-    }
-  } else {
-    if (pfds[0].revents & POLLIN_CHECK) {
-      grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
-    }
-    if (pfds[1].revents & POLLIN_CHECK) {
-      grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd);
-    }
-    for (i = 2; i < pfd_count; i++) {
-      if (watchers[i].fd == NULL) {
-        grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0);
-        continue;
-      }
-      grpc_fd_end_poll(exec_ctx, &watchers[i], pfds[i].revents & POLLIN_CHECK,
-                       pfds[i].revents & POLLOUT_CHECK);
-    }
-  }
-
-  gpr_free(pfds);
-  gpr_free(watchers);
-}
-
-static void multipoll_with_poll_pollset_finish_shutdown(grpc_pollset *pollset) {
-  size_t i;
-  pollset_hdr *h = pollset->data.ptr;
-  for (i = 0; i < h->fd_count; i++) {
-    GRPC_FD_UNREF(h->fds[i], "multipoller");
-  }
-  for (i = 0; i < h->del_count; 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->fds);
-  gpr_free(h->dels);
-  gpr_free(h);
-}
-
-static const grpc_pollset_vtable multipoll_with_poll_pollset = {
-    multipoll_with_poll_pollset_add_fd,
-    multipoll_with_poll_pollset_maybe_work_and_unlock,
-    multipoll_with_poll_pollset_finish_shutdown,
-    multipoll_with_poll_pollset_destroy};
-
-void grpc_poll_become_multipoller(grpc_exec_ctx *exec_ctx,
-                                  grpc_pollset *pollset, grpc_fd **fds,
-                                  size_t nfds) {
-  size_t i;
-  pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr));
-  pollset->vtable = &multipoll_with_poll_pollset;
-  pollset->data.ptr = h;
-  h->fd_count = nfds;
-  h->fd_capacity = nfds;
-  h->fds = gpr_malloc(nfds * sizeof(grpc_fd *));
-  h->del_count = 0;
-  h->del_capacity = 0;
-  h->dels = NULL;
-  for (i = 0; i < nfds; i++) {
-    h->fds[i] = fds[i];
-    GRPC_FD_REF(fds[i], "multipoller");
-  }
-}
-
-#endif /* GPR_POSIX_SOCKET */
-
-#ifdef GPR_POSIX_MULTIPOLL_WITH_POLL
-grpc_platform_become_multipoller_type grpc_platform_become_multipoller =
-    grpc_poll_become_multipoller;
-#endif
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
deleted file mode 100644
index e895a77..0000000
--- a/src/core/iomgr/pollset_posix.c
+++ /dev/null
@@ -1,633 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/iomgr/pollset_posix.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/tls.h>
-#include <grpc/support/useful.h>
-#include "src/core/iomgr/fd_posix.h"
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/socket_utils_posix.h"
-#include "src/core/profiling/timers.h"
-#include "src/core/support/block_annotate.h"
-
-GPR_TLS_DECL(g_current_thread_poller);
-GPR_TLS_DECL(g_current_thread_worker);
-
-/** Default poll() function - a pointer so that it can be overridden by some
- *  tests */
-grpc_poll_function_type grpc_poll_function = poll;
-
-/** The alarm system needs to be able to wakeup 'some poller' sometimes
- *  (specifically when a new alarm needs to be triggered earlier than the next
- *  alarm 'epoch').
- *  This wakeup_fd gives us something to alert on when such a case occurs. */
-grpc_wakeup_fd grpc_global_wakeup_fd;
-
-static void remove_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
-  worker->prev->next = worker->next;
-  worker->next->prev = worker->prev;
-}
-
-int grpc_pollset_has_workers(grpc_pollset *p) {
-  return p->root_worker.next != &p->root_worker;
-}
-
-static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) {
-  if (grpc_pollset_has_workers(p)) {
-    grpc_pollset_worker *w = p->root_worker.next;
-    remove_worker(p, w);
-    return w;
-  } else {
-    return NULL;
-  }
-}
-
-static void push_back_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
-  worker->next = &p->root_worker;
-  worker->prev = worker->next->prev;
-  worker->prev->next = worker->next->prev = worker;
-}
-
-static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
-  worker->prev = &p->root_worker;
-  worker->next = worker->prev->next;
-  worker->prev->next = worker->next->prev = worker;
-}
-
-size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); }
-
-void grpc_pollset_kick_ext(grpc_pollset *p,
-                           grpc_pollset_worker *specific_worker,
-                           uint32_t flags) {
-  GPR_TIMER_BEGIN("grpc_pollset_kick_ext", 0);
-
-  /* pollset->mu already held */
-  if (specific_worker != NULL) {
-    if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
-      GPR_TIMER_BEGIN("grpc_pollset_kick_ext.broadcast", 0);
-      GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0);
-      for (specific_worker = p->root_worker.next;
-           specific_worker != &p->root_worker;
-           specific_worker = specific_worker->next) {
-        grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
-      }
-      p->kicked_without_pollers = 1;
-      GPR_TIMER_END("grpc_pollset_kick_ext.broadcast", 0);
-    } else if (gpr_tls_get(&g_current_thread_worker) !=
-               (intptr_t)specific_worker) {
-      GPR_TIMER_MARK("different_thread_worker", 0);
-      if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
-        specific_worker->reevaluate_polling_on_wakeup = 1;
-      }
-      specific_worker->kicked_specifically = 1;
-      grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
-    } else if ((flags & GRPC_POLLSET_CAN_KICK_SELF) != 0) {
-      GPR_TIMER_MARK("kick_yoself", 0);
-      if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
-        specific_worker->reevaluate_polling_on_wakeup = 1;
-      }
-      specific_worker->kicked_specifically = 1;
-      grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
-    }
-  } else if (gpr_tls_get(&g_current_thread_poller) != (intptr_t)p) {
-    GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0);
-    GPR_TIMER_MARK("kick_anonymous", 0);
-    specific_worker = pop_front_worker(p);
-    if (specific_worker != NULL) {
-      if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) {
-        GPR_TIMER_MARK("kick_anonymous_not_self", 0);
-        push_back_worker(p, specific_worker);
-        specific_worker = pop_front_worker(p);
-        if ((flags & GRPC_POLLSET_CAN_KICK_SELF) == 0 &&
-            gpr_tls_get(&g_current_thread_worker) ==
-                (intptr_t)specific_worker) {
-          push_back_worker(p, specific_worker);
-          specific_worker = NULL;
-        }
-      }
-      if (specific_worker != NULL) {
-        GPR_TIMER_MARK("finally_kick", 0);
-        push_back_worker(p, specific_worker);
-        grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
-      }
-    } else {
-      GPR_TIMER_MARK("kicked_no_pollers", 0);
-      p->kicked_without_pollers = 1;
-    }
-  }
-
-  GPR_TIMER_END("grpc_pollset_kick_ext", 0);
-}
-
-void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) {
-  grpc_pollset_kick_ext(p, specific_worker, 0);
-}
-
-/* global state management */
-
-void grpc_pollset_global_init(void) {
-  gpr_tls_init(&g_current_thread_poller);
-  gpr_tls_init(&g_current_thread_worker);
-  grpc_wakeup_fd_global_init();
-  grpc_wakeup_fd_init(&grpc_global_wakeup_fd);
-}
-
-void grpc_pollset_global_shutdown(void) {
-  grpc_wakeup_fd_destroy(&grpc_global_wakeup_fd);
-  gpr_tls_destroy(&g_current_thread_poller);
-  gpr_tls_destroy(&g_current_thread_worker);
-  grpc_wakeup_fd_global_destroy();
-}
-
-void grpc_kick_poller(void) { grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd); }
-
-/* main interface */
-
-static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null);
-
-void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
-  gpr_mu_init(&pollset->mu);
-  *mu = &pollset->mu;
-  pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker;
-  pollset->in_flight_cbs = 0;
-  pollset->shutting_down = 0;
-  pollset->called_shutdown = 0;
-  pollset->kicked_without_pollers = 0;
-  pollset->idle_jobs.head = pollset->idle_jobs.tail = NULL;
-  pollset->local_wakeup_cache = NULL;
-  pollset->kicked_without_pollers = 0;
-  become_basic_pollset(pollset, NULL);
-}
-
-void grpc_pollset_destroy(grpc_pollset *pollset) {
-  GPR_ASSERT(pollset->in_flight_cbs == 0);
-  GPR_ASSERT(!grpc_pollset_has_workers(pollset));
-  GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail);
-  pollset->vtable->destroy(pollset);
-  while (pollset->local_wakeup_cache) {
-    grpc_cached_wakeup_fd *next = pollset->local_wakeup_cache->next;
-    grpc_wakeup_fd_destroy(&pollset->local_wakeup_cache->fd);
-    gpr_free(pollset->local_wakeup_cache);
-    pollset->local_wakeup_cache = next;
-  }
-}
-
-void grpc_pollset_reset(grpc_pollset *pollset) {
-  GPR_ASSERT(pollset->shutting_down);
-  GPR_ASSERT(pollset->in_flight_cbs == 0);
-  GPR_ASSERT(!grpc_pollset_has_workers(pollset));
-  GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail);
-  pollset->vtable->destroy(pollset);
-  pollset->shutting_down = 0;
-  pollset->called_shutdown = 0;
-  pollset->kicked_without_pollers = 0;
-  become_basic_pollset(pollset, NULL);
-}
-
-void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                         grpc_fd *fd) {
-  gpr_mu_lock(&pollset->mu);
-  pollset->vtable->add_fd(exec_ctx, pollset, fd, 1);
-/* the following (enabled only in debug) will reacquire and then release
-   our lock - meaning that if the unlocking flag passed to add_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_exec_ctx *exec_ctx, grpc_pollset *pollset) {
-  GPR_ASSERT(grpc_closure_list_empty(pollset->idle_jobs));
-  pollset->vtable->finish_shutdown(pollset);
-  grpc_exec_ctx_enqueue(exec_ctx, pollset->shutdown_done, true, NULL);
-}
-
-void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                       grpc_pollset_worker **worker_hdl, gpr_timespec now,
-                       gpr_timespec deadline) {
-  grpc_pollset_worker worker;
-  *worker_hdl = &worker;
-
-  /* pollset->mu already held */
-  int added_worker = 0;
-  int locked = 1;
-  int queued_work = 0;
-  int keep_polling = 0;
-  GPR_TIMER_BEGIN("grpc_pollset_work", 0);
-  /* this must happen before we (potentially) drop pollset->mu */
-  worker.next = worker.prev = NULL;
-  worker.reevaluate_polling_on_wakeup = 0;
-  if (pollset->local_wakeup_cache != NULL) {
-    worker.wakeup_fd = pollset->local_wakeup_cache;
-    pollset->local_wakeup_cache = worker.wakeup_fd->next;
-  } else {
-    worker.wakeup_fd = gpr_malloc(sizeof(*worker.wakeup_fd));
-    grpc_wakeup_fd_init(&worker.wakeup_fd->fd);
-  }
-  worker.kicked_specifically = 0;
-  /* If there's work waiting for the pollset to be idle, and the
-     pollset is idle, then do that work */
-  if (!grpc_pollset_has_workers(pollset) &&
-      !grpc_closure_list_empty(pollset->idle_jobs)) {
-    GPR_TIMER_MARK("grpc_pollset_work.idle_jobs", 0);
-    grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
-    goto done;
-  }
-  /* If we're shutting down then we don't execute any extended work */
-  if (pollset->shutting_down) {
-    GPR_TIMER_MARK("grpc_pollset_work.shutting_down", 0);
-    goto done;
-  }
-  /* Give do_promote priority so we don't starve it out */
-  if (pollset->in_flight_cbs) {
-    GPR_TIMER_MARK("grpc_pollset_work.in_flight_cbs", 0);
-    gpr_mu_unlock(&pollset->mu);
-    locked = 0;
-    goto done;
-  }
-  /* Start polling, and keep doing so while we're being asked to
-     re-evaluate our pollers (this allows poll() based pollers to
-     ensure they don't miss wakeups) */
-  keep_polling = 1;
-  while (keep_polling) {
-    keep_polling = 0;
-    if (!pollset->kicked_without_pollers) {
-      if (!added_worker) {
-        push_front_worker(pollset, &worker);
-        added_worker = 1;
-        gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
-      }
-      gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset);
-      GPR_TIMER_BEGIN("maybe_work_and_unlock", 0);
-      pollset->vtable->maybe_work_and_unlock(exec_ctx, pollset, &worker,
-                                             deadline, now);
-      GPR_TIMER_END("maybe_work_and_unlock", 0);
-      locked = 0;
-      gpr_tls_set(&g_current_thread_poller, 0);
-    } else {
-      GPR_TIMER_MARK("grpc_pollset_work.kicked_without_pollers", 0);
-      pollset->kicked_without_pollers = 0;
-    }
-  /* Finished execution - start cleaning up.
-     Note that we may arrive here from outside the enclosing while() loop.
-     In that case we won't loop though as we haven't added worker to the
-     worker list, which means nobody could ask us to re-evaluate polling). */
-  done:
-    if (!locked) {
-      queued_work |= grpc_exec_ctx_flush(exec_ctx);
-      gpr_mu_lock(&pollset->mu);
-      locked = 1;
-    }
-    /* If we're forced to re-evaluate polling (via grpc_pollset_kick with
-       GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) then we land here and force
-       a loop */
-    if (worker.reevaluate_polling_on_wakeup) {
-      worker.reevaluate_polling_on_wakeup = 0;
-      pollset->kicked_without_pollers = 0;
-      if (queued_work || worker.kicked_specifically) {
-        /* If there's queued work on the list, then set the deadline to be
-           immediate so we get back out of the polling loop quickly */
-        deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC);
-      }
-      keep_polling = 1;
-    }
-  }
-  if (added_worker) {
-    remove_worker(pollset, &worker);
-    gpr_tls_set(&g_current_thread_worker, 0);
-  }
-  /* release wakeup fd to the local pool */
-  worker.wakeup_fd->next = pollset->local_wakeup_cache;
-  pollset->local_wakeup_cache = worker.wakeup_fd;
-  /* check shutdown conditions */
-  if (pollset->shutting_down) {
-    if (grpc_pollset_has_workers(pollset)) {
-      grpc_pollset_kick(pollset, NULL);
-    } else if (!pollset->called_shutdown && pollset->in_flight_cbs == 0) {
-      pollset->called_shutdown = 1;
-      gpr_mu_unlock(&pollset->mu);
-      finish_shutdown(exec_ctx, pollset);
-      grpc_exec_ctx_flush(exec_ctx);
-      /* 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.
-       * TODO(dklempner): Can we refactor the shutdown logic to avoid this? */
-      gpr_mu_lock(&pollset->mu);
-    } else if (!grpc_closure_list_empty(pollset->idle_jobs)) {
-      grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
-      gpr_mu_unlock(&pollset->mu);
-      grpc_exec_ctx_flush(exec_ctx);
-      gpr_mu_lock(&pollset->mu);
-    }
-  }
-  *worker_hdl = NULL;
-  GPR_TIMER_END("grpc_pollset_work", 0);
-}
-
-void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                           grpc_closure *closure) {
-  GPR_ASSERT(!pollset->shutting_down);
-  pollset->shutting_down = 1;
-  pollset->shutdown_done = closure;
-  grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
-  if (!grpc_pollset_has_workers(pollset)) {
-    grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
-  }
-  if (!pollset->called_shutdown && pollset->in_flight_cbs == 0 &&
-      !grpc_pollset_has_workers(pollset)) {
-    pollset->called_shutdown = 1;
-    finish_shutdown(exec_ctx, pollset);
-  }
-}
-
-int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline,
-                                         gpr_timespec now) {
-  gpr_timespec timeout;
-  static const int64_t max_spin_polling_us = 10;
-  if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 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_MS - 1, GPR_TIMESPAN)));
-}
-
-/*
- * basic_pollset - a vtable that provides polling for zero or one file
- *                 descriptor via poll()
- */
-
-typedef struct grpc_unary_promote_args {
-  const grpc_pollset_vtable *original_vtable;
-  grpc_pollset *pollset;
-  grpc_fd *fd;
-  grpc_closure promotion_closure;
-} grpc_unary_promote_args;
-
-static void basic_do_promote(grpc_exec_ctx *exec_ctx, void *args,
-                             bool success) {
-  grpc_unary_promote_args *up_args = args;
-  const grpc_pollset_vtable *original_vtable = up_args->original_vtable;
-  grpc_pollset *pollset = up_args->pollset;
-  grpc_fd *fd = up_args->fd;
-
-  /*
-   * This is quite tricky. There are a number of cases to keep in mind here:
-   * 1. fd may have been orphaned
-   * 2. The pollset may no longer be a unary poller (and we can't let case #1
-   * leak to other pollset types!)
-   * 3. pollset's fd (which may have changed) may have been orphaned
-   * 4. The pollset may be shutting down.
-   */
-
-  gpr_mu_lock(&pollset->mu);
-  /* First we need to ensure that nobody is polling concurrently */
-  GPR_ASSERT(!grpc_pollset_has_workers(pollset));
-
-  gpr_free(up_args);
-  /* At this point the pollset may no longer be a unary poller. In that case
-   * we should just call the right add function and be done. */
-  /* TODO(klempner): If we're not careful this could cause infinite recursion.
-   * That's not a problem for now because empty_pollset has a trivial poller
-   * and we don't have any mechanism to unbecome multipoller. */
-  pollset->in_flight_cbs--;
-  if (pollset->shutting_down) {
-    /* We don't care about this pollset anymore. */
-    if (pollset->in_flight_cbs == 0 && !pollset->called_shutdown) {
-      pollset->called_shutdown = 1;
-      finish_shutdown(exec_ctx, pollset);
-    }
-  } 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(exec_ctx, pollset, fd, 0);
-  } else if (fd != pollset->data.ptr) {
-    grpc_fd *fds[2];
-    fds[0] = pollset->data.ptr;
-    fds[1] = fd;
-
-    if (fds[0] && !grpc_fd_is_orphaned(fds[0])) {
-      grpc_platform_become_multipoller(exec_ctx, pollset, fds,
-                                       GPR_ARRAY_SIZE(fds));
-      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. */
-      if (fds[0]) GRPC_FD_UNREF(fds[0], "basicpoll");
-      pollset->data.ptr = fd;
-      GRPC_FD_REF(fd, "basicpoll");
-    }
-  }
-
-  gpr_mu_unlock(&pollset->mu);
-
-  /* Matching ref in basic_pollset_add_fd */
-  GRPC_FD_UNREF(fd, "basicpoll_add");
-}
-
-static void basic_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                                 grpc_fd *fd, int and_unlock_pollset) {
-  grpc_unary_promote_args *up_args;
-  GPR_ASSERT(fd);
-  if (fd == pollset->data.ptr) goto exit;
-
-  if (!grpc_pollset_has_workers(pollset)) {
-    /* Fast path -- no in flight cbs */
-    /* TODO(klempner): Comment this out and fix any test failures or establish
-     * they are due to timing issues */
-    grpc_fd *fds[2];
-    fds[0] = pollset->data.ptr;
-    fds[1] = fd;
-
-    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(exec_ctx, pollset, fds,
-                                       GPR_ARRAY_SIZE(fds));
-      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], "basicpoll");
-      pollset->data.ptr = fd;
-      GRPC_FD_REF(fd, "basicpoll");
-    }
-    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, "basicpoll_add");
-  pollset->in_flight_cbs++;
-  up_args = gpr_malloc(sizeof(*up_args));
-  up_args->fd = fd;
-  up_args->original_vtable = pollset->vtable;
-  up_args->pollset = pollset;
-  up_args->promotion_closure.cb = basic_do_promote;
-  up_args->promotion_closure.cb_arg = up_args;
-
-  grpc_closure_list_add(&pollset->idle_jobs, &up_args->promotion_closure, 1);
-  grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
-
-exit:
-  if (and_unlock_pollset) {
-    gpr_mu_unlock(&pollset->mu);
-  }
-}
-
-static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
-                                                grpc_pollset *pollset,
-                                                grpc_pollset_worker *worker,
-                                                gpr_timespec deadline,
-                                                gpr_timespec now) {
-#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
-#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR)
-
-  struct pollfd pfd[3];
-  grpc_fd *fd;
-  grpc_fd_watcher fd_watcher;
-  int timeout;
-  int r;
-  nfds_t nfds;
-
-  fd = pollset->data.ptr;
-  if (fd && grpc_fd_is_orphaned(fd)) {
-    GRPC_FD_UNREF(fd, "basicpoll");
-    fd = pollset->data.ptr = NULL;
-  }
-  timeout = grpc_poll_deadline_to_millis_timeout(deadline, now);
-  pfd[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd);
-  pfd[0].events = POLLIN;
-  pfd[0].revents = 0;
-  pfd[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd);
-  pfd[1].events = POLLIN;
-  pfd[1].revents = 0;
-  nfds = 2;
-  if (fd) {
-    pfd[2].fd = fd->fd;
-    pfd[2].revents = 0;
-    GRPC_FD_REF(fd, "basicpoll_begin");
-    gpr_mu_unlock(&pollset->mu);
-    pfd[2].events = (short)grpc_fd_begin_poll(fd, pollset, worker, POLLIN,
-                                              POLLOUT, &fd_watcher);
-    if (pfd[2].events != 0) {
-      nfds++;
-    }
-  } else {
-    gpr_mu_unlock(&pollset->mu);
-  }
-
-  /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid
-     even going into the blocking annotation if possible */
-  /* poll fd count (argument 2) is shortened by one if we have no events
-     to poll on - such that it only includes the kicker */
-  GPR_TIMER_BEGIN("poll", 0);
-  GRPC_SCHEDULING_START_BLOCKING_REGION;
-  r = grpc_poll_function(pfd, nfds, timeout);
-  GRPC_SCHEDULING_END_BLOCKING_REGION;
-  GPR_TIMER_END("poll", 0);
-
-  if (r < 0) {
-    if (errno != EINTR) {
-      gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
-    }
-    if (fd) {
-      grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
-    }
-  } else if (r == 0) {
-    if (fd) {
-      grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
-    }
-  } else {
-    if (pfd[0].revents & POLLIN_CHECK) {
-      grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
-    }
-    if (pfd[1].revents & POLLIN_CHECK) {
-      grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd);
-    }
-    if (nfds > 2) {
-      grpc_fd_end_poll(exec_ctx, &fd_watcher, pfd[2].revents & POLLIN_CHECK,
-                       pfd[2].revents & POLLOUT_CHECK);
-    } else if (fd) {
-      grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
-    }
-  }
-
-  if (fd) {
-    GRPC_FD_UNREF(fd, "basicpoll_begin");
-  }
-}
-
-static void basic_pollset_destroy(grpc_pollset *pollset) {
-  if (pollset->data.ptr != NULL) {
-    GRPC_FD_UNREF(pollset->data.ptr, "basicpoll");
-    pollset->data.ptr = NULL;
-  }
-}
-
-static const grpc_pollset_vtable basic_pollset = {
-    basic_pollset_add_fd, basic_pollset_maybe_work_and_unlock,
-    basic_pollset_destroy, basic_pollset_destroy};
-
-static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null) {
-  pollset->vtable = &basic_pollset;
-  pollset->data.ptr = fd_or_null;
-  if (fd_or_null != 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
deleted file mode 100644
index bbedb66..0000000
--- a/src/core/iomgr/pollset_posix.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_POSIX_H
-#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_POSIX_H
-
-#include <poll.h>
-
-#include <grpc/support/sync.h>
-
-#include "src/core/iomgr/exec_ctx.h"
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/iomgr/pollset.h"
-#include "src/core/iomgr/wakeup_fd_posix.h"
-
-typedef struct grpc_pollset_vtable grpc_pollset_vtable;
-
-/* forward declare only in this file to avoid leaking impl details via
-   pollset.h; real users of grpc_fd should always include 'fd_posix.h' and not
-   use the struct tag */
-struct grpc_fd;
-
-typedef struct grpc_cached_wakeup_fd {
-  grpc_wakeup_fd fd;
-  struct grpc_cached_wakeup_fd *next;
-} grpc_cached_wakeup_fd;
-
-struct grpc_pollset_worker {
-  grpc_cached_wakeup_fd *wakeup_fd;
-  int reevaluate_polling_on_wakeup;
-  int kicked_specifically;
-  struct grpc_pollset_worker *next;
-  struct grpc_pollset_worker *prev;
-};
-
-struct grpc_pollset {
-  /* pollsets under posix can mutate representation as fds are added and
-     removed.
-     For example, we may choose a poll() based implementation on linux for
-     few fds, and an epoll() based implementation for many fds */
-  const grpc_pollset_vtable *vtable;
-  gpr_mu mu;
-  grpc_pollset_worker root_worker;
-  int in_flight_cbs;
-  int shutting_down;
-  int called_shutdown;
-  int kicked_without_pollers;
-  grpc_closure *shutdown_done;
-  grpc_closure_list idle_jobs;
-  union {
-    int fd;
-    void *ptr;
-  } data;
-  /* Local cache of eventfds for workers */
-  grpc_cached_wakeup_fd *local_wakeup_cache;
-};
-
-struct grpc_pollset_vtable {
-  void (*add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                 struct grpc_fd *fd, int and_unlock_pollset);
-  void (*maybe_work_and_unlock)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                                grpc_pollset_worker *worker,
-                                gpr_timespec deadline, gpr_timespec now);
-  void (*finish_shutdown)(grpc_pollset *pollset);
-  void (*destroy)(grpc_pollset *pollset);
-};
-
-/* Add an fd to a pollset */
-void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                         struct grpc_fd *fd);
-
-/* Returns the fd to listen on for kicks */
-int grpc_kick_read_fd(grpc_pollset *p);
-/* Call after polling has been kicked to leave the kicked state */
-void grpc_kick_drain(grpc_pollset *p);
-
-/* 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);
-
-/* Allow kick to wakeup the currently polling worker */
-#define GRPC_POLLSET_CAN_KICK_SELF 1
-/* Force the wakee to repoll when awoken */
-#define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2
-/* As per grpc_pollset_kick, with an extended set of flags (defined above)
-   -- mostly for fd_posix's use. */
-void grpc_pollset_kick_ext(grpc_pollset *p,
-                           grpc_pollset_worker *specific_worker,
-                           uint32_t flags);
-
-/* turn a pollset into a multipoller: platform specific */
-typedef void (*grpc_platform_become_multipoller_type)(grpc_exec_ctx *exec_ctx,
-                                                      grpc_pollset *pollset,
-                                                      struct grpc_fd **fds,
-                                                      size_t fd_count);
-extern grpc_platform_become_multipoller_type grpc_platform_become_multipoller;
-
-void grpc_poll_become_multipoller(grpc_exec_ctx *exec_ctx,
-                                  grpc_pollset *pollset, struct grpc_fd **fds,
-                                  size_t fd_count);
-
-/* Return 1 if the pollset has active threads in grpc_pollset_work (pollset must
- * be locked) */
-int grpc_pollset_has_workers(grpc_pollset *pollset);
-
-void grpc_remove_fd_from_all_epoll_sets(int fd);
-
-/* override to allow tests to hook poll() usage */
-/* NOTE: Any changes to grpc_poll_function must take place when the gRPC
-   is certainly not doing any polling anywhere.
-   Otherwise, there might be a race between changing the variable and actually
-   doing a polling operation */
-typedef int (*grpc_poll_function_type)(struct pollfd *, nfds_t, int);
-extern grpc_poll_function_type grpc_poll_function;
-extern grpc_wakeup_fd grpc_global_wakeup_fd;
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_POSIX_H */
diff --git a/src/core/iomgr/pollset_set.h b/src/core/iomgr/pollset_set.h
deleted file mode 100644
index dddcd83..0000000
--- a/src/core/iomgr/pollset_set.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_H
-#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_H
-
-#include "src/core/iomgr/pollset.h"
-
-/* 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. */
-
-typedef struct grpc_pollset_set grpc_pollset_set;
-
-grpc_pollset_set *grpc_pollset_set_create(void);
-void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set);
-void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
-                                  grpc_pollset_set *pollset_set,
-                                  grpc_pollset *pollset);
-void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
-                                  grpc_pollset_set *pollset_set,
-                                  grpc_pollset *pollset);
-void grpc_pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx,
-                                      grpc_pollset_set *bag,
-                                      grpc_pollset_set *item);
-void grpc_pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
-                                      grpc_pollset_set *bag,
-                                      grpc_pollset_set *item);
-
-#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
deleted file mode 100644
index 9dc9aff..0000000
--- a/src/core/iomgr/pollset_set_posix.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <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_posix.h"
-#include "src/core/iomgr/pollset_set_posix.h"
-
-struct grpc_pollset_set {
-  gpr_mu mu;
-
-  size_t pollset_count;
-  size_t pollset_capacity;
-  grpc_pollset **pollsets;
-
-  size_t pollset_set_count;
-  size_t pollset_set_capacity;
-  struct grpc_pollset_set **pollset_sets;
-
-  size_t fd_count;
-  size_t fd_capacity;
-  grpc_fd **fds;
-};
-
-grpc_pollset_set *grpc_pollset_set_create(void) {
-  grpc_pollset_set *pollset_set = gpr_malloc(sizeof(*pollset_set));
-  memset(pollset_set, 0, sizeof(*pollset_set));
-  gpr_mu_init(&pollset_set->mu);
-  return pollset_set;
-}
-
-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_set");
-  }
-  gpr_free(pollset_set->pollsets);
-  gpr_free(pollset_set->pollset_sets);
-  gpr_free(pollset_set->fds);
-  gpr_free(pollset_set);
-}
-
-void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
-                                  grpc_pollset_set *pollset_set,
-                                  grpc_pollset *pollset) {
-  size_t i, j;
-  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, j = 0; i < pollset_set->fd_count; i++) {
-    if (grpc_fd_is_orphaned(pollset_set->fds[i])) {
-      GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set");
-    } else {
-      grpc_pollset_add_fd(exec_ctx, pollset, pollset_set->fds[i]);
-      pollset_set->fds[j++] = pollset_set->fds[i];
-    }
-  }
-  pollset_set->fd_count = j;
-  gpr_mu_unlock(&pollset_set->mu);
-}
-
-void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
-                                  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_pollset_set(grpc_exec_ctx *exec_ctx,
-                                      grpc_pollset_set *bag,
-                                      grpc_pollset_set *item) {
-  size_t i, j;
-  gpr_mu_lock(&bag->mu);
-  if (bag->pollset_set_count == bag->pollset_set_capacity) {
-    bag->pollset_set_capacity = GPR_MAX(8, 2 * bag->pollset_set_capacity);
-    bag->pollset_sets =
-        gpr_realloc(bag->pollset_sets,
-                    bag->pollset_set_capacity * sizeof(*bag->pollset_sets));
-  }
-  bag->pollset_sets[bag->pollset_set_count++] = item;
-  for (i = 0, j = 0; i < bag->fd_count; i++) {
-    if (grpc_fd_is_orphaned(bag->fds[i])) {
-      GRPC_FD_UNREF(bag->fds[i], "pollset_set");
-    } else {
-      grpc_pollset_set_add_fd(exec_ctx, item, bag->fds[i]);
-      bag->fds[j++] = bag->fds[i];
-    }
-  }
-  bag->fd_count = j;
-  gpr_mu_unlock(&bag->mu);
-}
-
-void grpc_pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
-                                      grpc_pollset_set *bag,
-                                      grpc_pollset_set *item) {
-  size_t i;
-  gpr_mu_lock(&bag->mu);
-  for (i = 0; i < bag->pollset_set_count; i++) {
-    if (bag->pollset_sets[i] == item) {
-      bag->pollset_set_count--;
-      GPR_SWAP(grpc_pollset_set *, bag->pollset_sets[i],
-               bag->pollset_sets[bag->pollset_set_count]);
-      break;
-    }
-  }
-  gpr_mu_unlock(&bag->mu);
-}
-
-void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx,
-                             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(exec_ctx, pollset_set->pollsets[i], fd);
-  }
-  for (i = 0; i < pollset_set->pollset_set_count; i++) {
-    grpc_pollset_set_add_fd(exec_ctx, pollset_set->pollset_sets[i], fd);
-  }
-  gpr_mu_unlock(&pollset_set->mu);
-}
-
-void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
-                             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;
-    }
-  }
-  for (i = 0; i < pollset_set->pollset_set_count; i++) {
-    grpc_pollset_set_del_fd(exec_ctx, pollset_set->pollset_sets[i], fd);
-  }
-  gpr_mu_unlock(&pollset_set->mu);
-}
-
-#endif /* GPR_POSIX_SOCKET */
diff --git a/src/core/iomgr/pollset_set_posix.h b/src/core/iomgr/pollset_set_posix.h
deleted file mode 100644
index 7d1aaf4..0000000
--- a/src/core/iomgr/pollset_set_posix.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_POSIX_H
-#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_POSIX_H
-
-#include "src/core/iomgr/fd_posix.h"
-#include "src/core/iomgr/pollset_set.h"
-
-void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx,
-                             grpc_pollset_set *pollset_set, grpc_fd *fd);
-void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
-                             grpc_pollset_set *pollset_set, grpc_fd *fd);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */
diff --git a/src/core/iomgr/pollset_set_windows.c b/src/core/iomgr/pollset_set_windows.c
deleted file mode 100644
index d17b65b..0000000
--- a/src/core/iomgr/pollset_set_windows.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WINSOCK_SOCKET
-
-#include "src/core/iomgr/pollset_set_windows.h"
-
-grpc_pollset_set* grpc_pollset_set_create(void) { return NULL; }
-
-void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {}
-
-void grpc_pollset_set_add_pollset(grpc_exec_ctx* exec_ctx,
-                                  grpc_pollset_set* pollset_set,
-                                  grpc_pollset* pollset) {}
-
-void grpc_pollset_set_del_pollset(grpc_exec_ctx* exec_ctx,
-                                  grpc_pollset_set* pollset_set,
-                                  grpc_pollset* pollset) {}
-
-void grpc_pollset_set_add_pollset_set(grpc_exec_ctx* exec_ctx,
-                                      grpc_pollset_set* bag,
-                                      grpc_pollset_set* item) {}
-
-void grpc_pollset_set_del_pollset_set(grpc_exec_ctx* exec_ctx,
-                                      grpc_pollset_set* bag,
-                                      grpc_pollset_set* item) {}
-
-#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/pollset_set_windows.h b/src/core/iomgr/pollset_set_windows.h
deleted file mode 100644
index 9661cd2..0000000
--- a/src/core/iomgr/pollset_set_windows.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_WINDOWS_H
-#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_WINDOWS_H
-
-#include "src/core/iomgr/pollset_set.h"
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */
diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c
deleted file mode 100644
index c7f30f4..0000000
--- a/src/core/iomgr/pollset_windows.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WINSOCK_SOCKET
-
-#include <grpc/support/log.h>
-#include <grpc/support/thd.h>
-
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/iocp_windows.h"
-#include "src/core/iomgr/pollset.h"
-#include "src/core/iomgr/pollset_windows.h"
-
-gpr_mu grpc_polling_mu;
-static grpc_pollset_worker *g_active_poller;
-static grpc_pollset_worker g_global_root_worker;
-
-void grpc_pollset_global_init() {
-  gpr_mu_init(&grpc_polling_mu);
-  g_active_poller = NULL;
-  g_global_root_worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next =
-      g_global_root_worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].prev =
-          &g_global_root_worker;
-}
-
-void grpc_pollset_global_shutdown() { gpr_mu_destroy(&grpc_polling_mu); }
-
-static void remove_worker(grpc_pollset_worker *worker,
-                          grpc_pollset_worker_link_type type) {
-  worker->links[type].prev->links[type].next = worker->links[type].next;
-  worker->links[type].next->links[type].prev = worker->links[type].prev;
-  worker->links[type].next = worker->links[type].prev = worker;
-}
-
-static int has_workers(grpc_pollset_worker *root,
-                       grpc_pollset_worker_link_type type) {
-  return root->links[type].next != root;
-}
-
-static grpc_pollset_worker *pop_front_worker(
-    grpc_pollset_worker *root, grpc_pollset_worker_link_type type) {
-  if (has_workers(root, type)) {
-    grpc_pollset_worker *w = root->links[type].next;
-    remove_worker(w, type);
-    return w;
-  } else {
-    return NULL;
-  }
-}
-
-static void push_front_worker(grpc_pollset_worker *root,
-                              grpc_pollset_worker_link_type type,
-                              grpc_pollset_worker *worker) {
-  worker->links[type].prev = root;
-  worker->links[type].next = worker->links[type].prev->links[type].next;
-  worker->links[type].prev->links[type].next =
-      worker->links[type].next->links[type].prev = worker;
-}
-
-size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); }
-
-/* There isn't really any such thing as a pollset under Windows, due to the
-   nature of the IO completion ports. We're still going to provide a minimal
-   set of features for the sake of the rest of grpc. But grpc_pollset_work
-   won't actually do any polling, and return as quickly as possible. */
-
-void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
-  *mu = &grpc_polling_mu;
-  memset(pollset, 0, sizeof(*pollset));
-  pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next =
-      pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev =
-          &pollset->root_worker;
-}
-
-void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                           grpc_closure *closure) {
-  pollset->shutting_down = 1;
-  grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
-  if (!pollset->is_iocp_worker) {
-    grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
-  } else {
-    pollset->on_shutdown = closure;
-  }
-}
-
-void grpc_pollset_destroy(grpc_pollset *pollset) {}
-
-void grpc_pollset_reset(grpc_pollset *pollset) {
-  GPR_ASSERT(pollset->shutting_down);
-  GPR_ASSERT(
-      !has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET));
-  pollset->shutting_down = 0;
-  pollset->is_iocp_worker = 0;
-  pollset->kicked_without_pollers = 0;
-  pollset->on_shutdown = NULL;
-}
-
-void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
-                       grpc_pollset_worker **worker_hdl, gpr_timespec now,
-                       gpr_timespec deadline) {
-  grpc_pollset_worker worker;
-  *worker_hdl = &worker;
-
-  int added_worker = 0;
-  worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next =
-      worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev =
-          worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next =
-              worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].prev = NULL;
-  worker.kicked = 0;
-  worker.pollset = pollset;
-  gpr_cv_init(&worker.cv);
-  if (!pollset->kicked_without_pollers && !pollset->shutting_down) {
-    if (g_active_poller == NULL) {
-      grpc_pollset_worker *next_worker;
-      /* become poller */
-      pollset->is_iocp_worker = 1;
-      g_active_poller = &worker;
-      gpr_mu_unlock(&grpc_polling_mu);
-      grpc_iocp_work(exec_ctx, deadline);
-      grpc_exec_ctx_flush(exec_ctx);
-      gpr_mu_lock(&grpc_polling_mu);
-      pollset->is_iocp_worker = 0;
-      g_active_poller = NULL;
-      /* try to get a worker from this pollsets worker list */
-      next_worker = pop_front_worker(&pollset->root_worker,
-                                     GRPC_POLLSET_WORKER_LINK_POLLSET);
-      if (next_worker == NULL) {
-        /* try to get a worker from the global list */
-        next_worker = pop_front_worker(&g_global_root_worker,
-                                       GRPC_POLLSET_WORKER_LINK_GLOBAL);
-      }
-      if (next_worker != NULL) {
-        next_worker->kicked = 1;
-        gpr_cv_signal(&next_worker->cv);
-      }
-
-      if (pollset->shutting_down && pollset->on_shutdown != NULL) {
-        grpc_exec_ctx_enqueue(exec_ctx, pollset->on_shutdown, true, NULL);
-        pollset->on_shutdown = NULL;
-      }
-      goto done;
-    }
-    push_front_worker(&g_global_root_worker, GRPC_POLLSET_WORKER_LINK_GLOBAL,
-                      &worker);
-    push_front_worker(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET,
-                      &worker);
-    added_worker = 1;
-    while (!worker.kicked) {
-      if (gpr_cv_wait(&worker.cv, &grpc_polling_mu, deadline)) {
-        break;
-      }
-    }
-  } else {
-    pollset->kicked_without_pollers = 0;
-  }
-done:
-  if (!grpc_closure_list_empty(exec_ctx->closure_list)) {
-    gpr_mu_unlock(&grpc_polling_mu);
-    grpc_exec_ctx_flush(exec_ctx);
-    gpr_mu_lock(&grpc_polling_mu);
-  }
-  if (added_worker) {
-    remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_GLOBAL);
-    remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_POLLSET);
-  }
-  gpr_cv_destroy(&worker.cv);
-  *worker_hdl = NULL;
-}
-
-void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) {
-  if (specific_worker != NULL) {
-    if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
-      for (specific_worker =
-               p->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next;
-           specific_worker != &p->root_worker;
-           specific_worker =
-               specific_worker->links[GRPC_POLLSET_WORKER_LINK_POLLSET].next) {
-        specific_worker->kicked = 1;
-        gpr_cv_signal(&specific_worker->cv);
-      }
-      p->kicked_without_pollers = 1;
-      if (p->is_iocp_worker) {
-        grpc_iocp_kick();
-      }
-    } else {
-      if (p->is_iocp_worker && g_active_poller == specific_worker) {
-        grpc_iocp_kick();
-      } else {
-        specific_worker->kicked = 1;
-        gpr_cv_signal(&specific_worker->cv);
-      }
-    }
-  } else {
-    specific_worker =
-        pop_front_worker(&p->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET);
-    if (specific_worker != NULL) {
-      grpc_pollset_kick(p, specific_worker);
-    } else if (p->is_iocp_worker) {
-      grpc_iocp_kick();
-    } else {
-      p->kicked_without_pollers = 1;
-    }
-  }
-}
-
-void grpc_kick_poller(void) { grpc_iocp_kick(); }
-
-#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/pollset_windows.h b/src/core/iomgr/pollset_windows.h
deleted file mode 100644
index dc0b7a4..0000000
--- a/src/core/iomgr/pollset_windows.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H
-#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H
-
-#include <grpc/support/sync.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
-   used to synchronize with the IOCP, and workers are condition variables
-   used to block threads until work is ready. */
-
-typedef enum {
-  GRPC_POLLSET_WORKER_LINK_POLLSET = 0,
-  GRPC_POLLSET_WORKER_LINK_GLOBAL,
-  GRPC_POLLSET_WORKER_LINK_TYPES
-} grpc_pollset_worker_link_type;
-
-typedef struct grpc_pollset_worker_link {
-  struct grpc_pollset_worker *next;
-  struct grpc_pollset_worker *prev;
-} grpc_pollset_worker_link;
-
-struct grpc_pollset;
-typedef struct grpc_pollset grpc_pollset;
-
-typedef struct grpc_pollset_worker {
-  gpr_cv cv;
-  int kicked;
-  struct grpc_pollset *pollset;
-  grpc_pollset_worker_link links[GRPC_POLLSET_WORKER_LINK_TYPES];
-} grpc_pollset_worker;
-
-struct grpc_pollset {
-  int shutting_down;
-  int kicked_without_pollers;
-  int is_iocp_worker;
-  grpc_pollset_worker root_worker;
-  grpc_closure *on_shutdown;
-};
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */
diff --git a/src/core/iomgr/resolve_address.h b/src/core/iomgr/resolve_address.h
deleted file mode 100644
index 01eedff..0000000
--- a/src/core/iomgr/resolve_address.h
+++ /dev/null
@@ -1,72 +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_RESOLVE_ADDRESS_H
-#define GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H
-
-#include <stddef.h>
-#include "src/core/iomgr/exec_ctx.h"
-#include "src/core/iomgr/iomgr.h"
-
-#define GRPC_MAX_SOCKADDR_SIZE 128
-
-typedef struct {
-  char addr[GRPC_MAX_SOCKADDR_SIZE];
-  size_t len;
-} grpc_resolved_address;
-
-typedef struct {
-  size_t naddrs;
-  grpc_resolved_address *addrs;
-} grpc_resolved_addresses;
-
-/* Async result callback:
-   On success: addresses is the result, and the callee must call
-   grpc_resolved_addresses_destroy when it's done with them
-   On failure: addresses is NULL */
-typedef void (*grpc_resolve_cb)(grpc_exec_ctx *exec_ctx, void *arg,
-                                grpc_resolved_addresses *addresses);
-/* Asynchronously resolve addr. Use default_port if a port isn't designated
-   in addr, otherwise use the port in addr. */
-/* TODO(ctiller): add a timeout here */
-void grpc_resolve_address(const char *addr, const char *default_port,
-                          grpc_resolve_cb cb, void *arg);
-/* Destroy resolved addresses */
-void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addresses);
-
-/* Resolve addr in a blocking fashion. Returns NULL on failure. On success,
-   result must be freed with grpc_resolved_addresses_destroy. */
-grpc_resolved_addresses *grpc_blocking_resolve_address(
-    const char *addr, const char *default_port);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H */
diff --git a/src/core/iomgr/resolve_address_posix.c b/src/core/iomgr/resolve_address_posix.c
deleted file mode 100644
index c51745b..0000000
--- a/src/core/iomgr/resolve_address_posix.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/iomgr/sockaddr.h"
-#include "src/core/iomgr/resolve_address.h"
-
-#include <sys/types.h>
-#include <sys/un.h>
-#include <string.h>
-
-#include "src/core/iomgr/executor.h"
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/support/block_annotate.h"
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/time.h>
-#include <grpc/support/useful.h>
-
-typedef struct {
-  char *name;
-  char *default_port;
-  grpc_resolve_cb cb;
-  grpc_closure request_closure;
-  void *arg;
-} request;
-
-grpc_resolved_addresses *grpc_blocking_resolve_address(
-    const char *name, const char *default_port) {
-  struct addrinfo hints;
-  struct addrinfo *result = NULL, *resp;
-  char *host;
-  char *port;
-  int s;
-  size_t i;
-  grpc_resolved_addresses *addrs = NULL;
-  struct sockaddr_un *un;
-
-  if (name[0] == 'u' && name[1] == 'n' && name[2] == 'i' && name[3] == 'x' &&
-      name[4] == ':' && name[5] != 0) {
-    addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
-    addrs->naddrs = 1;
-    addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address));
-    un = (struct sockaddr_un *)addrs->addrs->addr;
-    un->sun_family = AF_UNIX;
-    strcpy(un->sun_path, name + 5);
-    addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1;
-    return addrs;
-  }
-
-  /* parse name, splitting it into host and port parts */
-  gpr_split_host_port(name, &host, &port);
-  if (host == NULL) {
-    gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name);
-    goto done;
-  }
-  if (port == NULL) {
-    if (default_port == NULL) {
-      gpr_log(GPR_ERROR, "no port in name '%s'", name);
-      goto done;
-    }
-    port = gpr_strdup(default_port);
-  }
-
-  /* Call getaddrinfo */
-  memset(&hints, 0, sizeof(hints));
-  hints.ai_family = AF_UNSPEC;     /* ipv4 or ipv6 */
-  hints.ai_socktype = SOCK_STREAM; /* stream socket */
-  hints.ai_flags = AI_PASSIVE;     /* for wildcard IP address */
-
-  GRPC_SCHEDULING_START_BLOCKING_REGION;
-  s = getaddrinfo(host, port, &hints, &result);
-  GRPC_SCHEDULING_END_BLOCKING_REGION;
-
-  if (s != 0) {
-    /* Retry if well-known service name is recognized */
-    char *svc[][2] = {{"http", "80"}, {"https", "443"}};
-    for (i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
-      if (strcmp(port, svc[i][0]) == 0) {
-        GRPC_SCHEDULING_START_BLOCKING_REGION;
-        s = getaddrinfo(host, svc[i][1], &hints, &result);
-        GRPC_SCHEDULING_END_BLOCKING_REGION;
-        break;
-      }
-    }
-  }
-
-  if (s != 0) {
-    gpr_log(GPR_ERROR, "getaddrinfo: %s", gai_strerror(s));
-    goto done;
-  }
-
-  /* Success path: set addrs non-NULL, fill it in */
-  addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
-  addrs->naddrs = 0;
-  for (resp = result; resp != NULL; resp = resp->ai_next) {
-    addrs->naddrs++;
-  }
-  addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs);
-  i = 0;
-  for (resp = result; resp != NULL; resp = resp->ai_next) {
-    memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
-    addrs->addrs[i].len = resp->ai_addrlen;
-    i++;
-  }
-
-done:
-  gpr_free(host);
-  gpr_free(port);
-  if (result) {
-    freeaddrinfo(result);
-  }
-  return addrs;
-}
-
-/* Callback to be passed to grpc_executor to asynch-ify
- * grpc_blocking_resolve_address */
-static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) {
-  request *r = rp;
-  grpc_resolved_addresses *resolved =
-      grpc_blocking_resolve_address(r->name, r->default_port);
-  void *arg = r->arg;
-  grpc_resolve_cb cb = r->cb;
-  gpr_free(r->name);
-  gpr_free(r->default_port);
-  cb(exec_ctx, arg, resolved);
-  gpr_free(r);
-}
-
-void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) {
-  gpr_free(addrs->addrs);
-  gpr_free(addrs);
-}
-
-void grpc_resolve_address(const char *name, const char *default_port,
-                          grpc_resolve_cb cb, void *arg) {
-  request *r = gpr_malloc(sizeof(request));
-  grpc_closure_init(&r->request_closure, do_request_thread, r);
-  r->name = gpr_strdup(name);
-  r->default_port = gpr_strdup(default_port);
-  r->cb = cb;
-  r->arg = arg;
-  grpc_executor_enqueue(&r->request_closure, 1);
-}
-
-#endif
diff --git a/src/core/iomgr/resolve_address_windows.c b/src/core/iomgr/resolve_address_windows.c
deleted file mode 100644
index 28c8661..0000000
--- a/src/core/iomgr/resolve_address_windows.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-#ifdef GPR_WINSOCK_SOCKET
-
-#include "src/core/iomgr/sockaddr.h"
-#include "src/core/iomgr/resolve_address.h"
-
-#include <sys/types.h>
-#include <string.h>
-
-#include "src/core/iomgr/executor.h"
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/support/block_annotate.h"
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/log.h>
-#include <grpc/support/log_win32.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/time.h>
-
-typedef struct {
-  char *name;
-  char *default_port;
-  grpc_resolve_cb cb;
-  grpc_closure request_closure;
-  void *arg;
-} request;
-
-grpc_resolved_addresses *grpc_blocking_resolve_address(
-    const char *name, const char *default_port) {
-  struct addrinfo hints;
-  struct addrinfo *result = NULL, *resp;
-  char *host;
-  char *port;
-  int s;
-  size_t i;
-  grpc_resolved_addresses *addrs = NULL;
-
-  /* parse name, splitting it into host and port parts */
-  gpr_split_host_port(name, &host, &port);
-  if (host == NULL) {
-    gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name);
-    goto done;
-  }
-  if (port == NULL) {
-    if (default_port == NULL) {
-      gpr_log(GPR_ERROR, "no port in name '%s'", name);
-      goto done;
-    }
-    port = gpr_strdup(default_port);
-  }
-
-  /* Call getaddrinfo */
-  memset(&hints, 0, sizeof(hints));
-  hints.ai_family = AF_UNSPEC;     /* ipv4 or ipv6 */
-  hints.ai_socktype = SOCK_STREAM; /* stream socket */
-  hints.ai_flags = AI_PASSIVE;     /* for wildcard IP address */
-
-  GRPC_SCHEDULING_START_BLOCKING_REGION;
-  s = getaddrinfo(host, port, &hints, &result);
-  GRPC_SCHEDULING_END_BLOCKING_REGION;
-  if (s != 0) {
-    char *error_message = gpr_format_message(s);
-    gpr_log(GPR_ERROR, "getaddrinfo: %s", error_message);
-    gpr_free(error_message);
-    goto done;
-  }
-
-  /* Success path: set addrs non-NULL, fill it in */
-  addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
-  addrs->naddrs = 0;
-  for (resp = result; resp != NULL; resp = resp->ai_next) {
-    addrs->naddrs++;
-  }
-  addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs);
-  i = 0;
-  for (resp = result; resp != NULL; resp = resp->ai_next) {
-    memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
-    addrs->addrs[i].len = resp->ai_addrlen;
-    i++;
-  }
-
-  {
-    for (i = 0; i < addrs->naddrs; i++) {
-      char *buf;
-      grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr,
-                              0);
-      gpr_free(buf);
-    }
-  }
-
-done:
-  gpr_free(host);
-  gpr_free(port);
-  if (result) {
-    freeaddrinfo(result);
-  }
-  return addrs;
-}
-
-/* Callback to be passed to grpc_executor to asynch-ify
- * grpc_blocking_resolve_address */
-static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) {
-  request *r = rp;
-  grpc_resolved_addresses *resolved =
-      grpc_blocking_resolve_address(r->name, r->default_port);
-  void *arg = r->arg;
-  grpc_resolve_cb cb = r->cb;
-  gpr_free(r->name);
-  gpr_free(r->default_port);
-  cb(exec_ctx, arg, resolved);
-  gpr_free(r);
-}
-
-void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) {
-  gpr_free(addrs->addrs);
-  gpr_free(addrs);
-}
-
-void grpc_resolve_address(const char *name, const char *default_port,
-                          grpc_resolve_cb cb, void *arg) {
-  request *r = gpr_malloc(sizeof(request));
-  grpc_closure_init(&r->request_closure, do_request_thread, r);
-  r->name = gpr_strdup(name);
-  r->default_port = gpr_strdup(default_port);
-  r->cb = cb;
-  r->arg = arg;
-  grpc_executor_enqueue(&r->request_closure, 1);
-}
-
-#endif
diff --git a/src/core/iomgr/sockaddr.h b/src/core/iomgr/sockaddr.h
deleted file mode 100644
index e41e1ec..0000000
--- a/src/core/iomgr/sockaddr.h
+++ /dev/null
@@ -1,47 +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_SOCKADDR_H
-#define GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_H
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WIN32
-#include "src/core/iomgr/sockaddr_win32.h"
-#endif
-
-#ifdef GPR_POSIX_SOCKETADDR
-#include "src/core/iomgr/sockaddr_posix.h"
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_H */
diff --git a/src/core/iomgr/sockaddr_posix.h b/src/core/iomgr/sockaddr_posix.h
deleted file mode 100644
index 388abb3..0000000
--- a/src/core/iomgr/sockaddr_posix.h
+++ /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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_POSIX_H
-#define GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_POSIX_H
-
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <unistd.h>
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_POSIX_H */
diff --git a/src/core/iomgr/sockaddr_utils.c b/src/core/iomgr/sockaddr_utils.c
deleted file mode 100644
index 61006d7..0000000
--- a/src/core/iomgr/sockaddr_utils.c
+++ /dev/null
@@ -1,234 +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/iomgr/sockaddr_utils.h"
-
-#include <errno.h>
-#include <string.h>
-
-#ifdef GPR_POSIX_SOCKET
-#include <sys/un.h>
-#endif
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/support/string.h"
-
-static const uint8_t kV4MappedPrefix[] = {0, 0, 0, 0, 0,    0,
-                                          0, 0, 0, 0, 0xff, 0xff};
-
-int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr,
-                              struct sockaddr_in *addr4_out) {
-  GPR_ASSERT(addr != (struct sockaddr *)addr4_out);
-  if (addr->sa_family == AF_INET6) {
-    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
-    if (memcmp(addr6->sin6_addr.s6_addr, kV4MappedPrefix,
-               sizeof(kV4MappedPrefix)) == 0) {
-      if (addr4_out != NULL) {
-        /* Normalize ::ffff:0.0.0.0/96 to IPv4. */
-        memset(addr4_out, 0, sizeof(*addr4_out));
-        addr4_out->sin_family = AF_INET;
-        /* s6_addr32 would be nice, but it's non-standard. */
-        memcpy(&addr4_out->sin_addr, &addr6->sin6_addr.s6_addr[12], 4);
-        addr4_out->sin_port = addr6->sin6_port;
-      }
-      return 1;
-    }
-  }
-  return 0;
-}
-
-int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr,
-                              struct sockaddr_in6 *addr6_out) {
-  GPR_ASSERT(addr != (struct sockaddr *)addr6_out);
-  if (addr->sa_family == AF_INET) {
-    const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
-    memset(addr6_out, 0, sizeof(*addr6_out));
-    addr6_out->sin6_family = AF_INET6;
-    memcpy(&addr6_out->sin6_addr.s6_addr[0], kV4MappedPrefix, 12);
-    memcpy(&addr6_out->sin6_addr.s6_addr[12], &addr4->sin_addr, 4);
-    addr6_out->sin6_port = addr4->sin_port;
-    return 1;
-  }
-  return 0;
-}
-
-int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out) {
-  struct sockaddr_in addr4_normalized;
-  if (grpc_sockaddr_is_v4mapped(addr, &addr4_normalized)) {
-    addr = (struct sockaddr *)&addr4_normalized;
-  }
-  if (addr->sa_family == AF_INET) {
-    /* Check for 0.0.0.0 */
-    const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
-    if (addr4->sin_addr.s_addr != 0) {
-      return 0;
-    }
-    *port_out = ntohs(addr4->sin_port);
-    return 1;
-  } else if (addr->sa_family == AF_INET6) {
-    /* Check for :: */
-    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
-    int i;
-    for (i = 0; i < 16; i++) {
-      if (addr6->sin6_addr.s6_addr[i] != 0) {
-        return 0;
-      }
-    }
-    *port_out = ntohs(addr6->sin6_port);
-    return 1;
-  } else {
-    return 0;
-  }
-}
-
-void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out,
-                                  struct sockaddr_in6 *wild6_out) {
-  grpc_sockaddr_make_wildcard4(port, wild4_out);
-  grpc_sockaddr_make_wildcard6(port, wild6_out);
-}
-
-void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out) {
-  GPR_ASSERT(port >= 0 && port < 65536);
-  memset(wild_out, 0, sizeof(*wild_out));
-  wild_out->sin_family = AF_INET;
-  wild_out->sin_port = htons((uint16_t)port);
-}
-
-void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out) {
-  GPR_ASSERT(port >= 0 && port < 65536);
-  memset(wild_out, 0, sizeof(*wild_out));
-  wild_out->sin6_family = AF_INET6;
-  wild_out->sin6_port = htons((uint16_t)port);
-}
-
-int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr,
-                            int normalize) {
-  const int save_errno = errno;
-  struct sockaddr_in addr_normalized;
-  char ntop_buf[INET6_ADDRSTRLEN];
-  const void *ip = NULL;
-  int port;
-  int ret;
-
-  *out = NULL;
-  if (normalize && grpc_sockaddr_is_v4mapped(addr, &addr_normalized)) {
-    addr = (const struct sockaddr *)&addr_normalized;
-  }
-  if (addr->sa_family == AF_INET) {
-    const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
-    ip = &addr4->sin_addr;
-    port = ntohs(addr4->sin_port);
-  } else if (addr->sa_family == AF_INET6) {
-    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
-    ip = &addr6->sin6_addr;
-    port = ntohs(addr6->sin6_port);
-  }
-  /* Windows inet_ntop wants a mutable ip pointer */
-  if (ip != NULL &&
-      inet_ntop(addr->sa_family, (void *)ip, ntop_buf, sizeof(ntop_buf)) !=
-          NULL) {
-    ret = gpr_join_host_port(out, ntop_buf, port);
-  } else {
-    ret = gpr_asprintf(out, "(sockaddr family=%d)", addr->sa_family);
-  }
-  /* This is probably redundant, but we wouldn't want to log the wrong error. */
-  errno = save_errno;
-  return ret;
-}
-
-char *grpc_sockaddr_to_uri(const struct sockaddr *addr) {
-  char *temp;
-  char *result;
-  struct sockaddr_in addr_normalized;
-
-  if (grpc_sockaddr_is_v4mapped(addr, &addr_normalized)) {
-    addr = (const struct sockaddr *)&addr_normalized;
-  }
-
-  switch (addr->sa_family) {
-    case AF_INET:
-      grpc_sockaddr_to_string(&temp, addr, 0);
-      gpr_asprintf(&result, "ipv4:%s", temp);
-      gpr_free(temp);
-      return result;
-    case AF_INET6:
-      grpc_sockaddr_to_string(&temp, addr, 0);
-      gpr_asprintf(&result, "ipv6:%s", temp);
-      gpr_free(temp);
-      return result;
-#ifdef GPR_POSIX_SOCKET
-    case AF_UNIX:
-      gpr_asprintf(&result, "unix:%s", ((struct sockaddr_un *)addr)->sun_path);
-      return result;
-#endif
-  }
-
-  return NULL;
-}
-
-int grpc_sockaddr_get_port(const struct sockaddr *addr) {
-  switch (addr->sa_family) {
-    case AF_INET:
-      return ntohs(((struct sockaddr_in *)addr)->sin_port);
-    case AF_INET6:
-      return ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
-    case AF_UNIX:
-      return 1;
-    default:
-      gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_get_port",
-              addr->sa_family);
-      return 0;
-  }
-}
-
-int grpc_sockaddr_set_port(const struct sockaddr *addr, int port) {
-  switch (addr->sa_family) {
-    case AF_INET:
-      GPR_ASSERT(port >= 0 && port < 65536);
-      ((struct sockaddr_in *)addr)->sin_port = htons((uint16_t)port);
-      return 1;
-    case AF_INET6:
-      GPR_ASSERT(port >= 0 && port < 65536);
-      ((struct sockaddr_in6 *)addr)->sin6_port = htons((uint16_t)port);
-      return 1;
-    default:
-      gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port",
-              addr->sa_family);
-      return 0;
-  }
-}
diff --git a/src/core/iomgr/sockaddr_utils.h b/src/core/iomgr/sockaddr_utils.h
deleted file mode 100644
index 6f7a279..0000000
--- a/src/core/iomgr/sockaddr_utils.h
+++ /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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_UTILS_H
-#define GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_UTILS_H
-
-#include "src/core/iomgr/sockaddr.h"
-
-/* Returns true if addr is an IPv4-mapped IPv6 address within the
-   ::ffff:0.0.0.0/96 range, or false otherwise.
-
-   If addr4_out is non-NULL, the inner IPv4 address will be copied here when
-   returning true. */
-int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr,
-                              struct sockaddr_in *addr4_out);
-
-/* If addr is an AF_INET address, writes the corresponding ::ffff:0.0.0.0/96
-   address to addr6_out and returns true.  Otherwise returns false. */
-int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr,
-                              struct sockaddr_in6 *addr6_out);
-
-/* If addr is ::, 0.0.0.0, or ::ffff:0.0.0.0, writes the port number to
-   *port_out (if not NULL) and returns true, otherwise returns false. */
-int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out);
-
-/* Writes 0.0.0.0:port and [::]:port to separate sockaddrs. */
-void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out,
-                                  struct sockaddr_in6 *wild6_out);
-
-/* Writes 0.0.0.0:port. */
-void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out);
-
-/* Writes [::]:port. */
-void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out);
-
-/* Return the IP port number of a sockaddr */
-int grpc_sockaddr_get_port(const struct sockaddr *addr);
-
-/* Set IP port number of a sockaddr */
-int grpc_sockaddr_set_port(const struct sockaddr *addr, int port);
-
-/* Converts a sockaddr into a newly-allocated human-readable string.
-
-   Currently, only the AF_INET and AF_INET6 families are recognized.
-   If the normalize flag is enabled, ::ffff:0.0.0.0/96 IPv6 addresses are
-   displayed as plain IPv4.
-
-   Usage is similar to gpr_asprintf: returns the number of bytes written
-   (excluding the final '\0'), and *out points to a string which must later be
-   destroyed using gpr_free().
-
-   In the unlikely event of an error, returns -1 and sets *out to NULL.
-   The existing value of errno is always preserved. */
-int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr,
-                            int normalize);
-
-char *grpc_sockaddr_to_uri(const struct sockaddr *addr);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_UTILS_H */
diff --git a/src/core/iomgr/sockaddr_win32.h b/src/core/iomgr/sockaddr_win32.h
deleted file mode 100644
index 8e3946a..0000000
--- a/src/core/iomgr/sockaddr_win32.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H
-#define GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H
-
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <mswsock.h>
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H */
diff --git a/src/core/iomgr/socket_utils_common_posix.c b/src/core/iomgr/socket_utils_common_posix.c
deleted file mode 100644
index a9af594..0000000
--- a/src/core/iomgr/socket_utils_common_posix.c
+++ /dev/null
@@ -1,208 +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/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/iomgr/socket_utils_posix.h"
-
-#include <arpa/inet.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/support/string.h"
-#include <grpc/support/host_port.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/sync.h>
-
-/* set a socket to non blocking mode */
-int grpc_set_socket_nonblocking(int fd, int non_blocking) {
-  int oldflags = fcntl(fd, F_GETFL, 0);
-  if (oldflags < 0) {
-    return 0;
-  }
-
-  if (non_blocking) {
-    oldflags |= O_NONBLOCK;
-  } else {
-    oldflags &= ~O_NONBLOCK;
-  }
-
-  if (fcntl(fd, F_SETFL, oldflags) != 0) {
-    return 0;
-  }
-
-  return 1;
-}
-
-int grpc_set_socket_no_sigpipe_if_possible(int fd) {
-#ifdef GPR_HAVE_SO_NOSIGPIPE
-  int val = 1;
-  int newval;
-  socklen_t intlen = sizeof(newval);
-  return 0 == setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)) &&
-         0 == getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &newval, &intlen) &&
-         (newval != 0) == val;
-#else
-  return 1;
-#endif
-}
-
-/* set a socket to close on exec */
-int grpc_set_socket_cloexec(int fd, int close_on_exec) {
-  int oldflags = fcntl(fd, F_GETFD, 0);
-  if (oldflags < 0) {
-    return 0;
-  }
-
-  if (close_on_exec) {
-    oldflags |= FD_CLOEXEC;
-  } else {
-    oldflags &= ~FD_CLOEXEC;
-  }
-
-  if (fcntl(fd, F_SETFD, oldflags) != 0) {
-    return 0;
-  }
-
-  return 1;
-}
-
-/* set a socket to reuse old addresses */
-int grpc_set_socket_reuse_addr(int fd, int reuse) {
-  int val = (reuse != 0);
-  int newval;
-  socklen_t intlen = sizeof(newval);
-  return 0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) &&
-         0 == getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen) &&
-         (newval != 0) == val;
-}
-
-/* disable nagle */
-int grpc_set_socket_low_latency(int fd, int low_latency) {
-  int val = (low_latency != 0);
-  int newval;
-  socklen_t intlen = sizeof(newval);
-  return 0 == setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) &&
-         0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen) &&
-         (newval != 0) == val;
-}
-
-static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
-static int g_ipv6_loopback_available;
-
-static void probe_ipv6_once(void) {
-  int fd = socket(AF_INET6, SOCK_STREAM, 0);
-  g_ipv6_loopback_available = 0;
-  if (fd < 0) {
-    gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
-  } else {
-    struct sockaddr_in6 addr;
-    memset(&addr, 0, sizeof(addr));
-    addr.sin6_family = AF_INET6;
-    addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
-    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
-      g_ipv6_loopback_available = 1;
-    } else {
-      gpr_log(GPR_INFO,
-              "Disabling AF_INET6 sockets because ::1 is not available.");
-    }
-    close(fd);
-  }
-}
-
-int grpc_ipv6_loopback_available(void) {
-  gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
-  return g_ipv6_loopback_available;
-}
-
-/* This should be 0 in production, but it may be enabled for testing or
-   debugging purposes, to simulate an environment where IPv6 sockets can't
-   also speak IPv4. */
-int grpc_forbid_dualstack_sockets_for_testing = 0;
-
-static int set_socket_dualstack(int fd) {
-  if (!grpc_forbid_dualstack_sockets_for_testing) {
-    const int off = 0;
-    return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off));
-  } else {
-    /* Force an IPv6-only socket, for testing purposes. */
-    const int on = 1;
-    setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
-    return 0;
-  }
-}
-
-int grpc_create_dualstack_socket(const struct sockaddr *addr, int type,
-                                 int protocol, grpc_dualstack_mode *dsmode) {
-  int family = addr->sa_family;
-  if (family == AF_INET6) {
-    int fd;
-    if (grpc_ipv6_loopback_available()) {
-      fd = socket(family, type, protocol);
-    } else {
-      fd = -1;
-      errno = EAFNOSUPPORT;
-    }
-    /* Check if we've got a valid dualstack socket. */
-    if (fd >= 0 && set_socket_dualstack(fd)) {
-      *dsmode = GRPC_DSMODE_DUALSTACK;
-      return fd;
-    }
-    /* If this isn't an IPv4 address, then return whatever we've got. */
-    if (!grpc_sockaddr_is_v4mapped(addr, NULL)) {
-      *dsmode = GRPC_DSMODE_IPV6;
-      return fd;
-    }
-    /* Fall back to AF_INET. */
-    if (fd >= 0) {
-      close(fd);
-    }
-    family = AF_INET;
-  }
-  *dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE;
-  return socket(family, type, protocol);
-}
-
-#endif
diff --git a/src/core/iomgr/socket_utils_linux.c b/src/core/iomgr/socket_utils_linux.c
deleted file mode 100644
index a876252..0000000
--- a/src/core/iomgr/socket_utils_linux.c
+++ /dev/null
@@ -1,51 +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/support/port_platform.h>
-
-#ifdef GPR_LINUX_SOCKETUTILS
-
-#include "src/core/iomgr/socket_utils_posix.h"
-
-#include <sys/types.h>
-#include <sys/socket.h>
-
-int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
-                 int nonblock, int cloexec) {
-  int flags = 0;
-  flags |= nonblock ? SOCK_NONBLOCK : 0;
-  flags |= cloexec ? SOCK_CLOEXEC : 0;
-  return accept4(sockfd, addr, addrlen, flags);
-}
-
-#endif
diff --git a/src/core/iomgr/socket_utils_posix.c b/src/core/iomgr/socket_utils_posix.c
deleted file mode 100644
index 3c56b46..0000000
--- a/src/core/iomgr/socket_utils_posix.c
+++ /dev/null
@@ -1,70 +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/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKETUTILS
-
-#include "src/core/iomgr/socket_utils_posix.h"
-
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <grpc/support/log.h>
-
-int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
-                 int nonblock, int cloexec) {
-  int fd, flags;
-
-  fd = accept(sockfd, addr, addrlen);
-  if (fd >= 0) {
-    if (nonblock) {
-      flags = fcntl(fd, F_GETFL, 0);
-      if (flags < 0) goto close_and_error;
-      if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) goto close_and_error;
-    }
-    if (cloexec) {
-      flags = fcntl(fd, F_GETFD, 0);
-      if (flags < 0) goto close_and_error;
-      if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != 0) goto close_and_error;
-    }
-  }
-  return fd;
-
-close_and_error:
-  close(fd);
-  return -1;
-}
-
-#endif /* GPR_POSIX_SOCKETUTILS */
diff --git a/src/core/iomgr/socket_utils_posix.h b/src/core/iomgr/socket_utils_posix.h
deleted file mode 100644
index d330d19..0000000
--- a/src/core/iomgr/socket_utils_posix.h
+++ /dev/null
@@ -1,113 +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_SOCKET_UTILS_POSIX_H
-#define GRPC_INTERNAL_CORE_IOMGR_SOCKET_UTILS_POSIX_H
-
-#include <unistd.h>
-#include <sys/socket.h>
-
-/* a wrapper for accept or accept4 */
-int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
-                 int nonblock, int cloexec);
-
-/* set a socket to non blocking mode */
-int grpc_set_socket_nonblocking(int fd, int non_blocking);
-
-/* set a socket to close on exec */
-int grpc_set_socket_cloexec(int fd, int close_on_exec);
-
-/* set a socket to reuse old addresses */
-int grpc_set_socket_reuse_addr(int fd, int reuse);
-
-/* disable nagle */
-int grpc_set_socket_low_latency(int fd, int low_latency);
-
-/* Returns true if this system can create AF_INET6 sockets bound to ::1.
-   The value is probed once, and cached for the life of the process.
-
-   This is more restrictive than checking for socket(AF_INET6) to succeed,
-   because Linux with "net.ipv6.conf.all.disable_ipv6 = 1" is able to create
-   and bind IPv6 sockets, but cannot connect to a getsockname() of [::]:port
-   without a valid loopback interface.  Rather than expose this half-broken
-   state to library users, we turn off IPv6 sockets. */
-int grpc_ipv6_loopback_available(void);
-
-/* Tries to set SO_NOSIGPIPE if available on this platform.
-   Returns 1 on success, 0 on failure.
-   If SO_NO_SIGPIPE is not available, returns 1. */
-int grpc_set_socket_no_sigpipe_if_possible(int fd);
-
-/* An enum to keep track of IPv4/IPv6 socket modes.
-
-   Currently, this information is only used when a socket is first created, but
-   in the future we may wish to store it alongside the fd.  This would let calls
-   like sendto() know which family to use without asking the kernel first. */
-typedef enum grpc_dualstack_mode {
-  /* Uninitialized, or a non-IP socket. */
-  GRPC_DSMODE_NONE,
-  /* AF_INET only. */
-  GRPC_DSMODE_IPV4,
-  /* AF_INET6 only, because IPV6_V6ONLY could not be cleared. */
-  GRPC_DSMODE_IPV6,
-  /* AF_INET6, which also supports ::ffff-mapped IPv4 addresses. */
-  GRPC_DSMODE_DUALSTACK
-} grpc_dualstack_mode;
-
-/* Only tests should use this flag. */
-extern int grpc_forbid_dualstack_sockets_for_testing;
-
-/* Creates a new socket for connecting to (or listening on) an address.
-
-   If addr is AF_INET6, this creates an IPv6 socket first.  If that fails,
-   and addr is within ::ffff:0.0.0.0/96, then it automatically falls back to
-   an IPv4 socket.
-
-   If addr is AF_INET, AF_UNIX, or anything else, then this is similar to
-   calling socket() directly.
-
-   Returns an fd on success, otherwise returns -1 with errno set to the result
-   of a failed socket() call.
-
-   The *dsmode output indicates which address family was actually created.
-   The recommended way to use this is:
-   - First convert to IPv6 using grpc_sockaddr_to_v4mapped().
-   - Create the socket.
-   - If *dsmode is IPV4, use grpc_sockaddr_is_v4mapped() to convert back to
-     IPv4, so that bind() or connect() see the correct family.
-   Also, it's important to distinguish between DUALSTACK and IPV6 when
-   listening on the [::] wildcard address. */
-int grpc_create_dualstack_socket(const struct sockaddr *addr, int type,
-                                 int protocol, grpc_dualstack_mode *dsmode);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_UTILS_POSIX_H */
diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c
deleted file mode 100644
index fafb7b6..0000000
--- a/src/core/iomgr/socket_windows.c
+++ /dev/null
@@ -1,98 +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/support/port_platform.h>
-
-#ifdef GPR_WINSOCK_SOCKET
-
-#include <winsock2.h>
-#include <mswsock.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/log_win32.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/iomgr/iocp_windows.h"
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/pollset.h"
-#include "src/core/iomgr/pollset_windows.h"
-#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);
-  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;
-}
-
-/* Schedule a shutdown of the socket operations. Will call the pending
-   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. */
-void grpc_winsocket_shutdown(grpc_winsocket *winsocket) {
-  /* Grab the function pointer for DisconnectEx for that specific socket.
-     It may change depending on the interface. */
-  int status;
-  GUID guid = WSAID_DISCONNECTEX;
-  LPFN_DISCONNECTEX DisconnectEx;
-  DWORD ioctl_num_bytes;
-
-  status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
-                    &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx),
-                    &ioctl_num_bytes, NULL, NULL);
-
-  if (status == 0) {
-    DisconnectEx(winsocket->socket, NULL, 0, 0);
-  } else {
-    char *utf8_message = gpr_format_message(WSAGetLastError());
-    gpr_log(GPR_ERROR, "Unable to retrieve DisconnectEx pointer : %s",
-            utf8_message);
-    gpr_free(utf8_message);
-  }
-  closesocket(winsocket->socket);
-}
-
-void grpc_winsocket_destroy(grpc_winsocket *winsocket) {
-  grpc_iomgr_unregister_object(&winsocket->iomgr_object);
-  gpr_mu_destroy(&winsocket->state_mu);
-  gpr_free(winsocket);
-}
-
-#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/socket_windows.h b/src/core/iomgr/socket_windows.h
deleted file mode 100644
index dfbfabe..0000000
--- a/src/core/iomgr/socket_windows.h
+++ /dev/null
@@ -1,111 +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_SOCKET_WINDOWS_H
-#define GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H
-
-#include <grpc/support/port_platform.h>
-#include <winsock2.h>
-
-#include <grpc/support/sync.h>
-#include <grpc/support/atm.h>
-
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/exec_ctx.h"
-
-/* This holds the data for an outstanding read or write on a socket.
-   The mutex to protect the concurrent access to that data is the one
-   inside the winsocket wrapper. */
-typedef struct grpc_winsocket_callback_info {
-  /* This is supposed to be a WSAOVERLAPPED, but in order to get that
-     definition, we need to include ws2tcpip.h, which needs to be included
-     from the top, otherwise it'll clash with a previous inclusion of
-     windows.h that in turns includes winsock.h. If anyone knows a way
-     to do it properly, feel free to send a patch. */
-  OVERLAPPED overlapped;
-  /* The callback information for the pending operation. May be empty if the
-     caller hasn't registered a callback yet. */
-  grpc_closure *closure;
-  /* A boolean to describe if the IO Completion Port got a notification for
-     that operation. This will happen if the operation completed before the
-     called had time to register a callback. We could avoid that behavior
-     altogether by forcing the caller to always register its callback before
-     proceeding queue an operation, but it is frequent for an IO Completion
-     Port to trigger quickly. This way we avoid a context switch for calling
-     the callback. We also simplify the read / write operations to avoid having
-     to hold a mutex for a long amount of time. */
-  int has_pending_iocp;
-  /* The results of the overlapped operation. */
-  DWORD bytes_transfered;
-  int wsa_error;
-} grpc_winsocket_callback_info;
-
-/* This is a wrapper to a Windows socket. A socket can have one outstanding
-   read, and one outstanding write. Doing an asynchronous accept means waiting
-   for a read operation. Doing an asynchronous connect means waiting for a
-   write operation. These are completely arbitrary ties between the operation
-   and the kind of event, because we can have one overlapped per pending
-   operation, whichever its nature is. So we could have more dedicated pending
-   operation callbacks for connect and listen. But given the scope of listen
-   and accept, we don't need to go to that extent and waste memory. Also, this
-   is closer to what happens in posix world. */
-typedef struct grpc_winsocket {
-  SOCKET socket;
-
-  grpc_winsocket_callback_info write_info;
-  grpc_winsocket_callback_info read_info;
-
-  gpr_mu state_mu;
-
-  /* You can't add the same socket twice to the same IO Completion Port.
-     This prevents that. */
-  int added_to_iocp;
-
-  grpc_closure shutdown_closure;
-
-  /* A label for iomgr to track outstanding objects */
-  grpc_iomgr_object iomgr_object;
-} grpc_winsocket;
-
-/* Create a wrapped windows handle. This takes ownership of it, meaning that
-   it will be responsible for closing it. */
-grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name);
-
-/* Initiate an asynchronous shutdown of the socket. Will call off any pending
-   operation to cancel them. */
-void grpc_winsocket_shutdown(grpc_winsocket *socket);
-
-/* Destroy a socket. Should only be called if there's no pending operation. */
-void grpc_winsocket_destroy(grpc_winsocket *socket);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H */
diff --git a/src/core/iomgr/tcp_client.h b/src/core/iomgr/tcp_client.h
deleted file mode 100644
index 5e18e71..0000000
--- a/src/core/iomgr/tcp_client.h
+++ /dev/null
@@ -1,53 +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_TCP_CLIENT_H
-#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).
-   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(grpc_exec_ctx *exec_ctx, grpc_closure *on_connect,
-                             grpc_endpoint **endpoint,
-                             grpc_pollset_set *interested_parties,
-                             const struct sockaddr *addr, size_t addr_len,
-                             gpr_timespec deadline);
-
-#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
deleted file mode 100644
index 1572785..0000000
--- a/src/core/iomgr/tcp_client_posix.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/iomgr/tcp_client.h"
-
-#include <errno.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/time.h>
-
-#include "src/core/iomgr/iomgr_posix.h"
-#include "src/core/iomgr/pollset_posix.h"
-#include "src/core/iomgr/pollset_set_posix.h"
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/iomgr/socket_utils_posix.h"
-#include "src/core/iomgr/tcp_posix.h"
-#include "src/core/iomgr/timer.h"
-#include "src/core/support/string.h"
-
-extern int grpc_tcp_trace;
-
-typedef struct {
-  gpr_mu mu;
-  grpc_fd *fd;
-  gpr_timespec deadline;
-  grpc_timer alarm;
-  int refs;
-  grpc_closure write_closure;
-  grpc_pollset_set *interested_parties;
-  char *addr_str;
-  grpc_endpoint **ep;
-  grpc_closure *closure;
-} async_connect;
-
-static int prepare_socket(const struct sockaddr *addr, int fd) {
-  if (fd < 0) {
-    goto error;
-  }
-
-  if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
-      (addr->sa_family != AF_UNIX && !grpc_set_socket_low_latency(fd, 1)) ||
-      !grpc_set_socket_no_sigpipe_if_possible(fd)) {
-    gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
-            strerror(errno));
-    goto error;
-  }
-
-  return 1;
-
-error:
-  if (fd >= 0) {
-    close(fd);
-  }
-  return 0;
-}
-
-static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
-  int done;
-  async_connect *ac = acp;
-  if (grpc_tcp_trace) {
-    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: success=%d", ac->addr_str,
-            success);
-  }
-  gpr_mu_lock(&ac->mu);
-  if (ac->fd != NULL) {
-    grpc_fd_shutdown(exec_ctx, ac->fd);
-  }
-  done = (--ac->refs == 0);
-  gpr_mu_unlock(&ac->mu);
-  if (done) {
-    gpr_mu_destroy(&ac->mu);
-    gpr_free(ac->addr_str);
-    gpr_free(ac);
-  }
-}
-
-static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
-  async_connect *ac = acp;
-  int so_error = 0;
-  socklen_t so_error_size;
-  int err;
-  int done;
-  grpc_endpoint **ep = ac->ep;
-  grpc_closure *closure = ac->closure;
-  grpc_fd *fd;
-
-  if (grpc_tcp_trace) {
-    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_writable: success=%d",
-            ac->addr_str, success);
-  }
-
-  gpr_mu_lock(&ac->mu);
-  GPR_ASSERT(ac->fd);
-  fd = ac->fd;
-  ac->fd = NULL;
-  gpr_mu_unlock(&ac->mu);
-
-  grpc_timer_cancel(exec_ctx, &ac->alarm);
-
-  gpr_mu_lock(&ac->mu);
-  if (success) {
-    do {
-      so_error_size = sizeof(so_error);
-      err = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size);
-    } while (err < 0 && errno == EINTR);
-    if (err < 0) {
-      gpr_log(GPR_ERROR, "failed to connect to '%s': getsockopt(ERROR): %s",
-              ac->addr_str, strerror(errno));
-      goto finish;
-    } else if (so_error != 0) {
-      if (so_error == ENOBUFS) {
-        /* We will get one of these errors if we have run out of
-           memory in the kernel for the data structures allocated
-           when you connect a socket.  If this happens it is very
-           likely that if we wait a little bit then try again the
-           connection will work (since other programs or this
-           program will close their network connections and free up
-           memory).  This does _not_ indicate that there is anything
-           wrong with the server we are connecting to, this is a
-           local problem.
-
-           If you are looking at this code, then chances are that
-           your program or another program on the same computer
-           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(exec_ctx, fd, &ac->write_closure);
-        return;
-      } else {
-        switch (so_error) {
-          case ECONNREFUSED:
-            gpr_log(
-                GPR_ERROR,
-                "failed to connect to '%s': socket error: connection refused",
-                ac->addr_str);
-            break;
-          default:
-            gpr_log(GPR_ERROR, "failed to connect to '%s': socket error: %d",
-                    ac->addr_str, so_error);
-            break;
-        }
-        goto finish;
-      }
-    } else {
-      grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd);
-      *ep = grpc_tcp_create(fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, ac->addr_str);
-      fd = NULL;
-      goto finish;
-    }
-  } else {
-    gpr_log(GPR_ERROR, "failed to connect to '%s': timeout occurred",
-            ac->addr_str);
-    goto finish;
-  }
-
-  GPR_UNREACHABLE_CODE(return );
-
-finish:
-  if (fd != NULL) {
-    grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd);
-    grpc_fd_orphan(exec_ctx, fd, NULL, NULL, "tcp_client_orphan");
-    fd = NULL;
-  }
-  done = (--ac->refs == 0);
-  gpr_mu_unlock(&ac->mu);
-  if (done) {
-    gpr_mu_destroy(&ac->mu);
-    gpr_free(ac->addr_str);
-    gpr_free(ac);
-  }
-  grpc_exec_ctx_enqueue(exec_ctx, closure, *ep != NULL, NULL);
-}
-
-void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
-                             grpc_endpoint **ep,
-                             grpc_pollset_set *interested_parties,
-                             const struct sockaddr *addr, size_t 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;
-
-  *ep = NULL;
-
-  /* Use dualstack sockets where available. */
-  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
-    addr = (const struct sockaddr *)&addr6_v4mapped;
-    addr_len = sizeof(addr6_v4mapped);
-  }
-
-  fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
-  if (fd < 0) {
-    gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
-  }
-  if (dsmode == GRPC_DSMODE_IPV4) {
-    /* If we got an AF_INET socket, map the address back to IPv4. */
-    GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy));
-    addr = (struct sockaddr *)&addr4_copy;
-    addr_len = sizeof(addr4_copy);
-  }
-  if (!prepare_socket(addr, fd)) {
-    grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
-    return;
-  }
-
-  do {
-    GPR_ASSERT(addr_len < ~(socklen_t)0);
-    err = connect(fd, addr, (socklen_t)addr_len);
-  } while (err < 0 && errno == EINTR);
-
-  addr_str = grpc_sockaddr_to_uri(addr);
-  gpr_asprintf(&name, "tcp-client:%s", addr_str);
-
-  fdobj = grpc_fd_create(fd, name);
-
-  if (err >= 0) {
-    *ep = grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str);
-    grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
-    goto done;
-  }
-
-  if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
-    gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno));
-    grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error");
-    grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
-    goto done;
-  }
-
-  grpc_pollset_set_add_fd(exec_ctx, interested_parties, fdobj);
-
-  ac = gpr_malloc(sizeof(async_connect));
-  ac->closure = closure;
-  ac->ep = ep;
-  ac->fd = fdobj;
-  ac->interested_parties = interested_parties;
-  ac->addr_str = addr_str;
-  addr_str = NULL;
-  gpr_mu_init(&ac->mu);
-  ac->refs = 2;
-  ac->write_closure.cb = on_writable;
-  ac->write_closure.cb_arg = ac;
-
-  if (grpc_tcp_trace) {
-    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting",
-            ac->addr_str);
-  }
-
-  gpr_mu_lock(&ac->mu);
-  grpc_timer_init(exec_ctx, &ac->alarm,
-                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC));
-  grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure);
-  gpr_mu_unlock(&ac->mu);
-
-done:
-  gpr_free(name);
-  gpr_free(addr_str);
-}
-
-#endif
diff --git a/src/core/iomgr/tcp_client_windows.c b/src/core/iomgr/tcp_client_windows.c
deleted file mode 100644
index 689c6f7..0000000
--- a/src/core/iomgr/tcp_client_windows.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WINSOCK_SOCKET
-
-#include "src/core/iomgr/sockaddr_win32.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/log_win32.h>
-#include <grpc/support/slice_buffer.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/iomgr/timer.h"
-#include "src/core/iomgr/iocp_windows.h"
-#include "src/core/iomgr/tcp_client.h"
-#include "src/core/iomgr/tcp_windows.h"
-#include "src/core/iomgr/sockaddr.h"
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/iomgr/socket_windows.h"
-
-typedef struct {
-  grpc_closure *on_done;
-  gpr_mu mu;
-  grpc_winsocket *socket;
-  gpr_timespec deadline;
-  grpc_timer alarm;
-  char *addr_name;
-  int refs;
-  grpc_closure on_connect;
-  grpc_endpoint **endpoint;
-} async_connect;
-
-static void async_connect_unlock_and_cleanup(async_connect *ac) {
-  int done = (--ac->refs == 0);
-  gpr_mu_unlock(&ac->mu);
-  if (done) {
-    if (ac->socket != NULL) grpc_winsocket_destroy(ac->socket);
-    gpr_mu_destroy(&ac->mu);
-    gpr_free(ac->addr_name);
-    gpr_free(ac);
-  }
-}
-
-static void on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool occured) {
-  async_connect *ac = acp;
-  gpr_mu_lock(&ac->mu);
-  /* If the alarm didn't occur, it got cancelled. */
-  if (ac->socket != NULL && occured) {
-    grpc_winsocket_shutdown(ac->socket);
-  }
-  async_connect_unlock_and_cleanup(ac);
-}
-
-static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, bool from_iocp) {
-  async_connect *ac = acp;
-  SOCKET sock = ac->socket->socket;
-  grpc_endpoint **ep = ac->endpoint;
-  grpc_winsocket_callback_info *info = &ac->socket->write_info;
-  grpc_closure *on_done = ac->on_done;
-
-  grpc_timer_cancel(exec_ctx, &ac->alarm);
-
-  gpr_mu_lock(&ac->mu);
-
-  if (from_iocp) {
-    DWORD transfered_bytes = 0;
-    DWORD flags;
-    BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
-                                              &transfered_bytes, FALSE, &flags);
-    GPR_ASSERT(transfered_bytes == 0);
-    if (!wsa_success) {
-      char *utf8_message = gpr_format_message(WSAGetLastError());
-      gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
-      gpr_free(utf8_message);
-    } else {
-      *ep = grpc_tcp_create(ac->socket, ac->addr_name);
-      ac->socket = NULL;
-    }
-  }
-
-  async_connect_unlock_and_cleanup(ac);
-  /* If the connection was aborted, the callback was already called when
-     the deadline was met. */
-  on_done->cb(exec_ctx, on_done->cb_arg, *ep != NULL);
-}
-
-/* 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(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
-                             grpc_endpoint **endpoint,
-                             grpc_pollset_set *interested_parties,
-                             const struct sockaddr *addr, size_t addr_len,
-                             gpr_timespec deadline) {
-  SOCKET sock = INVALID_SOCKET;
-  BOOL success;
-  int status;
-  struct sockaddr_in6 addr6_v4mapped;
-  struct sockaddr_in6 local_address;
-  async_connect *ac;
-  grpc_winsocket *socket = NULL;
-  LPFN_CONNECTEX ConnectEx;
-  GUID guid = WSAID_CONNECTEX;
-  DWORD ioctl_num_bytes;
-  const char *message = NULL;
-  char *utf8_message;
-  grpc_winsocket_callback_info *info;
-
-  *endpoint = NULL;
-
-  /* Use dualstack sockets where available. */
-  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
-    addr = (const struct sockaddr *)&addr6_v4mapped;
-    addr_len = sizeof(addr6_v4mapped);
-  }
-
-  sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
-                   WSA_FLAG_OVERLAPPED);
-  if (sock == INVALID_SOCKET) {
-    message = "Unable to create socket: %s";
-    goto failure;
-  }
-
-  if (!grpc_tcp_prepare_socket(sock)) {
-    message = "Unable to set socket options: %s";
-    goto failure;
-  }
-
-  /* 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);
-
-  if (status != 0) {
-    message = "Unable to retrieve ConnectEx pointer: %s";
-    goto failure;
-  }
-
-  grpc_sockaddr_make_wildcard6(0, &local_address);
-
-  status = bind(sock, (struct sockaddr *)&local_address, sizeof(local_address));
-  if (status != 0) {
-    message = "Unable to bind socket: %s";
-    goto failure;
-  }
-
-  socket = grpc_winsocket_create(sock, "client");
-  info = &socket->write_info;
-  success =
-      ConnectEx(sock, addr, (int)addr_len, NULL, 0, NULL, &info->overlapped);
-
-  /* It wouldn't be unusual to get a success immediately. But we'll still get
-     an IOCP notification, so let's ignore it. */
-  if (!success) {
-    int error = WSAGetLastError();
-    if (error != ERROR_IO_PENDING) {
-      message = "ConnectEx failed: %s";
-      goto failure;
-    }
-  }
-
-  ac = gpr_malloc(sizeof(async_connect));
-  ac->on_done = on_done;
-  ac->socket = socket;
-  gpr_mu_init(&ac->mu);
-  ac->refs = 2;
-  ac->addr_name = grpc_sockaddr_to_uri(addr);
-  ac->endpoint = endpoint;
-  grpc_closure_init(&ac->on_connect, on_connect, ac);
-
-  grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac,
-                  gpr_now(GPR_CLOCK_MONOTONIC));
-  grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect);
-  return;
-
-failure:
-  utf8_message = gpr_format_message(WSAGetLastError());
-  gpr_log(GPR_ERROR, message, utf8_message);
-  gpr_free(utf8_message);
-  if (socket != NULL) {
-    grpc_winsocket_destroy(socket);
-  } else if (sock != INVALID_SOCKET) {
-    closesocket(sock);
-  }
-  grpc_exec_ctx_enqueue(exec_ctx, on_done, false, NULL);
-}
-
-#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c
deleted file mode 100644
index f74eb3f..0000000
--- a/src/core/iomgr/tcp_posix.c
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/iomgr/tcp_posix.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/time.h>
-
-#include "src/core/debug/trace.h"
-#include "src/core/iomgr/pollset_posix.h"
-#include "src/core/iomgr/pollset_set_posix.h"
-#include "src/core/profiling/timers.h"
-#include "src/core/support/string.h"
-
-#ifdef GPR_HAVE_MSG_NOSIGNAL
-#define SENDMSG_FLAGS MSG_NOSIGNAL
-#else
-#define SENDMSG_FLAGS 0
-#endif
-
-#ifdef GPR_MSG_IOVLEN_TYPE
-typedef GPR_MSG_IOVLEN_TYPE msg_iovlen_type;
-#else
-typedef size_t msg_iovlen_type;
-#endif
-
-int grpc_tcp_trace = 0;
-
-typedef struct {
-  grpc_endpoint base;
-  grpc_fd *em_fd;
-  int fd;
-  int finished_edge;
-  msg_iovlen_type iov_size; /* Number of slices to allocate per read attempt */
-  size_t slice_size;
-  gpr_refcount refcount;
-
-  /* garbage after the last read */
-  gpr_slice_buffer last_read_buffer;
-
-  gpr_slice_buffer *incoming_buffer;
-  gpr_slice_buffer *outgoing_buffer;
-  /** slice within outgoing_buffer to write next */
-  size_t outgoing_slice_idx;
-  /** byte within outgoing_buffer->slices[outgoing_slice_idx] to write next */
-  size_t outgoing_byte_idx;
-
-  grpc_closure *read_cb;
-  grpc_closure *write_cb;
-  grpc_closure *release_fd_cb;
-  int *release_fd;
-
-  grpc_closure read_closure;
-  grpc_closure write_closure;
-
-  char *peer_string;
-} grpc_tcp;
-
-static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
-                            bool success);
-static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
-                             bool success);
-
-static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  grpc_fd_shutdown(exec_ctx, tcp->em_fd);
-}
-
-static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
-  grpc_fd_orphan(exec_ctx, tcp->em_fd, tcp->release_fd_cb, tcp->release_fd,
-                 "tcp_unref_orphan");
-  gpr_slice_buffer_destroy(&tcp->last_read_buffer);
-  gpr_free(tcp->peer_string);
-  gpr_free(tcp);
-}
-
-/*#define GRPC_TCP_REFCOUNT_DEBUG*/
-#ifdef GRPC_TCP_REFCOUNT_DEBUG
-#define TCP_UNREF(cl, tcp, reason) \
-  tcp_unref((cl), (tcp), (reason), __FILE__, __LINE__)
-#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
-static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp,
-                      const char *reason, const char *file, int line) {
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
-          reason, tcp->refcount.count, tcp->refcount.count - 1);
-  if (gpr_unref(&tcp->refcount)) {
-    tcp_free(exec_ctx, tcp);
-  }
-}
-
-static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
-                    int line) {
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP   ref %p : %s %d -> %d", tcp,
-          reason, tcp->refcount.count, tcp->refcount.count + 1);
-  gpr_ref(&tcp->refcount);
-}
-#else
-#define TCP_UNREF(cl, tcp, reason) tcp_unref((cl), (tcp))
-#define TCP_REF(tcp, reason) tcp_ref((tcp))
-static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
-  if (gpr_unref(&tcp->refcount)) {
-    tcp_free(exec_ctx, tcp);
-  }
-}
-
-static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
-#endif
-
-static void tcp_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  TCP_UNREF(exec_ctx, tcp, "destroy");
-}
-
-static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, int success) {
-  grpc_closure *cb = tcp->read_cb;
-
-  if (grpc_tcp_trace) {
-    size_t i;
-    gpr_log(GPR_DEBUG, "read: success=%d", success);
-    for (i = 0; i < tcp->incoming_buffer->count; i++) {
-      char *dump = gpr_dump_slice(tcp->incoming_buffer->slices[i],
-                                  GPR_DUMP_HEX | GPR_DUMP_ASCII);
-      gpr_log(GPR_DEBUG, "READ %p: %s", tcp, dump);
-      gpr_free(dump);
-    }
-  }
-
-  tcp->read_cb = NULL;
-  tcp->incoming_buffer = NULL;
-  cb->cb(exec_ctx, cb->cb_arg, success);
-}
-
-#define MAX_READ_IOVEC 4
-static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
-  struct msghdr msg;
-  struct iovec iov[MAX_READ_IOVEC];
-  ssize_t read_bytes;
-  size_t i;
-
-  GPR_ASSERT(!tcp->finished_edge);
-  GPR_ASSERT(tcp->iov_size <= MAX_READ_IOVEC);
-  GPR_ASSERT(tcp->incoming_buffer->count <= MAX_READ_IOVEC);
-  GPR_TIMER_BEGIN("tcp_continue_read", 0);
-
-  while (tcp->incoming_buffer->count < (size_t)tcp->iov_size) {
-    gpr_slice_buffer_add_indexed(tcp->incoming_buffer,
-                                 gpr_slice_malloc(tcp->slice_size));
-  }
-  for (i = 0; i < tcp->incoming_buffer->count; i++) {
-    iov[i].iov_base = GPR_SLICE_START_PTR(tcp->incoming_buffer->slices[i]);
-    iov[i].iov_len = GPR_SLICE_LENGTH(tcp->incoming_buffer->slices[i]);
-  }
-
-  msg.msg_name = NULL;
-  msg.msg_namelen = 0;
-  msg.msg_iov = iov;
-  msg.msg_iovlen = tcp->iov_size;
-  msg.msg_control = NULL;
-  msg.msg_controllen = 0;
-  msg.msg_flags = 0;
-
-  GPR_TIMER_BEGIN("recvmsg", 1);
-  do {
-    read_bytes = recvmsg(tcp->fd, &msg, 0);
-  } while (read_bytes < 0 && errno == EINTR);
-  GPR_TIMER_END("recvmsg", 0);
-
-  if (read_bytes < 0) {
-    /* NB: After calling call_read_cb a parallel call of the read handler may
-     * be running. */
-    if (errno == EAGAIN) {
-      if (tcp->iov_size > 1) {
-        tcp->iov_size /= 2;
-      }
-      /* We've consumed the edge, request a new one */
-      grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
-    } else {
-      /* TODO(klempner): Log interesting errors */
-      gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
-      call_read_cb(exec_ctx, tcp, 0);
-      TCP_UNREF(exec_ctx, tcp, "read");
-    }
-  } else if (read_bytes == 0) {
-    /* 0 read size ==> end of stream */
-    gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
-    call_read_cb(exec_ctx, tcp, 0);
-    TCP_UNREF(exec_ctx, tcp, "read");
-  } else {
-    GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
-    if ((size_t)read_bytes < tcp->incoming_buffer->length) {
-      gpr_slice_buffer_trim_end(
-          tcp->incoming_buffer,
-          tcp->incoming_buffer->length - (size_t)read_bytes,
-          &tcp->last_read_buffer);
-    } else if (tcp->iov_size < MAX_READ_IOVEC) {
-      ++tcp->iov_size;
-    }
-    GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length);
-    call_read_cb(exec_ctx, tcp, 1);
-    TCP_UNREF(exec_ctx, tcp, "read");
-  }
-
-  GPR_TIMER_END("tcp_continue_read", 0);
-}
-
-static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
-                            bool success) {
-  grpc_tcp *tcp = (grpc_tcp *)arg;
-  GPR_ASSERT(!tcp->finished_edge);
-
-  if (!success) {
-    gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
-    call_read_cb(exec_ctx, tcp, 0);
-    TCP_UNREF(exec_ctx, tcp, "read");
-  } else {
-    tcp_continue_read(exec_ctx, tcp);
-  }
-}
-
-static void tcp_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                     gpr_slice_buffer *incoming_buffer, grpc_closure *cb) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  GPR_ASSERT(tcp->read_cb == NULL);
-  tcp->read_cb = cb;
-  tcp->incoming_buffer = incoming_buffer;
-  gpr_slice_buffer_reset_and_unref(incoming_buffer);
-  gpr_slice_buffer_swap(incoming_buffer, &tcp->last_read_buffer);
-  TCP_REF(tcp, "read");
-  if (tcp->finished_edge) {
-    tcp->finished_edge = 0;
-    grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
-  } else {
-    grpc_exec_ctx_enqueue(exec_ctx, &tcp->read_closure, true, NULL);
-  }
-}
-
-typedef enum { FLUSH_DONE, FLUSH_PENDING, FLUSH_ERROR } flush_result;
-
-#define MAX_WRITE_IOVEC 16
-static flush_result tcp_flush(grpc_tcp *tcp) {
-  struct msghdr msg;
-  struct iovec iov[MAX_WRITE_IOVEC];
-  msg_iovlen_type iov_size;
-  ssize_t sent_length;
-  size_t sending_length;
-  size_t trailing;
-  size_t unwind_slice_idx;
-  size_t unwind_byte_idx;
-
-  for (;;) {
-    sending_length = 0;
-    unwind_slice_idx = tcp->outgoing_slice_idx;
-    unwind_byte_idx = tcp->outgoing_byte_idx;
-    for (iov_size = 0; tcp->outgoing_slice_idx != tcp->outgoing_buffer->count &&
-                           iov_size != MAX_WRITE_IOVEC;
-         iov_size++) {
-      iov[iov_size].iov_base =
-          GPR_SLICE_START_PTR(
-              tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) +
-          tcp->outgoing_byte_idx;
-      iov[iov_size].iov_len =
-          GPR_SLICE_LENGTH(
-              tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) -
-          tcp->outgoing_byte_idx;
-      sending_length += iov[iov_size].iov_len;
-      tcp->outgoing_slice_idx++;
-      tcp->outgoing_byte_idx = 0;
-    }
-    GPR_ASSERT(iov_size > 0);
-
-    msg.msg_name = NULL;
-    msg.msg_namelen = 0;
-    msg.msg_iov = iov;
-    msg.msg_iovlen = iov_size;
-    msg.msg_control = NULL;
-    msg.msg_controllen = 0;
-    msg.msg_flags = 0;
-
-    GPR_TIMER_BEGIN("sendmsg", 1);
-    do {
-      /* TODO(klempner): Cork if this is a partial write */
-      sent_length = sendmsg(tcp->fd, &msg, SENDMSG_FLAGS);
-    } while (sent_length < 0 && errno == EINTR);
-    GPR_TIMER_END("sendmsg", 0);
-
-    if (sent_length < 0) {
-      if (errno == EAGAIN) {
-        tcp->outgoing_slice_idx = unwind_slice_idx;
-        tcp->outgoing_byte_idx = unwind_byte_idx;
-        return FLUSH_PENDING;
-      } else {
-        /* TODO(klempner): Log some of these */
-        return FLUSH_ERROR;
-      }
-    }
-
-    GPR_ASSERT(tcp->outgoing_byte_idx == 0);
-    trailing = sending_length - (size_t)sent_length;
-    while (trailing > 0) {
-      size_t slice_length;
-
-      tcp->outgoing_slice_idx--;
-      slice_length = GPR_SLICE_LENGTH(
-          tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]);
-      if (slice_length > trailing) {
-        tcp->outgoing_byte_idx = slice_length - trailing;
-        break;
-      } else {
-        trailing -= slice_length;
-      }
-    }
-
-    if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) {
-      return FLUSH_DONE;
-    }
-  };
-}
-
-static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
-                             bool success) {
-  grpc_tcp *tcp = (grpc_tcp *)arg;
-  flush_result status;
-  grpc_closure *cb;
-
-  if (!success) {
-    cb = tcp->write_cb;
-    tcp->write_cb = NULL;
-    cb->cb(exec_ctx, cb->cb_arg, 0);
-    TCP_UNREF(exec_ctx, tcp, "write");
-    return;
-  }
-
-  status = tcp_flush(tcp);
-  if (status == FLUSH_PENDING) {
-    grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
-  } else {
-    cb = tcp->write_cb;
-    tcp->write_cb = NULL;
-    GPR_TIMER_BEGIN("tcp_handle_write.cb", 0);
-    cb->cb(exec_ctx, cb->cb_arg, status == FLUSH_DONE);
-    GPR_TIMER_END("tcp_handle_write.cb", 0);
-    TCP_UNREF(exec_ctx, tcp, "write");
-  }
-}
-
-static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                      gpr_slice_buffer *buf, grpc_closure *cb) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  flush_result status;
-
-  if (grpc_tcp_trace) {
-    size_t i;
-
-    for (i = 0; i < buf->count; i++) {
-      char *data =
-          gpr_dump_slice(buf->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
-      gpr_log(GPR_DEBUG, "WRITE %p: %s", tcp, data);
-      gpr_free(data);
-    }
-  }
-
-  GPR_TIMER_BEGIN("tcp_write", 0);
-  GPR_ASSERT(tcp->write_cb == NULL);
-
-  if (buf->length == 0) {
-    GPR_TIMER_END("tcp_write", 0);
-    grpc_exec_ctx_enqueue(exec_ctx, cb, true, NULL);
-    return;
-  }
-  tcp->outgoing_buffer = buf;
-  tcp->outgoing_slice_idx = 0;
-  tcp->outgoing_byte_idx = 0;
-
-  status = tcp_flush(tcp);
-  if (status == FLUSH_PENDING) {
-    TCP_REF(tcp, "write");
-    tcp->write_cb = cb;
-    grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
-  } else {
-    grpc_exec_ctx_enqueue(exec_ctx, cb, status == FLUSH_DONE, NULL);
-  }
-
-  GPR_TIMER_END("tcp_write", 0);
-}
-
-static void tcp_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                               grpc_pollset *pollset) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  grpc_pollset_add_fd(exec_ctx, pollset, tcp->em_fd);
-}
-
-static void tcp_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                                   grpc_pollset_set *pollset_set) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  grpc_pollset_set_add_fd(exec_ctx, pollset_set, tcp->em_fd);
-}
-
-static char *tcp_get_peer(grpc_endpoint *ep) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  return gpr_strdup(tcp->peer_string);
-}
-
-static const grpc_endpoint_vtable vtable = {
-    tcp_read, tcp_write, tcp_add_to_pollset, tcp_add_to_pollset_set,
-    tcp_shutdown, tcp_destroy, tcp_get_peer};
-
-grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
-                               const char *peer_string) {
-  grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
-  tcp->base.vtable = &vtable;
-  tcp->peer_string = gpr_strdup(peer_string);
-  tcp->fd = em_fd->fd;
-  tcp->read_cb = NULL;
-  tcp->write_cb = NULL;
-  tcp->release_fd_cb = NULL;
-  tcp->release_fd = NULL;
-  tcp->incoming_buffer = NULL;
-  tcp->slice_size = slice_size;
-  tcp->iov_size = 1;
-  tcp->finished_edge = 1;
-  /* paired with unref in grpc_tcp_destroy */
-  gpr_ref_init(&tcp->refcount, 1);
-  tcp->em_fd = em_fd;
-  tcp->read_closure.cb = tcp_handle_read;
-  tcp->read_closure.cb_arg = tcp;
-  tcp->write_closure.cb = tcp_handle_write;
-  tcp->write_closure.cb_arg = tcp;
-  gpr_slice_buffer_init(&tcp->last_read_buffer);
-
-  return &tcp->base;
-}
-
-int grpc_tcp_fd(grpc_endpoint *ep) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  GPR_ASSERT(ep->vtable == &vtable);
-  return grpc_fd_wrapped_fd(tcp->em_fd);
-}
-
-void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                                     int *fd, grpc_closure *done) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  GPR_ASSERT(ep->vtable == &vtable);
-  tcp->release_fd = fd;
-  tcp->release_fd_cb = done;
-  TCP_UNREF(exec_ctx, tcp, "destroy");
-}
-
-#endif
diff --git a/src/core/iomgr/tcp_posix.h b/src/core/iomgr/tcp_posix.h
deleted file mode 100644
index 2a40cdd..0000000
--- a/src/core/iomgr/tcp_posix.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H
-#define GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H
-/*
-   Low level TCP "bottom half" implementation, for use by transports built on
-   top of a TCP connection.
-
-   Note that this file does not (yet) include APIs for creating the socket in
-   the first place.
-
-   All calls passing slice transfer ownership of a slice refcount unless
-   otherwise specified.
-*/
-
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/iomgr/fd_posix.h"
-
-#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
-
-extern int grpc_tcp_trace;
-
-/* Create a tcp endpoint given a file desciptor and a read slice size.
-   Takes ownership of fd. */
-grpc_endpoint *grpc_tcp_create(grpc_fd *fd, size_t read_slice_size,
-                               const char *peer_string);
-
-/* Return the tcp endpoint's fd, or -1 if this is not available. Does not
-   release the fd.
-   Requires: ep must be a tcp endpoint.
- */
-int grpc_tcp_fd(grpc_endpoint *ep);
-
-/* Destroy the tcp endpoint without closing its fd. *fd will be set and done
- * will be called when the endpoint is destroyed.
- * Requires: ep must be a tcp endpoint and fd must not be NULL. */
-void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                                     int *fd, grpc_closure *done);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_POSIX_H */
diff --git a/src/core/iomgr/tcp_server.h b/src/core/iomgr/tcp_server.h
deleted file mode 100644
index a39dd3b..0000000
--- a/src/core/iomgr/tcp_server.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H
-#define GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H
-
-#include "src/core/iomgr/closure.h"
-#include "src/core/iomgr/endpoint.h"
-
-/* Forward decl of grpc_tcp_server */
-typedef struct grpc_tcp_server grpc_tcp_server;
-
-typedef struct grpc_tcp_server_acceptor {
-  /* grpc_tcp_server_cb functions share a ref on from_server that is valid
-     until the function returns. */
-  grpc_tcp_server *from_server;
-  /* Indices that may be passed to grpc_tcp_server_port_fd(). */
-  unsigned port_index;
-  unsigned fd_index;
-} grpc_tcp_server_acceptor;
-
-/* Called for newly connected TCP connections. */
-typedef void (*grpc_tcp_server_cb)(grpc_exec_ctx *exec_ctx, void *arg,
-                                   grpc_endpoint *ep,
-                                   grpc_tcp_server_acceptor *acceptor);
-
-/* Create a server, initially not bound to any ports. The caller owns one ref.
-   If shutdown_complete is not NULL, it will be used by
-   grpc_tcp_server_unref() when the ref count reaches zero. */
-grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete);
-
-/* Start listening to bound ports */
-void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server,
-                           grpc_pollset **pollsets, size_t pollset_count,
-                           grpc_tcp_server_cb on_accept_cb, void *cb_arg);
-
-/* Add a port to the server, returning the newly allocated port on success, or
-   -1 on failure.
-
-   The :: and 0.0.0.0 wildcard addresses are treated identically, accepting
-   both IPv4 and IPv6 connections, but :: is the preferred style.  This usually
-   creates one socket, but possibly two on systems which support IPv6,
-   but not dualstack sockets. */
-/* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle
-                  all of the multiple socket port matching logic in one place */
-int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
-                             size_t addr_len);
-
-/* Number of fds at the given port_index, or 0 if port_index is out of
-   bounds. */
-unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s, unsigned port_index);
-
-/* Returns the file descriptor of the Mth (fd_index) listening socket of the Nth
-   (port_index) call to add_port() on this server, or -1 if the indices are out
-   of bounds. The file descriptor remains owned by the server, and will be
-   cleaned up when the ref count reaches zero. */
-int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index,
-                            unsigned fd_index);
-
-/* Ref s and return s. */
-grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s);
-
-/* shutdown_starting is called when ref count has reached zero and the server is
-   about to be destroyed. The server will be deleted after it returns. Calling
-   grpc_tcp_server_ref() from it has no effect. */
-void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
-                                           grpc_closure *shutdown_starting);
-
-/* If the refcount drops to zero, delete s, and call (exec_ctx==NULL) or enqueue
-   a call (exec_ctx!=NULL) to shutdown_complete. */
-void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H */
diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c
deleted file mode 100644
index 5e07f82..0000000
--- a/src/core/iomgr/tcp_server_posix.c
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/iomgr/tcp_server.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include "src/core/iomgr/pollset_posix.h"
-#include "src/core/iomgr/resolve_address.h"
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/iomgr/socket_utils_posix.h"
-#include "src/core/iomgr/tcp_posix.h"
-#include "src/core/support/string.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/time.h>
-
-#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
-
-static gpr_once s_init_max_accept_queue_size;
-static int s_max_accept_queue_size;
-
-/* one listening port */
-typedef struct grpc_tcp_listener grpc_tcp_listener;
-struct grpc_tcp_listener {
-  int fd;
-  grpc_fd *emfd;
-  grpc_tcp_server *server;
-  union {
-    uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE];
-    struct sockaddr sockaddr;
-    struct sockaddr_un un;
-  } addr;
-  size_t addr_len;
-  int port;
-  unsigned port_index;
-  unsigned fd_index;
-  grpc_closure read_closure;
-  grpc_closure destroyed_closure;
-  struct grpc_tcp_listener *next;
-  /* When we add a listener, more than one can be created, mainly because of
-     IPv6. A sibling will still be in the normal list, but will be flagged
-     as such. Any action, such as ref or unref, will affect all of the
-     siblings in the list. */
-  struct grpc_tcp_listener *sibling;
-  int is_sibling;
-};
-
-static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) {
-  struct stat st;
-
-  if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
-    unlink(un->sun_path);
-  }
-}
-
-/* the overall server */
-struct grpc_tcp_server {
-  gpr_refcount refs;
-  /* Called whenever accept() succeeds on a server port. */
-  grpc_tcp_server_cb on_accept_cb;
-  void *on_accept_cb_arg;
-
-  gpr_mu mu;
-
-  /* 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;
-
-  /* linked list of server ports */
-  grpc_tcp_listener *head;
-  grpc_tcp_listener *tail;
-  unsigned nports;
-
-  /* List of closures passed to shutdown_starting_add(). */
-  grpc_closure_list shutdown_starting;
-
-  /* shutdown callback */
-  grpc_closure *shutdown_complete;
-
-  /* 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(grpc_closure *shutdown_complete) {
-  grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
-  gpr_ref_init(&s->refs, 1);
-  gpr_mu_init(&s->mu);
-  s->active_ports = 0;
-  s->destroyed_ports = 0;
-  s->shutdown = 0;
-  s->shutdown_starting.head = NULL;
-  s->shutdown_starting.tail = NULL;
-  s->shutdown_complete = shutdown_complete;
-  s->on_accept_cb = NULL;
-  s->on_accept_cb_arg = NULL;
-  s->head = NULL;
-  s->tail = NULL;
-  s->nports = 0;
-  return s;
-}
-
-static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
-  if (s->shutdown_complete != NULL) {
-    grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, true, NULL);
-  }
-
-  gpr_mu_destroy(&s->mu);
-
-  while (s->head) {
-    grpc_tcp_listener *sp = s->head;
-    s->head = sp->next;
-    gpr_free(sp);
-  }
-
-  gpr_free(s);
-}
-
-static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server,
-                           bool success) {
-  grpc_tcp_server *s = server;
-  gpr_mu_lock(&s->mu);
-  s->destroyed_ports++;
-  if (s->destroyed_ports == s->nports) {
-    gpr_mu_unlock(&s->mu);
-    finish_shutdown(exec_ctx, s);
-  } else {
-    GPR_ASSERT(s->destroyed_ports < s->nports);
-    gpr_mu_unlock(&s->mu);
-  }
-}
-
-/* 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_exec_ctx *exec_ctx, grpc_tcp_server *s) {
-  /* delete ALL the things */
-  gpr_mu_lock(&s->mu);
-
-  if (!s->shutdown) {
-    gpr_mu_unlock(&s->mu);
-    return;
-  }
-
-  if (s->head) {
-    grpc_tcp_listener *sp;
-    for (sp = s->head; sp; sp = sp->next) {
-      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(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
-                     "tcp_listener_shutdown");
-    }
-    gpr_mu_unlock(&s->mu);
-  } else {
-    gpr_mu_unlock(&s->mu);
-    finish_shutdown(exec_ctx, s);
-  }
-}
-
-static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
-  gpr_mu_lock(&s->mu);
-
-  GPR_ASSERT(!s->shutdown);
-  s->shutdown = 1;
-
-  /* shutdown all fd's */
-  if (s->active_ports) {
-    grpc_tcp_listener *sp;
-    for (sp = s->head; sp; sp = sp->next) {
-      grpc_fd_shutdown(exec_ctx, sp->emfd);
-    }
-    gpr_mu_unlock(&s->mu);
-  } else {
-    gpr_mu_unlock(&s->mu);
-    deactivated_all_ports(exec_ctx, s);
-  }
-}
-
-/* get max listen queue size on linux */
-static void init_max_accept_queue_size(void) {
-  int n = SOMAXCONN;
-  char buf[64];
-  FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r");
-  if (fp == NULL) {
-    /* 2.4 kernel. */
-    s_max_accept_queue_size = SOMAXCONN;
-    return;
-  }
-  if (fgets(buf, sizeof buf, fp)) {
-    char *end;
-    long i = strtol(buf, &end, 10);
-    if (i > 0 && i <= INT_MAX && end && *end == 0) {
-      n = (int)i;
-    }
-  }
-  fclose(fp);
-  s_max_accept_queue_size = n;
-
-  if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) {
-    gpr_log(GPR_INFO,
-            "Suspiciously small accept queue (%d) will probably lead to "
-            "connection drops",
-            s_max_accept_queue_size);
-  }
-}
-
-static int get_max_accept_queue_size(void) {
-  gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size);
-  return s_max_accept_queue_size;
-}
-
-/* Prepare a recently-created socket for listening. */
-static int prepare_socket(int fd, const struct sockaddr *addr,
-                          size_t addr_len) {
-  struct sockaddr_storage sockname_temp;
-  socklen_t sockname_len;
-
-  if (fd < 0) {
-    goto error;
-  }
-
-  if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
-      (addr->sa_family != AF_UNIX && (!grpc_set_socket_low_latency(fd, 1) ||
-                                      !grpc_set_socket_reuse_addr(fd, 1))) ||
-      !grpc_set_socket_no_sigpipe_if_possible(fd)) {
-    gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
-            strerror(errno));
-    goto error;
-  }
-
-  GPR_ASSERT(addr_len < ~(socklen_t)0);
-  if (bind(fd, addr, (socklen_t)addr_len) < 0) {
-    char *addr_str;
-    grpc_sockaddr_to_string(&addr_str, addr, 0);
-    gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno));
-    gpr_free(addr_str);
-    goto error;
-  }
-
-  if (listen(fd, get_max_accept_queue_size()) < 0) {
-    gpr_log(GPR_ERROR, "listen: %s", strerror(errno));
-    goto error;
-  }
-
-  sockname_len = sizeof(sockname_temp);
-  if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) {
-    goto error;
-  }
-
-  return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
-
-error:
-  if (fd >= 0) {
-    close(fd);
-  }
-  return -1;
-}
-
-/* event manager callback when reads are ready */
-static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  grpc_tcp_listener *sp = arg;
-  grpc_tcp_server_acceptor acceptor = {sp->server, sp->port_index,
-                                       sp->fd_index};
-  grpc_fd *fdobj;
-  size_t i;
-
-  if (!success) {
-    goto error;
-  }
-
-  /* loop until accept4 returns EAGAIN, and then re-arm notification */
-  for (;;) {
-    struct sockaddr_storage addr;
-    socklen_t addrlen = sizeof(addr);
-    char *addr_str;
-    char *name;
-    /* Note: If we ever decide to return this address to the user, remember to
-       strip off the ::ffff:0.0.0.0/96 prefix first. */
-    int fd = grpc_accept4(sp->fd, (struct sockaddr *)&addr, &addrlen, 1, 1);
-    if (fd < 0) {
-      switch (errno) {
-        case EINTR:
-          continue;
-        case EAGAIN:
-          grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
-          return;
-        default:
-          gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno));
-          goto error;
-      }
-    }
-
-    grpc_set_socket_no_sigpipe_if_possible(fd);
-
-    addr_str = grpc_sockaddr_to_uri((struct sockaddr *)&addr);
-    gpr_asprintf(&name, "tcp-server-connection:%s", addr_str);
-
-    if (grpc_tcp_trace) {
-      gpr_log(GPR_DEBUG, "SERVER_CONNECT: incoming 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(exec_ctx, sp->server->pollsets[i], fdobj);
-    }
-    sp->server->on_accept_cb(
-        exec_ctx, sp->server->on_accept_cb_arg,
-        grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str),
-        &acceptor);
-
-    gpr_free(name);
-    gpr_free(addr_str);
-  }
-
-  GPR_UNREACHABLE_CODE(return );
-
-error:
-  gpr_mu_lock(&sp->server->mu);
-  if (0 == --sp->server->active_ports) {
-    gpr_mu_unlock(&sp->server->mu);
-    deactivated_all_ports(exec_ctx, sp->server);
-  } else {
-    gpr_mu_unlock(&sp->server->mu);
-  }
-}
-
-static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, int fd,
-                                               const struct sockaddr *addr,
-                                               size_t addr_len,
-                                               unsigned port_index,
-                                               unsigned fd_index) {
-  grpc_tcp_listener *sp = NULL;
-  int port;
-  char *addr_str;
-  char *name;
-
-  port = prepare_socket(fd, addr, addr_len);
-  if (port >= 0) {
-    grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
-    gpr_asprintf(&name, "tcp-server-listener:%s", addr_str);
-    gpr_mu_lock(&s->mu);
-    s->nports++;
-    GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
-    sp = gpr_malloc(sizeof(grpc_tcp_listener));
-    sp->next = NULL;
-    if (s->head == NULL) {
-      s->head = sp;
-    } else {
-      s->tail->next = sp;
-    }
-    s->tail = sp;
-    sp->server = s;
-    sp->fd = fd;
-    sp->emfd = grpc_fd_create(fd, name);
-    memcpy(sp->addr.untyped, addr, addr_len);
-    sp->addr_len = addr_len;
-    sp->port = port;
-    sp->port_index = port_index;
-    sp->fd_index = fd_index;
-    sp->is_sibling = 0;
-    sp->sibling = NULL;
-    GPR_ASSERT(sp->emfd);
-    gpr_mu_unlock(&s->mu);
-    gpr_free(addr_str);
-    gpr_free(name);
-  }
-
-  return sp;
-}
-
-int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
-                             size_t addr_len) {
-  grpc_tcp_listener *sp;
-  grpc_tcp_listener *sp2 = NULL;
-  int fd;
-  grpc_dualstack_mode dsmode;
-  struct sockaddr_in6 addr6_v4mapped;
-  struct sockaddr_in wild4;
-  struct sockaddr_in6 wild6;
-  struct sockaddr_in addr4_copy;
-  struct sockaddr *allocated_addr = NULL;
-  struct sockaddr_storage sockname_temp;
-  socklen_t sockname_len;
-  int port;
-  unsigned port_index = 0;
-  unsigned fd_index = 0;
-  if (s->tail != NULL) {
-    port_index = s->tail->port_index + 1;
-  }
-  if (((struct sockaddr *)addr)->sa_family == AF_UNIX) {
-    unlink_if_unix_domain_socket(addr);
-  }
-
-  /* Check if this is a wildcard port, and if so, try to keep the port the same
-     as some previously created listener. */
-  if (grpc_sockaddr_get_port(addr) == 0) {
-    for (sp = s->head; sp; sp = sp->next) {
-      sockname_len = sizeof(sockname_temp);
-      if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp,
-                           &sockname_len)) {
-        port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
-        if (port > 0) {
-          allocated_addr = malloc(addr_len);
-          memcpy(allocated_addr, addr, addr_len);
-          grpc_sockaddr_set_port(allocated_addr, port);
-          addr = allocated_addr;
-          break;
-        }
-      }
-    }
-  }
-
-  sp = NULL;
-
-  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
-    addr = (const struct sockaddr *)&addr6_v4mapped;
-    addr_len = sizeof(addr6_v4mapped);
-  }
-
-  /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
-  if (grpc_sockaddr_is_wildcard(addr, &port)) {
-    grpc_sockaddr_make_wildcards(port, &wild4, &wild6);
-
-    /* Try listening on IPv6 first. */
-    addr = (struct sockaddr *)&wild6;
-    addr_len = sizeof(wild6);
-    fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
-    sp = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index);
-    if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
-      goto done;
-    }
-    if (sp != NULL) {
-      ++fd_index;
-    }
-    /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
-    if (port == 0 && sp != NULL) {
-      grpc_sockaddr_set_port((struct sockaddr *)&wild4, sp->port);
-      sp2 = sp;
-    }
-    addr = (struct sockaddr *)&wild4;
-    addr_len = sizeof(wild4);
-  }
-
-  fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
-  if (fd < 0) {
-    gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
-  }
-  if (dsmode == GRPC_DSMODE_IPV4 &&
-      grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
-    addr = (struct sockaddr *)&addr4_copy;
-    addr_len = sizeof(addr4_copy);
-  }
-  sp = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index);
-  if (sp2 != NULL && sp != NULL) {
-    sp2->sibling = sp;
-    sp->is_sibling = 1;
-  }
-
-done:
-  gpr_free(allocated_addr);
-  if (sp != NULL) {
-    return sp->port;
-  } else {
-    return -1;
-  }
-}
-
-unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s,
-                                       unsigned port_index) {
-  unsigned num_fds = 0;
-  grpc_tcp_listener *sp;
-  for (sp = s->head; sp && port_index != 0; sp = sp->next) {
-    if (!sp->is_sibling) {
-      --port_index;
-    }
-  }
-  for (; sp; sp = sp->sibling, ++num_fds)
-    ;
-  return num_fds;
-}
-
-int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index,
-                            unsigned fd_index) {
-  grpc_tcp_listener *sp;
-  for (sp = s->head; sp && port_index != 0; sp = sp->next) {
-    if (!sp->is_sibling) {
-      --port_index;
-    }
-  }
-  for (; sp && fd_index != 0; sp = sp->sibling, --fd_index)
-    ;
-  if (sp) {
-    return sp->fd;
-  } else {
-    return -1;
-  }
-}
-
-void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
-                           grpc_pollset **pollsets, size_t pollset_count,
-                           grpc_tcp_server_cb on_accept_cb,
-                           void *on_accept_cb_arg) {
-  size_t i;
-  grpc_tcp_listener *sp;
-  GPR_ASSERT(on_accept_cb);
-  gpr_mu_lock(&s->mu);
-  GPR_ASSERT(!s->on_accept_cb);
-  GPR_ASSERT(s->active_ports == 0);
-  s->on_accept_cb = on_accept_cb;
-  s->on_accept_cb_arg = on_accept_cb_arg;
-  s->pollsets = pollsets;
-  s->pollset_count = pollset_count;
-  for (sp = s->head; sp; sp = sp->next) {
-    for (i = 0; i < pollset_count; i++) {
-      grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd);
-    }
-    sp->read_closure.cb = on_read;
-    sp->read_closure.cb_arg = sp;
-    grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
-    s->active_ports++;
-  }
-  gpr_mu_unlock(&s->mu);
-}
-
-grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) {
-  gpr_ref(&s->refs);
-  return s;
-}
-
-void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
-                                           grpc_closure *shutdown_starting) {
-  gpr_mu_lock(&s->mu);
-  grpc_closure_list_add(&s->shutdown_starting, shutdown_starting, 1);
-  gpr_mu_unlock(&s->mu);
-}
-
-void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
-  if (gpr_unref(&s->refs)) {
-    /* Complete shutdown_starting work before destroying. */
-    grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT;
-    gpr_mu_lock(&s->mu);
-    grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL);
-    gpr_mu_unlock(&s->mu);
-    if (exec_ctx == NULL) {
-      grpc_exec_ctx_flush(&local_exec_ctx);
-      tcp_server_destroy(&local_exec_ctx, s);
-      grpc_exec_ctx_finish(&local_exec_ctx);
-    } else {
-      grpc_exec_ctx_finish(&local_exec_ctx);
-      tcp_server_destroy(exec_ctx, s);
-    }
-  }
-}
-
-#endif
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
deleted file mode 100644
index a4abc5b..0000000
--- a/src/core/iomgr/tcp_server_windows.c
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WINSOCK_SOCKET
-
-#include <io.h>
-
-#include "src/core/iomgr/sockaddr_utils.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/log_win32.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/time.h>
-
-#include "src/core/iomgr/iocp_windows.h"
-#include "src/core/iomgr/pollset_windows.h"
-#include "src/core/iomgr/socket_windows.h"
-#include "src/core/iomgr/tcp_server.h"
-#include "src/core/iomgr/tcp_windows.h"
-
-#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
-
-/* one listening port */
-typedef struct grpc_tcp_listener grpc_tcp_listener;
-struct grpc_tcp_listener {
-  /* This seemingly magic number comes from AcceptEx's documentation. each
-     address buffer needs to have at least 16 more bytes at their end. */
-  uint8_t addresses[(sizeof(struct sockaddr_in6) + 16) * 2];
-  /* This will hold the socket for the next accept. */
-  SOCKET new_socket;
-  /* The listener winsocket. */
-  grpc_winsocket *socket;
-  /* The actual TCP port number. */
-  int port;
-  unsigned port_index;
-  grpc_tcp_server *server;
-  /* The cached AcceptEx for that port. */
-  LPFN_ACCEPTEX AcceptEx;
-  int shutting_down;
-  /* closure for socket notification of accept being ready */
-  grpc_closure on_accept;
-  /* linked list */
-  struct grpc_tcp_listener *next;
-};
-
-/* the overall server */
-struct grpc_tcp_server {
-  gpr_refcount refs;
-  /* Called whenever accept() succeeds on a server port. */
-  grpc_tcp_server_cb on_accept_cb;
-  void *on_accept_cb_arg;
-
-  gpr_mu mu;
-
-  /* active port count: how many ports are actually still listening */
-  int active_ports;
-
-  /* linked list of server ports */
-  grpc_tcp_listener *head;
-  grpc_tcp_listener *tail;
-
-  /* List of closures passed to shutdown_starting_add(). */
-  grpc_closure_list shutdown_starting;
-
-  /* shutdown callback */
-  grpc_closure *shutdown_complete;
-};
-
-/* Public function. Allocates the proper data structures to hold a
-   grpc_tcp_server. */
-grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete) {
-  grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
-  gpr_ref_init(&s->refs, 1);
-  gpr_mu_init(&s->mu);
-  s->active_ports = 0;
-  s->on_accept_cb = NULL;
-  s->on_accept_cb_arg = NULL;
-  s->head = NULL;
-  s->tail = NULL;
-  s->shutdown_starting.head = NULL;
-  s->shutdown_starting.tail = NULL;
-  s->shutdown_complete = shutdown_complete;
-  return s;
-}
-
-static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
-  if (s->shutdown_complete != NULL) {
-    grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, true, NULL);
-  }
-
-  /* Now that the accepts have been aborted, we can destroy the sockets.
-     The IOCP won't get notified on these, so we can flag them as already
-     closed by the system. */
-  while (s->head) {
-    grpc_tcp_listener *sp = s->head;
-    s->head = sp->next;
-    sp->next = NULL;
-    grpc_winsocket_destroy(sp->socket);
-    gpr_free(sp);
-  }
-  gpr_free(s);
-}
-
-grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) {
-  gpr_ref(&s->refs);
-  return s;
-}
-
-void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
-                                           grpc_closure *shutdown_starting) {
-  gpr_mu_lock(&s->mu);
-  grpc_closure_list_add(&s->shutdown_starting, shutdown_starting, 1);
-  gpr_mu_unlock(&s->mu);
-}
-
-static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
-  int immediately_done = 0;
-  grpc_tcp_listener *sp;
-  gpr_mu_lock(&s->mu);
-
-  /* First, shutdown all fd's. This will queue abortion calls for all
-     of the pending accepts due to the normal operation mechanism. */
-  if (s->active_ports == 0) {
-    immediately_done = 1;
-  }
-  for (sp = s->head; sp; sp = sp->next) {
-    sp->shutting_down = 1;
-    grpc_winsocket_shutdown(sp->socket);
-  }
-  gpr_mu_unlock(&s->mu);
-
-  if (immediately_done) {
-    finish_shutdown(exec_ctx, s);
-  }
-}
-
-void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
-  if (gpr_unref(&s->refs)) {
-    /* Complete shutdown_starting work before destroying. */
-    grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT;
-    gpr_mu_lock(&s->mu);
-    grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL);
-    gpr_mu_unlock(&s->mu);
-    if (exec_ctx == NULL) {
-      grpc_exec_ctx_flush(&local_exec_ctx);
-      tcp_server_destroy(&local_exec_ctx, s);
-      grpc_exec_ctx_finish(&local_exec_ctx);
-    } else {
-      grpc_exec_ctx_finish(&local_exec_ctx);
-      tcp_server_destroy(exec_ctx, s);
-    }
-  }
-}
-
-/* Prepare (bind) a recently-created socket for listening. */
-static int prepare_socket(SOCKET sock, const struct sockaddr *addr,
-                          size_t addr_len) {
-  struct sockaddr_storage sockname_temp;
-  socklen_t sockname_len;
-
-  if (sock == INVALID_SOCKET) goto error;
-
-  if (!grpc_tcp_prepare_socket(sock)) {
-    char *utf8_message = gpr_format_message(WSAGetLastError());
-    gpr_log(GPR_ERROR, "Unable to prepare socket: %s", utf8_message);
-    gpr_free(utf8_message);
-    goto error;
-  }
-
-  if (bind(sock, addr, (int)addr_len) == SOCKET_ERROR) {
-    char *addr_str;
-    char *utf8_message = gpr_format_message(WSAGetLastError());
-    grpc_sockaddr_to_string(&addr_str, addr, 0);
-    gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, utf8_message);
-    gpr_free(utf8_message);
-    gpr_free(addr_str);
-    goto error;
-  }
-
-  if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
-    char *utf8_message = gpr_format_message(WSAGetLastError());
-    gpr_log(GPR_ERROR, "listen: %s", utf8_message);
-    gpr_free(utf8_message);
-    goto error;
-  }
-
-  sockname_len = sizeof(sockname_temp);
-  if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) ==
-      SOCKET_ERROR) {
-    char *utf8_message = gpr_format_message(WSAGetLastError());
-    gpr_log(GPR_ERROR, "getsockname: %s", utf8_message);
-    gpr_free(utf8_message);
-    goto error;
-  }
-
-  return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
-
-error:
-  if (sock != INVALID_SOCKET) closesocket(sock);
-  return -1;
-}
-
-static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
-                                              grpc_tcp_listener *sp) {
-  int notify = 0;
-  sp->shutting_down = 0;
-  gpr_mu_lock(&sp->server->mu);
-  GPR_ASSERT(sp->server->active_ports > 0);
-  if (0 == --sp->server->active_ports) {
-    notify = 1;
-  }
-  gpr_mu_unlock(&sp->server->mu);
-  if (notify) {
-    finish_shutdown(exec_ctx, sp->server);
-  }
-}
-
-/* In order to do an async accept, we need to create a socket first which
-   will be the one assigned to the new incoming connection. */
-static void start_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *port) {
-  SOCKET sock = INVALID_SOCKET;
-  char *message;
-  char *utf8_message;
-  BOOL success;
-  DWORD addrlen = sizeof(struct sockaddr_in6) + 16;
-  DWORD bytes_received = 0;
-
-  sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
-                   WSA_FLAG_OVERLAPPED);
-
-  if (sock == INVALID_SOCKET) {
-    message = "Unable to create socket: %s";
-    goto failure;
-  }
-
-  if (!grpc_tcp_prepare_socket(sock)) {
-    message = "Unable to prepare socket: %s";
-    goto failure;
-  }
-
-  /* Start the "accept" asynchronously. */
-  success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0,
-                           addrlen, addrlen, &bytes_received,
-                           &port->socket->read_info.overlapped);
-
-  /* It is possible to get an accept immediately without delay. However, we
-     will still get an IOCP notification for it. So let's just ignore it. */
-  if (!success) {
-    int error = WSAGetLastError();
-    if (error != ERROR_IO_PENDING) {
-      message = "AcceptEx failed: %s";
-      goto failure;
-    }
-  }
-
-  /* We're ready to do the accept. Calling grpc_socket_notify_on_read may
-     immediately process an accept that happened in the meantime. */
-  port->new_socket = sock;
-  grpc_socket_notify_on_read(exec_ctx, port->socket, &port->on_accept);
-  return;
-
-failure:
-  if (port->shutting_down) {
-    /* We are abandoning the listener port, take that into account to prevent
-       occasional hangs on shutdown. The hang happens when sp->shutting_down
-       change is not seen by on_accept and we proceed to trying new accept,
-       but we fail there because the listening port has been closed in the
-       meantime. */
-    decrement_active_ports_and_notify(exec_ctx, port);
-    return;
-  }
-  utf8_message = gpr_format_message(WSAGetLastError());
-  gpr_log(GPR_ERROR, message, utf8_message);
-  gpr_free(utf8_message);
-  if (sock != INVALID_SOCKET) closesocket(sock);
-}
-
-/* Event manager callback when reads are ready. */
-static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, bool from_iocp) {
-  grpc_tcp_listener *sp = arg;
-  grpc_tcp_server_acceptor acceptor = {sp->server, sp->port_index, 0};
-  SOCKET sock = sp->new_socket;
-  grpc_winsocket_callback_info *info = &sp->socket->read_info;
-  grpc_endpoint *ep = NULL;
-  struct sockaddr_storage peer_name;
-  char *peer_name_string;
-  char *fd_name;
-  int peer_name_len = sizeof(peer_name);
-  DWORD transfered_bytes;
-  DWORD flags;
-  BOOL wsa_success;
-  int err;
-
-  /* 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. We only need to adjust the pending callback count */
-  if (!from_iocp) {
-    return;
-  }
-
-  /* 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 well,
-         and we can wake up the shutdown thread. */
-      decrement_active_ports_and_notify(exec_ctx, sp);
-      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 {
-    if (!sp->shutting_down) {
-      peer_name_string = NULL;
-      err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
-                       (char *)&sp->socket->socket, sizeof(sp->socket->socket));
-      if (err) {
-        char *utf8_message = gpr_format_message(WSAGetLastError());
-        gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message);
-        gpr_free(utf8_message);
-      }
-      err = getpeername(sock, (struct sockaddr *)&peer_name, &peer_name_len);
-      if (!err) {
-        peer_name_string = grpc_sockaddr_to_uri((struct sockaddr *)&peer_name);
-      } else {
-        char *utf8_message = gpr_format_message(WSAGetLastError());
-        gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message);
-        gpr_free(utf8_message);
-      }
-      gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string);
-      ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name),
-                           peer_name_string);
-      gpr_free(fd_name);
-      gpr_free(peer_name_string);
-    } else {
-      closesocket(sock);
-    }
-  }
-
-  /* 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->on_accept_cb(exec_ctx, sp->server->on_accept_cb_arg, ep,
-                             &acceptor);
-  /* 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. */
-  start_accept(exec_ctx, sp);
-}
-
-static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
-                                               const struct sockaddr *addr,
-                                               size_t addr_len,
-                                               unsigned port_index) {
-  grpc_tcp_listener *sp = NULL;
-  int port;
-  int status;
-  GUID guid = WSAID_ACCEPTEX;
-  DWORD ioctl_num_bytes;
-  LPFN_ACCEPTEX AcceptEx;
-
-  if (sock == INVALID_SOCKET) return NULL;
-
-  /* We need to grab the AcceptEx pointer for that port, as it may be
-     interface-dependent. We'll cache it to avoid doing that again. */
-  status =
-      WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
-               &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL);
-
-  if (status != 0) {
-    char *utf8_message = gpr_format_message(WSAGetLastError());
-    gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
-    gpr_free(utf8_message);
-    closesocket(sock);
-    return NULL;
-  }
-
-  port = prepare_socket(sock, addr, addr_len);
-  if (port >= 0) {
-    gpr_mu_lock(&s->mu);
-    GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
-    sp = gpr_malloc(sizeof(grpc_tcp_listener));
-    sp->next = NULL;
-    if (s->head == NULL) {
-      s->head = sp;
-    } else {
-      s->tail->next = sp;
-    }
-    s->tail = sp;
-    sp->server = s;
-    sp->socket = grpc_winsocket_create(sock, "listener");
-    sp->shutting_down = 0;
-    sp->AcceptEx = AcceptEx;
-    sp->new_socket = INVALID_SOCKET;
-    sp->port = port;
-    sp->port_index = port_index;
-    grpc_closure_init(&sp->on_accept, on_accept, sp);
-    GPR_ASSERT(sp->socket);
-    gpr_mu_unlock(&s->mu);
-  }
-
-  return sp;
-}
-
-int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
-                             size_t addr_len) {
-  grpc_tcp_listener *sp;
-  SOCKET sock;
-  struct sockaddr_in6 addr6_v4mapped;
-  struct sockaddr_in6 wildcard;
-  struct sockaddr *allocated_addr = NULL;
-  struct sockaddr_storage sockname_temp;
-  socklen_t sockname_len;
-  int port;
-  unsigned port_index = 0;
-  if (s->tail != NULL) {
-    port_index = s->tail->port_index + 1;
-  }
-
-  /* Check if this is a wildcard port, and if so, try to keep the port the same
-     as some previously created listener. */
-  if (grpc_sockaddr_get_port(addr) == 0) {
-    for (sp = s->head; sp; sp = sp->next) {
-      sockname_len = sizeof(sockname_temp);
-      if (0 == getsockname(sp->socket->socket,
-                           (struct sockaddr *)&sockname_temp, &sockname_len)) {
-        port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
-        if (port > 0) {
-          allocated_addr = malloc(addr_len);
-          memcpy(allocated_addr, addr, addr_len);
-          grpc_sockaddr_set_port(allocated_addr, port);
-          addr = allocated_addr;
-          break;
-        }
-      }
-    }
-  }
-
-  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
-    addr = (const struct sockaddr *)&addr6_v4mapped;
-    addr_len = sizeof(addr6_v4mapped);
-  }
-
-  /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
-  if (grpc_sockaddr_is_wildcard(addr, &port)) {
-    grpc_sockaddr_make_wildcard6(port, &wildcard);
-
-    addr = (struct sockaddr *)&wildcard;
-    addr_len = sizeof(wildcard);
-  }
-
-  sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
-                   WSA_FLAG_OVERLAPPED);
-  if (sock == INVALID_SOCKET) {
-    char *utf8_message = gpr_format_message(WSAGetLastError());
-    gpr_log(GPR_ERROR, "unable to create socket: %s", utf8_message);
-    gpr_free(utf8_message);
-  }
-
-  sp = add_socket_to_server(s, sock, addr, addr_len, port_index);
-  gpr_free(allocated_addr);
-
-  if (sp) {
-    return sp->port;
-  } else {
-    return -1;
-  }
-}
-
-unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s,
-                                       unsigned port_index) {
-  grpc_tcp_listener *sp;
-  for (sp = s->head; sp && port_index != 0; sp = sp->next, --port_index)
-    ;
-  if (sp) {
-    return 1;
-  } else {
-    return 0;
-  }
-}
-
-int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index,
-                            unsigned fd_index) {
-  grpc_tcp_listener *sp;
-  if (fd_index != 0) {
-    /* Windows implementation has only one fd per port_index. */
-    return -1;
-  }
-  for (sp = s->head; sp && port_index != 0; sp = sp->next, --port_index)
-    ;
-  if (sp) {
-    return _open_osfhandle((intptr_t)sp->socket->socket, 0);
-  } else {
-    return -1;
-  }
-}
-
-void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
-                           grpc_pollset **pollset, size_t pollset_count,
-                           grpc_tcp_server_cb on_accept_cb,
-                           void *on_accept_cb_arg) {
-  grpc_tcp_listener *sp;
-  GPR_ASSERT(on_accept_cb);
-  gpr_mu_lock(&s->mu);
-  GPR_ASSERT(!s->on_accept_cb);
-  GPR_ASSERT(s->active_ports == 0);
-  s->on_accept_cb = on_accept_cb;
-  s->on_accept_cb_arg = on_accept_cb_arg;
-  for (sp = s->head; sp; sp = sp->next) {
-    start_accept(exec_ctx, sp);
-    s->active_ports++;
-  }
-  gpr_mu_unlock(&s->mu);
-}
-
-#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c
deleted file mode 100644
index 038e415..0000000
--- a/src/core/iomgr/tcp_windows.c
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WINSOCK_SOCKET
-
-#include "src/core/iomgr/sockaddr_win32.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/log_win32.h>
-#include <grpc/support/slice_buffer.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/iomgr/timer.h"
-#include "src/core/iomgr/iocp_windows.h"
-#include "src/core/iomgr/sockaddr.h"
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/iomgr/socket_windows.h"
-#include "src/core/iomgr/tcp_client.h"
-
-static int set_non_block(SOCKET sock) {
-  int status;
-  unsigned long param = 1;
-  DWORD ret;
-  status =
-      WSAIoctl(sock, FIONBIO, &param, sizeof(param), NULL, 0, &ret, NULL, NULL);
-  return status == 0;
-}
-
-static int set_dualstack(SOCKET sock) {
-  int status;
-  unsigned long param = 0;
-  status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&param,
-                      sizeof(param));
-  return status == 0;
-}
-
-int grpc_tcp_prepare_socket(SOCKET sock) {
-  if (!set_non_block(sock)) return 0;
-  if (!set_dualstack(sock)) return 0;
-  return 1;
-}
-
-typedef struct grpc_tcp {
-  /* This is our C++ class derivation emulation. */
-  grpc_endpoint base;
-  /* The one socket this endpoint is using. */
-  grpc_winsocket *socket;
-  /* Refcounting how many operations are in progress. */
-  gpr_refcount refcount;
-
-  grpc_closure on_read;
-  grpc_closure on_write;
-
-  grpc_closure *read_cb;
-  grpc_closure *write_cb;
-  gpr_slice read_slice;
-  gpr_slice_buffer *write_slices;
-  gpr_slice_buffer *read_slices;
-
-  /* The IO Completion Port runs from another thread. We need some mechanism
-     to protect ourselves when requesting a shutdown. */
-  gpr_mu mu;
-  int shutting_down;
-
-  char *peer_string;
-} grpc_tcp;
-
-static void tcp_free(grpc_tcp *tcp) {
-  grpc_winsocket_destroy(tcp->socket);
-  gpr_mu_destroy(&tcp->mu);
-  gpr_free(tcp->peer_string);
-  gpr_free(tcp);
-}
-
-/*#define GRPC_TCP_REFCOUNT_DEBUG*/
-#ifdef GRPC_TCP_REFCOUNT_DEBUG
-#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
-#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
-static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file,
-                      int line) {
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
-          reason, tcp->refcount.count, tcp->refcount.count - 1);
-  if (gpr_unref(&tcp->refcount)) {
-    tcp_free(tcp);
-  }
-}
-
-static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
-                    int line) {
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP   ref %p : %s %d -> %d", tcp,
-          reason, tcp->refcount.count, tcp->refcount.count + 1);
-  gpr_ref(&tcp->refcount);
-}
-#else
-#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
-#define TCP_REF(tcp, reason) tcp_ref((tcp))
-static void tcp_unref(grpc_tcp *tcp) {
-  if (gpr_unref(&tcp->refcount)) {
-    tcp_free(tcp);
-  }
-}
-
-static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
-#endif
-
-/* Asynchronous callback from the IOCP, or the background thread. */
-static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) {
-  grpc_tcp *tcp = tcpp;
-  grpc_closure *cb = tcp->read_cb;
-  grpc_winsocket *socket = tcp->socket;
-  gpr_slice sub;
-  grpc_winsocket_callback_info *info = &socket->read_info;
-
-  if (success) {
-    if (socket->read_info.wsa_error != 0 && !tcp->shutting_down) {
-      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);
-      }
-      success = 0;
-      gpr_slice_unref(tcp->read_slice);
-    } else {
-      if (info->bytes_transfered != 0 && !tcp->shutting_down) {
-        sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
-        gpr_slice_buffer_add(tcp->read_slices, sub);
-        success = 1;
-      } else {
-        gpr_slice_unref(tcp->read_slice);
-        success = 0;
-      }
-    }
-  }
-
-  tcp->read_cb = NULL;
-  TCP_UNREF(tcp, "read");
-  if (cb) {
-    cb->cb(exec_ctx, cb->cb_arg, success);
-  }
-}
-
-static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                     gpr_slice_buffer *read_slices, grpc_closure *cb) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  grpc_winsocket *handle = tcp->socket;
-  grpc_winsocket_callback_info *info = &handle->read_info;
-  int status;
-  DWORD bytes_read = 0;
-  DWORD flags = 0;
-  WSABUF buffer;
-
-  if (tcp->shutting_down) {
-    grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
-    return;
-  }
-
-  tcp->read_cb = cb;
-  tcp->read_slices = read_slices;
-  gpr_slice_buffer_reset_and_unref(read_slices);
-
-  tcp->read_slice = gpr_slice_malloc(8192);
-
-  buffer.len = (ULONG)GPR_SLICE_LENGTH(
-      tcp->read_slice);  // we know slice size fits in 32bit.
-  buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
-
-  TCP_REF(tcp, "read");
-
-  /* First let's try a synchronous, non-blocking read. */
-  status =
-      WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL);
-  info->wsa_error = status == 0 ? 0 : WSAGetLastError();
-
-  /* Did we get data immediately ? Yay. */
-  if (info->wsa_error != WSAEWOULDBLOCK) {
-    info->bytes_transfered = bytes_read;
-    grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, true, NULL);
-    return;
-  }
-
-  /* Otherwise, let's retry, by queuing a read. */
-  memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
-  status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
-                   &info->overlapped, NULL);
-
-  if (status != 0) {
-    int wsa_error = WSAGetLastError();
-    if (wsa_error != WSA_IO_PENDING) {
-      info->wsa_error = wsa_error;
-      grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, false, NULL);
-      return;
-    }
-  }
-
-  grpc_socket_notify_on_read(exec_ctx, tcp->socket, &tcp->on_read);
-}
-
-/* Asynchronous callback from the IOCP, or the background thread. */
-static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) {
-  grpc_tcp *tcp = (grpc_tcp *)tcpp;
-  grpc_winsocket *handle = tcp->socket;
-  grpc_winsocket_callback_info *info = &handle->write_info;
-  grpc_closure *cb;
-
-  gpr_mu_lock(&tcp->mu);
-  cb = tcp->write_cb;
-  tcp->write_cb = NULL;
-  gpr_mu_unlock(&tcp->mu);
-
-  if (success) {
-    if (info->wsa_error != 0) {
-      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);
-      }
-      success = 0;
-    } else {
-      GPR_ASSERT(info->bytes_transfered == tcp->write_slices->length);
-    }
-  }
-
-  TCP_UNREF(tcp, "write");
-  cb->cb(exec_ctx, cb->cb_arg, success);
-}
-
-/* Initiates a write. */
-static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                      gpr_slice_buffer *slices, grpc_closure *cb) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  grpc_winsocket *socket = tcp->socket;
-  grpc_winsocket_callback_info *info = &socket->write_info;
-  unsigned i;
-  DWORD bytes_sent;
-  int status;
-  WSABUF local_buffers[16];
-  WSABUF *allocated = NULL;
-  WSABUF *buffers = local_buffers;
-  size_t len;
-
-  if (tcp->shutting_down) {
-    grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
-    return;
-  }
-
-  tcp->write_cb = cb;
-  tcp->write_slices = slices;
-  GPR_ASSERT(tcp->write_slices->count <= UINT_MAX);
-  if (tcp->write_slices->count > GPR_ARRAY_SIZE(local_buffers)) {
-    buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices->count);
-    allocated = buffers;
-  }
-
-  for (i = 0; i < tcp->write_slices->count; i++) {
-    len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]);
-    GPR_ASSERT(len <= ULONG_MAX);
-    buffers[i].len = (ULONG)len;
-    buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices->slices[i]);
-  }
-
-  /* First, let's try a synchronous, non-blocking write. */
-  status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
-                   &bytes_sent, 0, NULL, NULL);
-  info->wsa_error = status == 0 ? 0 : WSAGetLastError();
-
-  /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
-     connection that has its send queue filled up. But if we don't, then we can
-     avoid doing an async write operation at all. */
-  if (info->wsa_error != WSAEWOULDBLOCK) {
-    bool ok = false;
-    if (status == 0) {
-      ok = true;
-      GPR_ASSERT(bytes_sent == tcp->write_slices->length);
-    } else {
-      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);
-    grpc_exec_ctx_enqueue(exec_ctx, cb, ok, NULL);
-    return;
-  }
-
-  TCP_REF(tcp, "write");
-
-  /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
-     operation, this time asynchronously. */
-  memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
-  status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
-                   &bytes_sent, 0, &socket->write_info.overlapped, NULL);
-  if (allocated) gpr_free(allocated);
-
-  if (status != 0) {
-    int wsa_error = WSAGetLastError();
-    if (wsa_error != WSA_IO_PENDING) {
-      TCP_UNREF(tcp, "write");
-      grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
-      return;
-    }
-  }
-
-  /* As all is now setup, we can now ask for the IOCP notification. It may
-     trigger the callback immediately however, but no matter. */
-  grpc_socket_notify_on_write(exec_ctx, socket, &tcp->on_write);
-}
-
-static void win_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                               grpc_pollset *ps) {
-  grpc_tcp *tcp;
-  (void)ps;
-  tcp = (grpc_tcp *)ep;
-  grpc_iocp_add_socket(tcp->socket);
-}
-
-static void win_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
-                                   grpc_pollset_set *pss) {
-  grpc_tcp *tcp;
-  (void)pss;
-  tcp = (grpc_tcp *)ep;
-  grpc_iocp_add_socket(tcp->socket);
-}
-
-/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks
-   for the potential read and write operations. It is up to the caller to
-   guarantee this isn't called in parallel to a read or write request, so
-   we're not going to protect against these. However the IO Completion Port
-   callback will happen from another thread, so we need to protect against
-   concurrent access of the data structure in that regard. */
-static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  gpr_mu_lock(&tcp->mu);
-  /* At that point, what may happen is that we're already inside the IOCP
-     callback. See the comments in on_read and on_write. */
-  tcp->shutting_down = 1;
-  grpc_winsocket_shutdown(tcp->socket);
-  gpr_mu_unlock(&tcp->mu);
-}
-
-static void win_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  TCP_UNREF(tcp, "destroy");
-}
-
-static char *win_get_peer(grpc_endpoint *ep) {
-  grpc_tcp *tcp = (grpc_tcp *)ep;
-  return gpr_strdup(tcp->peer_string);
-}
-
-static grpc_endpoint_vtable vtable = {win_read, win_write, win_add_to_pollset,
-                                      win_add_to_pollset_set, win_shutdown,
-                                      win_destroy, win_get_peer};
-
-grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
-  grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
-  memset(tcp, 0, sizeof(grpc_tcp));
-  tcp->base.vtable = &vtable;
-  tcp->socket = socket;
-  gpr_mu_init(&tcp->mu);
-  gpr_ref_init(&tcp->refcount, 1);
-  grpc_closure_init(&tcp->on_read, on_read, tcp);
-  grpc_closure_init(&tcp->on_write, on_write, tcp);
-  tcp->peer_string = gpr_strdup(peer_string);
-  return &tcp->base;
-}
-
-#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/tcp_windows.h b/src/core/iomgr/tcp_windows.h
deleted file mode 100644
index deb3e48..0000000
--- a/src/core/iomgr/tcp_windows.h
+++ /dev/null
@@ -1,57 +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_TCP_WINDOWS_H
-#define GRPC_INTERNAL_CORE_IOMGR_TCP_WINDOWS_H
-/*
-   Low level TCP "bottom half" implementation, for use by transports built on
-   top of a TCP connection.
-
-   Note that this file does not (yet) include APIs for creating the socket in
-   the first place.
-
-   All calls passing slice transfer ownership of a slice refcount unless
-   otherwise specified.
-*/
-
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/iomgr/socket_windows.h"
-
-/* Create a tcp endpoint given a winsock handle.
- * Takes ownership of the handle.
- */
-grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string);
-
-int grpc_tcp_prepare_socket(SOCKET sock);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_WINDOWS_H */
diff --git a/src/core/iomgr/time_averaged_stats.c b/src/core/iomgr/time_averaged_stats.c
deleted file mode 100644
index e075db4..0000000
--- a/src/core/iomgr/time_averaged_stats.c
+++ /dev/null
@@ -1,77 +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/iomgr/time_averaged_stats.h"
-
-void grpc_time_averaged_stats_init(grpc_time_averaged_stats* stats,
-                                   double init_avg, double regress_weight,
-                                   double persistence_factor) {
-  stats->init_avg = init_avg;
-  stats->regress_weight = regress_weight;
-  stats->persistence_factor = persistence_factor;
-  stats->batch_total_value = 0;
-  stats->batch_num_samples = 0;
-  stats->aggregate_total_weight = 0;
-  stats->aggregate_weighted_avg = init_avg;
-}
-
-void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats* stats,
-                                         double value) {
-  stats->batch_total_value += value;
-  ++stats->batch_num_samples;
-}
-
-double grpc_time_averaged_stats_update_average(
-    grpc_time_averaged_stats* stats) {
-  /* Start with the current batch: */
-  double weighted_sum = stats->batch_total_value;
-  double total_weight = stats->batch_num_samples;
-  if (stats->regress_weight > 0) {
-    /* Add in the regression towards init_avg_: */
-    weighted_sum += stats->regress_weight * stats->init_avg;
-    total_weight += stats->regress_weight;
-  }
-  if (stats->persistence_factor > 0) {
-    /* Add in the persistence: */
-    const double prev_sample_weight =
-        stats->persistence_factor * stats->aggregate_total_weight;
-    weighted_sum += prev_sample_weight * stats->aggregate_weighted_avg;
-    total_weight += prev_sample_weight;
-  }
-  stats->aggregate_weighted_avg =
-      (total_weight > 0) ? (weighted_sum / total_weight) : stats->init_avg;
-  stats->aggregate_total_weight = total_weight;
-  stats->batch_num_samples = 0;
-  stats->batch_total_value = 0;
-  return stats->aggregate_weighted_avg;
-}
diff --git a/src/core/iomgr/time_averaged_stats.h b/src/core/iomgr/time_averaged_stats.h
deleted file mode 100644
index 4e9e395..0000000
--- a/src/core/iomgr/time_averaged_stats.h
+++ /dev/null
@@ -1,88 +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_TIME_AVERAGED_STATS_H
-#define GRPC_INTERNAL_CORE_IOMGR_TIME_AVERAGED_STATS_H
-
-/* This tracks a time-decaying weighted average.  It works by collecting
-   batches of samples and then mixing their average into a time-decaying
-   weighted mean.  It is designed for batch operations where we do many adds
-   before updating the average. */
-
-typedef struct {
-  /* The initial average value.  This is the reported average until the first
-     grpc_time_averaged_stats_update_average call.  If a positive regress_weight
-     is used, we also regress towards this value on each update. */
-  double init_avg;
-  /* The sample weight of "init_avg" that is mixed in with each call to
-     grpc_time_averaged_stats_update_average.  If the calls to
-     grpc_time_averaged_stats_add_sample stop, this will cause the average to
-     regress back to the mean.  This should be non-negative.  Set it to 0 to
-     disable the bias.  A value of 1 has the effect of adding in 1 bonus sample
-     with value init_avg to each sample period. */
-  double regress_weight;
-  /* This determines the rate of decay of the time-averaging from one period
-     to the next by scaling the aggregate_total_weight of samples from prior
-     periods when combining with the latest period.  It should be in the range
-     [0,1].  A higher value adapts more slowly.  With a value of 0.5, if the
-     batches each have k samples, the samples_in_avg_ will grow to 2 k, so the
-     weighting of the time average will eventually be 1/3 new batch and 2/3
-     old average. */
-  double persistence_factor;
-
-  /* The total value of samples since the last UpdateAverage(). */
-  double batch_total_value;
-  /* The number of samples since the last UpdateAverage(). */
-  double batch_num_samples;
-  /* The time-decayed sum of batch_num_samples_ over previous batches.  This is
-     the "weight" of the old aggregate_weighted_avg_ when updating the
-     average. */
-  double aggregate_total_weight;
-  /* A time-decayed average of the (batch_total_value_ / batch_num_samples_),
-     computed by decaying the samples_in_avg_ weight in the weighted average. */
-  double aggregate_weighted_avg;
-} grpc_time_averaged_stats;
-
-/* See the comments on the members above for an explanation of init_avg,
-   regress_weight, and persistence_factor. */
-void grpc_time_averaged_stats_init(grpc_time_averaged_stats* stats,
-                                   double init_avg, double regress_weight,
-                                   double persistence_factor);
-/* Add a sample to the current batch. */
-void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats* stats,
-                                         double value);
-/* Complete a batch and compute the new estimate of the average sample
-   value. */
-double grpc_time_averaged_stats_update_average(grpc_time_averaged_stats* stats);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_TIME_AVERAGED_STATS_H */
diff --git a/src/core/iomgr/timer.c b/src/core/iomgr/timer.c
deleted file mode 100644
index 8379fff..0000000
--- a/src/core/iomgr/timer.c
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/iomgr/timer.h"
-
-#include "src/core/iomgr/timer_heap.h"
-#include "src/core/iomgr/time_averaged_stats.h"
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
-
-#define INVALID_HEAP_INDEX 0xffffffffu
-
-#define LOG2_NUM_SHARDS 5
-#define NUM_SHARDS (1 << LOG2_NUM_SHARDS)
-#define ADD_DEADLINE_SCALE 0.33
-#define MIN_QUEUE_WINDOW_DURATION 0.01
-#define MAX_QUEUE_WINDOW_DURATION 1
-
-typedef struct {
-  gpr_mu mu;
-  grpc_time_averaged_stats stats;
-  /* All and only timers with deadlines <= this will be in the heap. */
-  gpr_timespec queue_deadline_cap;
-  gpr_timespec min_deadline;
-  /* Index in the g_shard_queue */
-  uint32_t shard_queue_index;
-  /* This holds all timers with deadlines < queue_deadline_cap. Timers in this
-     list have the top bit of their deadline set to 0. */
-  grpc_timer_heap heap;
-  /* This holds timers whose deadline is >= queue_deadline_cap. */
-  grpc_timer list;
-} shard_type;
-
-/* Protects g_shard_queue */
-static gpr_mu g_mu;
-/* Allow only one run_some_expired_timers at once */
-static gpr_mu g_checker_mu;
-static gpr_clock_type g_clock_type;
-static shard_type g_shards[NUM_SHARDS];
-/* Protected by g_mu */
-static shard_type *g_shard_queue[NUM_SHARDS];
-
-static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
-                                   gpr_timespec *next, int success);
-
-static gpr_timespec compute_min_deadline(shard_type *shard) {
-  return grpc_timer_heap_is_empty(&shard->heap)
-             ? shard->queue_deadline_cap
-             : grpc_timer_heap_top(&shard->heap)->deadline;
-}
-
-void grpc_timer_list_init(gpr_timespec now) {
-  uint32_t i;
-
-  gpr_mu_init(&g_mu);
-  gpr_mu_init(&g_checker_mu);
-  g_clock_type = now.clock_type;
-
-  for (i = 0; i < NUM_SHARDS; i++) {
-    shard_type *shard = &g_shards[i];
-    gpr_mu_init(&shard->mu);
-    grpc_time_averaged_stats_init(&shard->stats, 1.0 / ADD_DEADLINE_SCALE, 0.1,
-                                  0.5);
-    shard->queue_deadline_cap = now;
-    shard->shard_queue_index = i;
-    grpc_timer_heap_init(&shard->heap);
-    shard->list.next = shard->list.prev = &shard->list;
-    shard->min_deadline = compute_min_deadline(shard);
-    g_shard_queue[i] = shard;
-  }
-}
-
-void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx) {
-  int i;
-  run_some_expired_timers(exec_ctx, gpr_inf_future(g_clock_type), NULL, 0);
-  for (i = 0; i < NUM_SHARDS; i++) {
-    shard_type *shard = &g_shards[i];
-    gpr_mu_destroy(&shard->mu);
-    grpc_timer_heap_destroy(&shard->heap);
-  }
-  gpr_mu_destroy(&g_mu);
-  gpr_mu_destroy(&g_checker_mu);
-}
-
-/* This is a cheap, but good enough, pointer hash for sharding the tasks: */
-static size_t shard_idx(const grpc_timer *info) {
-  size_t x = (size_t)info;
-  return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) & (NUM_SHARDS - 1);
-}
-
-static double ts_to_dbl(gpr_timespec ts) {
-  return (double)ts.tv_sec + 1e-9 * ts.tv_nsec;
-}
-
-static gpr_timespec dbl_to_ts(double d) {
-  gpr_timespec ts;
-  ts.tv_sec = (int64_t)d;
-  ts.tv_nsec = (int32_t)(1e9 * (d - (double)ts.tv_sec));
-  ts.clock_type = GPR_TIMESPAN;
-  return ts;
-}
-
-static void list_join(grpc_timer *head, grpc_timer *timer) {
-  timer->next = head;
-  timer->prev = head->prev;
-  timer->next->prev = timer->prev->next = timer;
-}
-
-static void list_remove(grpc_timer *timer) {
-  timer->next->prev = timer->prev;
-  timer->prev->next = timer->next;
-}
-
-static void swap_adjacent_shards_in_queue(uint32_t first_shard_queue_index) {
-  shard_type *temp;
-  temp = g_shard_queue[first_shard_queue_index];
-  g_shard_queue[first_shard_queue_index] =
-      g_shard_queue[first_shard_queue_index + 1];
-  g_shard_queue[first_shard_queue_index + 1] = temp;
-  g_shard_queue[first_shard_queue_index]->shard_queue_index =
-      first_shard_queue_index;
-  g_shard_queue[first_shard_queue_index + 1]->shard_queue_index =
-      first_shard_queue_index + 1;
-}
-
-static void note_deadline_change(shard_type *shard) {
-  while (shard->shard_queue_index > 0 &&
-         gpr_time_cmp(
-             shard->min_deadline,
-             g_shard_queue[shard->shard_queue_index - 1]->min_deadline) < 0) {
-    swap_adjacent_shards_in_queue(shard->shard_queue_index - 1);
-  }
-  while (shard->shard_queue_index < NUM_SHARDS - 1 &&
-         gpr_time_cmp(
-             shard->min_deadline,
-             g_shard_queue[shard->shard_queue_index + 1]->min_deadline) > 0) {
-    swap_adjacent_shards_in_queue(shard->shard_queue_index);
-  }
-}
-
-void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
-                     gpr_timespec deadline, grpc_iomgr_cb_func timer_cb,
-                     void *timer_cb_arg, gpr_timespec now) {
-  int is_first_timer = 0;
-  shard_type *shard = &g_shards[shard_idx(timer)];
-  GPR_ASSERT(deadline.clock_type == g_clock_type);
-  GPR_ASSERT(now.clock_type == g_clock_type);
-  grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg);
-  timer->deadline = deadline;
-  timer->triggered = 0;
-
-  /* TODO(ctiller): check deadline expired */
-
-  gpr_mu_lock(&shard->mu);
-  grpc_time_averaged_stats_add_sample(&shard->stats,
-                                      ts_to_dbl(gpr_time_sub(deadline, now)));
-  if (gpr_time_cmp(deadline, shard->queue_deadline_cap) < 0) {
-    is_first_timer = grpc_timer_heap_add(&shard->heap, timer);
-  } else {
-    timer->heap_index = INVALID_HEAP_INDEX;
-    list_join(&shard->list, timer);
-  }
-  gpr_mu_unlock(&shard->mu);
-
-  /* Deadline may have decreased, we need to adjust the master queue.  Note
-     that there is a potential racy unlocked region here.  There could be a
-     reordering of multiple grpc_timer_init calls, at this point, but the < test
-     below should ensure that we err on the side of caution.  There could
-     also be a race with grpc_timer_check, which might beat us to the lock.  In
-     that case, it is possible that the timer that we added will have already
-     run by the time we hold the lock, but that too is a safe error.
-     Finally, it's possible that the grpc_timer_check that intervened failed to
-     trigger the new timer because the min_deadline hadn't yet been reduced.
-     In that case, the timer will simply have to wait for the next
-     grpc_timer_check. */
-  if (is_first_timer) {
-    gpr_mu_lock(&g_mu);
-    if (gpr_time_cmp(deadline, shard->min_deadline) < 0) {
-      gpr_timespec old_min_deadline = g_shard_queue[0]->min_deadline;
-      shard->min_deadline = deadline;
-      note_deadline_change(shard);
-      if (shard->shard_queue_index == 0 &&
-          gpr_time_cmp(deadline, old_min_deadline) < 0) {
-        grpc_kick_poller();
-      }
-    }
-    gpr_mu_unlock(&g_mu);
-  }
-}
-
-void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) {
-  shard_type *shard = &g_shards[shard_idx(timer)];
-  gpr_mu_lock(&shard->mu);
-  if (!timer->triggered) {
-    grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, false, NULL);
-    timer->triggered = 1;
-    if (timer->heap_index == INVALID_HEAP_INDEX) {
-      list_remove(timer);
-    } else {
-      grpc_timer_heap_remove(&shard->heap, timer);
-    }
-  }
-  gpr_mu_unlock(&shard->mu);
-}
-
-/* This is called when the queue is empty and "now" has reached the
-   queue_deadline_cap.  We compute a new queue deadline and then scan the map
-   for timers that fall at or under it.  Returns true if the queue is no
-   longer empty.
-   REQUIRES: shard->mu locked */
-static int refill_queue(shard_type *shard, gpr_timespec now) {
-  /* Compute the new queue window width and bound by the limits: */
-  double computed_deadline_delta =
-      grpc_time_averaged_stats_update_average(&shard->stats) *
-      ADD_DEADLINE_SCALE;
-  double deadline_delta =
-      GPR_CLAMP(computed_deadline_delta, MIN_QUEUE_WINDOW_DURATION,
-                MAX_QUEUE_WINDOW_DURATION);
-  grpc_timer *timer, *next;
-
-  /* Compute the new cap and put all timers under it into the queue: */
-  shard->queue_deadline_cap = gpr_time_add(
-      gpr_time_max(now, shard->queue_deadline_cap), dbl_to_ts(deadline_delta));
-  for (timer = shard->list.next; timer != &shard->list; timer = next) {
-    next = timer->next;
-
-    if (gpr_time_cmp(timer->deadline, shard->queue_deadline_cap) < 0) {
-      list_remove(timer);
-      grpc_timer_heap_add(&shard->heap, timer);
-    }
-  }
-  return !grpc_timer_heap_is_empty(&shard->heap);
-}
-
-/* This pops the next non-cancelled timer with deadline <= now from the queue,
-   or returns NULL if there isn't one.
-   REQUIRES: shard->mu locked */
-static grpc_timer *pop_one(shard_type *shard, gpr_timespec now) {
-  grpc_timer *timer;
-  for (;;) {
-    if (grpc_timer_heap_is_empty(&shard->heap)) {
-      if (gpr_time_cmp(now, shard->queue_deadline_cap) < 0) return NULL;
-      if (!refill_queue(shard, now)) return NULL;
-    }
-    timer = grpc_timer_heap_top(&shard->heap);
-    if (gpr_time_cmp(timer->deadline, now) > 0) return NULL;
-    timer->triggered = 1;
-    grpc_timer_heap_pop(&shard->heap);
-    return timer;
-  }
-}
-
-/* REQUIRES: shard->mu unlocked */
-static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard,
-                         gpr_timespec now, gpr_timespec *new_min_deadline,
-                         int success) {
-  size_t n = 0;
-  grpc_timer *timer;
-  gpr_mu_lock(&shard->mu);
-  while ((timer = pop_one(shard, now))) {
-    grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, success, NULL);
-    n++;
-  }
-  *new_min_deadline = compute_min_deadline(shard);
-  gpr_mu_unlock(&shard->mu);
-  return n;
-}
-
-static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
-                                   gpr_timespec *next, int success) {
-  size_t n = 0;
-
-  /* TODO(ctiller): verify that there are any timers (atomically) here */
-
-  if (gpr_mu_trylock(&g_checker_mu)) {
-    gpr_mu_lock(&g_mu);
-
-    while (gpr_time_cmp(g_shard_queue[0]->min_deadline, now) < 0) {
-      gpr_timespec new_min_deadline;
-
-      /* For efficiency, we pop as many available timers as we can from the
-         shard.  This may violate perfect timer deadline ordering, but that
-         shouldn't be a big deal because we don't make ordering guarantees. */
-      n += pop_timers(exec_ctx, g_shard_queue[0], now, &new_min_deadline,
-                      success);
-
-      /* An grpc_timer_init() on the shard could intervene here, adding a new
-         timer that is earlier than new_min_deadline.  However,
-         grpc_timer_init() will block on the master_lock before it can call
-         set_min_deadline, so this one will complete first and then the Addtimer
-         will reduce the min_deadline (perhaps unnecessarily). */
-      g_shard_queue[0]->min_deadline = new_min_deadline;
-      note_deadline_change(g_shard_queue[0]);
-    }
-
-    if (next) {
-      *next = gpr_time_min(*next, g_shard_queue[0]->min_deadline);
-    }
-
-    gpr_mu_unlock(&g_mu);
-    gpr_mu_unlock(&g_checker_mu);
-  }
-
-  return (int)n;
-}
-
-bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now,
-                      gpr_timespec *next) {
-  GPR_ASSERT(now.clock_type == g_clock_type);
-  return run_some_expired_timers(
-      exec_ctx, now, next,
-      gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0);
-}
diff --git a/src/core/iomgr/timer.h b/src/core/iomgr/timer.h
deleted file mode 100644
index 9ad1e92..0000000
--- a/src/core/iomgr/timer.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_TIMER_H
-#define GRPC_INTERNAL_CORE_IOMGR_TIMER_H
-
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/iomgr/exec_ctx.h"
-#include <grpc/support/port_platform.h>
-#include <grpc/support/time.h>
-
-typedef struct grpc_timer {
-  gpr_timespec deadline;
-  uint32_t heap_index; /* INVALID_HEAP_INDEX if not in heap */
-  int triggered;
-  struct grpc_timer *next;
-  struct grpc_timer *prev;
-  grpc_closure closure;
-} grpc_timer;
-
-/* Initialize *timer. When expired or canceled, timer_cb will be called with
-   *timer_cb_arg and status to indicate if it expired (SUCCESS) or was
-   canceled (CANCELLED). timer_cb is guaranteed to be called exactly once,
-   and application code should check the status to determine how it was
-   invoked. The application callback is also responsible for maintaining
-   information about when to free up any user-level state. */
-void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
-                     gpr_timespec deadline, grpc_iomgr_cb_func timer_cb,
-                     void *timer_cb_arg, gpr_timespec now);
-
-/* Note that there is no timer destroy function. This is because the
-   timer is a one-time occurrence with a guarantee that the callback will
-   be called exactly once, either at expiration or cancellation. Thus, all
-   the internal timer event management state is destroyed just before
-   that callback is invoked. If the user has additional state associated with
-   the timer, the user is responsible for determining when it is safe to
-   destroy that state. */
-
-/* Cancel an *timer.
-   There are three cases:
-   1. We normally cancel the timer
-   2. The timer has already run
-   3. We can't cancel the timer because it is "in flight".
-
-   In all of these cases, the cancellation is still considered successful.
-   They are essentially distinguished in that the timer_cb will be run
-   exactly once from either the cancellation (with status CANCELLED)
-   or from the activation (with status SUCCESS)
-
-   Note carefully that the callback function MAY occur in the same callstack
-   as grpc_timer_cancel. It's expected that most timers will be cancelled (their
-   primary use is to implement deadlines), and so this code is optimized such
-   that cancellation costs as little as possible. Making callbacks run inline
-   matches this aim.
-
-   Requires:  cancel() must happen after add() on a given timer */
-void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer);
-
-/* iomgr internal api for dealing with timers */
-
-/* Check for timers to be run, and run them.
-   Return true if timer callbacks were executed.
-   Drops drop_mu if it is non-null before executing callbacks.
-   If next is non-null, TRY to update *next with the next running timer
-   IF that timer occurs before *next current value.
-   *next is never guaranteed to be updated on any given execution; however,
-   with high probability at least one thread in the system will see an update
-   at any time slice. */
-
-bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now,
-                      gpr_timespec *next);
-void grpc_timer_list_init(gpr_timespec now);
-void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx);
-
-/* the following must be implemented by each iomgr implementation */
-
-void grpc_kick_poller(void);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_TIMER_H */
diff --git a/src/core/iomgr/timer_heap.c b/src/core/iomgr/timer_heap.c
deleted file mode 100644
index b5df566..0000000
--- a/src/core/iomgr/timer_heap.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/iomgr/timer_heap.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/useful.h>
-
-/* Adjusts a heap so as to move a hole at position i closer to the root,
-   until a suitable position is found for element t. Then, copies t into that
-   position. This functor is called each time immediately after modifying a
-   value in the underlying container, with the offset of the modified element as
-   its argument. */
-static void adjust_upwards(grpc_timer **first, uint32_t i, grpc_timer *t) {
-  while (i > 0) {
-    uint32_t parent = (uint32_t)(((int)i - 1) / 2);
-    if (gpr_time_cmp(first[parent]->deadline, t->deadline) <= 0) break;
-    first[i] = first[parent];
-    first[i]->heap_index = i;
-    i = parent;
-  }
-  first[i] = t;
-  t->heap_index = i;
-}
-
-/* Adjusts a heap so as to move a hole at position i farther away from the root,
-   until a suitable position is found for element t.  Then, copies t into that
-   position. */
-static void adjust_downwards(grpc_timer **first, uint32_t i, uint32_t length,
-                             grpc_timer *t) {
-  for (;;) {
-    uint32_t left_child = 1u + 2u * i;
-    if (left_child >= length) break;
-    uint32_t right_child = left_child + 1;
-    uint32_t next_i = right_child < length &&
-                              gpr_time_cmp(first[left_child]->deadline,
-                                           first[right_child]->deadline) > 0
-                          ? right_child
-                          : left_child;
-    if (gpr_time_cmp(t->deadline, first[next_i]->deadline) <= 0) break;
-    first[i] = first[next_i];
-    first[i]->heap_index = i;
-    i = next_i;
-  }
-  first[i] = t;
-  t->heap_index = i;
-}
-
-#define SHRINK_MIN_ELEMS 8
-#define SHRINK_FULLNESS_FACTOR 2
-
-static void maybe_shrink(grpc_timer_heap *heap) {
-  if (heap->timer_count >= 8 &&
-      heap->timer_count <= heap->timer_capacity / SHRINK_FULLNESS_FACTOR / 2) {
-    heap->timer_capacity = heap->timer_count * SHRINK_FULLNESS_FACTOR;
-    heap->timers =
-        gpr_realloc(heap->timers, heap->timer_capacity * sizeof(grpc_timer *));
-  }
-}
-
-static void note_changed_priority(grpc_timer_heap *heap, grpc_timer *timer) {
-  uint32_t i = timer->heap_index;
-  uint32_t parent = (uint32_t)(((int)i - 1) / 2);
-  if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) > 0) {
-    adjust_upwards(heap->timers, i, timer);
-  } else {
-    adjust_downwards(heap->timers, i, heap->timer_count, timer);
-  }
-}
-
-void grpc_timer_heap_init(grpc_timer_heap *heap) {
-  memset(heap, 0, sizeof(*heap));
-}
-
-void grpc_timer_heap_destroy(grpc_timer_heap *heap) { gpr_free(heap->timers); }
-
-int grpc_timer_heap_add(grpc_timer_heap *heap, grpc_timer *timer) {
-  if (heap->timer_count == heap->timer_capacity) {
-    heap->timer_capacity =
-        GPR_MAX(heap->timer_capacity + 1, heap->timer_capacity * 3 / 2);
-    heap->timers =
-        gpr_realloc(heap->timers, heap->timer_capacity * sizeof(grpc_timer *));
-  }
-  timer->heap_index = heap->timer_count;
-  adjust_upwards(heap->timers, heap->timer_count, timer);
-  heap->timer_count++;
-  return timer->heap_index == 0;
-}
-
-void grpc_timer_heap_remove(grpc_timer_heap *heap, grpc_timer *timer) {
-  uint32_t i = timer->heap_index;
-  if (i == heap->timer_count - 1) {
-    heap->timer_count--;
-    maybe_shrink(heap);
-    return;
-  }
-  heap->timers[i] = heap->timers[heap->timer_count - 1];
-  heap->timers[i]->heap_index = i;
-  heap->timer_count--;
-  maybe_shrink(heap);
-  note_changed_priority(heap, heap->timers[i]);
-}
-
-int grpc_timer_heap_is_empty(grpc_timer_heap *heap) {
-  return heap->timer_count == 0;
-}
-
-grpc_timer *grpc_timer_heap_top(grpc_timer_heap *heap) {
-  return heap->timers[0];
-}
-
-void grpc_timer_heap_pop(grpc_timer_heap *heap) {
-  grpc_timer_heap_remove(heap, grpc_timer_heap_top(heap));
-}
diff --git a/src/core/iomgr/timer_heap.h b/src/core/iomgr/timer_heap.h
deleted file mode 100644
index 2d220f1..0000000
--- a/src/core/iomgr/timer_heap.h
+++ /dev/null
@@ -1,57 +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_TIMER_HEAP_H
-#define GRPC_INTERNAL_CORE_IOMGR_TIMER_HEAP_H
-
-#include "src/core/iomgr/timer.h"
-
-typedef struct {
-  grpc_timer **timers;
-  uint32_t timer_count;
-  uint32_t timer_capacity;
-} grpc_timer_heap;
-
-/* return 1 if the new timer is the first timer in the heap */
-int grpc_timer_heap_add(grpc_timer_heap *heap, grpc_timer *timer);
-
-void grpc_timer_heap_init(grpc_timer_heap *heap);
-void grpc_timer_heap_destroy(grpc_timer_heap *heap);
-
-void grpc_timer_heap_remove(grpc_timer_heap *heap, grpc_timer *timer);
-grpc_timer *grpc_timer_heap_top(grpc_timer_heap *heap);
-void grpc_timer_heap_pop(grpc_timer_heap *heap);
-
-int grpc_timer_heap_is_empty(grpc_timer_heap *heap);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_TIMER_HEAP_H */
diff --git a/src/core/iomgr/udp_server.c b/src/core/iomgr/udp_server.c
deleted file mode 100644
index ef548cf..0000000
--- a/src/core/iomgr/udp_server.c
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GRPC_NEED_UDP
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/iomgr/udp_server.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include "src/core/iomgr/fd_posix.h"
-#include "src/core/iomgr/pollset_posix.h"
-#include "src/core/iomgr/resolve_address.h"
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/iomgr/socket_utils_posix.h"
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/time.h>
-
-#define INIT_PORT_CAP 2
-
-/* one listening port */
-typedef struct {
-  int fd;
-  grpc_fd *emfd;
-  grpc_udp_server *server;
-  union {
-    uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE];
-    struct sockaddr sockaddr;
-    struct sockaddr_un un;
-  } addr;
-  size_t addr_len;
-  grpc_closure read_closure;
-  grpc_closure destroyed_closure;
-  grpc_udp_server_read_cb read_cb;
-} server_port;
-
-static void unlink_if_unix_domain_socket(const struct sockaddr_un *un) {
-  struct stat st;
-
-  if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
-    unlink(un->sun_path);
-  }
-}
-
-/* the overall server */
-struct grpc_udp_server {
-  gpr_mu mu;
-  gpr_cv cv;
-
-  /* active port count: how many ports are actually still listening */
-  size_t active_ports;
-  /* destroyed port count: how many ports are completely destroyed */
-  size_t destroyed_ports;
-
-  /* is this server shutting down? (boolean) */
-  int shutdown;
-
-  /* all listening ports */
-  server_port *ports;
-  size_t nports;
-  size_t port_capacity;
-
-  /* shutdown callback */
-  grpc_closure *shutdown_complete;
-
-  /* all pollsets interested in new connections */
-  grpc_pollset **pollsets;
-  /* number of pollsets in the pollsets array */
-  size_t pollset_count;
-  /* The parent grpc server */
-  grpc_server *grpc_server;
-};
-
-grpc_udp_server *grpc_udp_server_create(void) {
-  grpc_udp_server *s = gpr_malloc(sizeof(grpc_udp_server));
-  gpr_mu_init(&s->mu);
-  gpr_cv_init(&s->cv);
-  s->active_ports = 0;
-  s->destroyed_ports = 0;
-  s->shutdown = 0;
-  s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
-  s->nports = 0;
-  s->port_capacity = INIT_PORT_CAP;
-
-  return s;
-}
-
-static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
-  grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1, NULL);
-
-  gpr_mu_destroy(&s->mu);
-  gpr_cv_destroy(&s->cv);
-
-  gpr_free(s->ports);
-  gpr_free(s);
-}
-
-static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server,
-                           bool success) {
-  grpc_udp_server *s = server;
-  gpr_mu_lock(&s->mu);
-  s->destroyed_ports++;
-  if (s->destroyed_ports == s->nports) {
-    gpr_mu_unlock(&s->mu);
-    finish_shutdown(exec_ctx, s);
-  } else {
-    gpr_mu_unlock(&s->mu);
-  }
-}
-
-/* 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_exec_ctx *exec_ctx, grpc_udp_server *s) {
-  size_t i;
-
-  /* delete ALL the things */
-  gpr_mu_lock(&s->mu);
-
-  if (!s->shutdown) {
-    gpr_mu_unlock(&s->mu);
-    return;
-  }
-
-  if (s->nports) {
-    for (i = 0; i < s->nports; i++) {
-      server_port *sp = &s->ports[i];
-      if (sp->addr.sockaddr.sa_family == AF_UNIX) {
-        unlink_if_unix_domain_socket(&sp->addr.un);
-      }
-      sp->destroyed_closure.cb = destroyed_port;
-      sp->destroyed_closure.cb_arg = s;
-      grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
-                     "udp_listener_shutdown");
-    }
-    gpr_mu_unlock(&s->mu);
-  } else {
-    gpr_mu_unlock(&s->mu);
-    finish_shutdown(exec_ctx, s);
-  }
-}
-
-void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
-                             grpc_closure *on_done) {
-  size_t i;
-  gpr_mu_lock(&s->mu);
-
-  GPR_ASSERT(!s->shutdown);
-  s->shutdown = 1;
-
-  s->shutdown_complete = on_done;
-
-  /* shutdown all fd's */
-  if (s->active_ports) {
-    for (i = 0; i < s->nports; i++) {
-      grpc_fd_shutdown(exec_ctx, s->ports[i].emfd);
-    }
-    gpr_mu_unlock(&s->mu);
-  } else {
-    gpr_mu_unlock(&s->mu);
-    deactivated_all_ports(exec_ctx, s);
-  }
-}
-
-/* Prepare a recently-created socket for listening. */
-static int prepare_socket(int fd, const struct sockaddr *addr,
-                          size_t addr_len) {
-  struct sockaddr_storage sockname_temp;
-  socklen_t sockname_len;
-  int get_local_ip;
-  int rc;
-
-  if (fd < 0) {
-    goto error;
-  }
-
-  if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1)) {
-    gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
-            strerror(errno));
-  }
-
-  get_local_ip = 1;
-  rc = setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip,
-                  sizeof(get_local_ip));
-  if (rc == 0 && addr->sa_family == AF_INET6) {
-#if !defined(__APPLE__)
-    rc = setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip,
-                    sizeof(get_local_ip));
-#endif
-  }
-
-  GPR_ASSERT(addr_len < ~(socklen_t)0);
-  if (bind(fd, addr, (socklen_t)addr_len) < 0) {
-    char *addr_str;
-    grpc_sockaddr_to_string(&addr_str, addr, 0);
-    gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno));
-    gpr_free(addr_str);
-    goto error;
-  }
-
-  sockname_len = sizeof(sockname_temp);
-  if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) {
-    goto error;
-  }
-
-  return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
-
-error:
-  if (fd >= 0) {
-    close(fd);
-  }
-  return -1;
-}
-
-/* event manager callback when reads are ready */
-static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  server_port *sp = arg;
-
-  if (!success) {
-    gpr_mu_lock(&sp->server->mu);
-    if (0 == --sp->server->active_ports) {
-      gpr_mu_unlock(&sp->server->mu);
-      deactivated_all_ports(exec_ctx, sp->server);
-    } else {
-      gpr_mu_unlock(&sp->server->mu);
-    }
-    return;
-  }
-
-  /* Tell the registered callback that data is available to read. */
-  GPR_ASSERT(sp->read_cb);
-  sp->read_cb(exec_ctx, sp->emfd, sp->server->grpc_server);
-
-  /* Re-arm the notification event so we get another chance to read. */
-  grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
-}
-
-static int add_socket_to_server(grpc_udp_server *s, int fd,
-                                const struct sockaddr *addr, size_t addr_len,
-                                grpc_udp_server_read_cb read_cb) {
-  server_port *sp;
-  int port;
-  char *addr_str;
-  char *name;
-
-  port = prepare_socket(fd, addr, addr_len);
-  if (port >= 0) {
-    grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
-    gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
-    gpr_free(addr_str);
-    gpr_mu_lock(&s->mu);
-    /* append it to the list under a lock */
-    if (s->nports == s->port_capacity) {
-      s->port_capacity *= 2;
-      s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
-    }
-    sp = &s->ports[s->nports++];
-    sp->server = s;
-    sp->fd = fd;
-    sp->emfd = grpc_fd_create(fd, name);
-    memcpy(sp->addr.untyped, addr, addr_len);
-    sp->addr_len = addr_len;
-    sp->read_cb = read_cb;
-    GPR_ASSERT(sp->emfd);
-    gpr_mu_unlock(&s->mu);
-    gpr_free(name);
-  }
-
-  return port;
-}
-
-int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr,
-                             size_t addr_len, grpc_udp_server_read_cb read_cb) {
-  int allocated_port1 = -1;
-  int allocated_port2 = -1;
-  unsigned i;
-  int fd;
-  grpc_dualstack_mode dsmode;
-  struct sockaddr_in6 addr6_v4mapped;
-  struct sockaddr_in wild4;
-  struct sockaddr_in6 wild6;
-  struct sockaddr_in addr4_copy;
-  struct sockaddr *allocated_addr = NULL;
-  struct sockaddr_storage sockname_temp;
-  socklen_t sockname_len;
-  int port;
-
-  if (((struct sockaddr *)addr)->sa_family == AF_UNIX) {
-    unlink_if_unix_domain_socket(addr);
-  }
-
-  /* Check if this is a wildcard port, and if so, try to keep the port the same
-     as some previously created listener. */
-  if (grpc_sockaddr_get_port(addr) == 0) {
-    for (i = 0; i < s->nports; i++) {
-      sockname_len = sizeof(sockname_temp);
-      if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp,
-                           &sockname_len)) {
-        port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
-        if (port > 0) {
-          allocated_addr = malloc(addr_len);
-          memcpy(allocated_addr, addr, addr_len);
-          grpc_sockaddr_set_port(allocated_addr, port);
-          addr = allocated_addr;
-          break;
-        }
-      }
-    }
-  }
-
-  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
-    addr = (const struct sockaddr *)&addr6_v4mapped;
-    addr_len = sizeof(addr6_v4mapped);
-  }
-
-  /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
-  if (grpc_sockaddr_is_wildcard(addr, &port)) {
-    grpc_sockaddr_make_wildcards(port, &wild4, &wild6);
-
-    /* Try listening on IPv6 first. */
-    addr = (struct sockaddr *)&wild6;
-    addr_len = sizeof(wild6);
-    fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode);
-    allocated_port1 = add_socket_to_server(s, fd, addr, addr_len, read_cb);
-    if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
-      goto done;
-    }
-
-    /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
-    if (port == 0 && allocated_port1 > 0) {
-      grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1);
-    }
-    addr = (struct sockaddr *)&wild4;
-    addr_len = sizeof(wild4);
-  }
-
-  fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode);
-  if (fd < 0) {
-    gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
-  }
-  if (dsmode == GRPC_DSMODE_IPV4 &&
-      grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
-    addr = (struct sockaddr *)&addr4_copy;
-    addr_len = sizeof(addr4_copy);
-  }
-  allocated_port2 = add_socket_to_server(s, fd, addr, addr_len, read_cb);
-
-done:
-  gpr_free(allocated_addr);
-  return allocated_port1 >= 0 ? allocated_port1 : allocated_port2;
-}
-
-int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned port_index) {
-  return (port_index < s->nports) ? s->ports[port_index].fd : -1;
-}
-
-void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
-                           grpc_pollset **pollsets, size_t pollset_count,
-                           grpc_server *server) {
-  size_t i, j;
-  gpr_mu_lock(&s->mu);
-  GPR_ASSERT(s->active_ports == 0);
-  s->pollsets = pollsets;
-  s->grpc_server = server;
-  for (i = 0; i < s->nports; i++) {
-    for (j = 0; j < pollset_count; j++) {
-      grpc_pollset_add_fd(exec_ctx, pollsets[j], s->ports[i].emfd);
-    }
-    s->ports[i].read_closure.cb = on_read;
-    s->ports[i].read_closure.cb_arg = &s->ports[i];
-    grpc_fd_notify_on_read(exec_ctx, s->ports[i].emfd,
-                           &s->ports[i].read_closure);
-    s->active_ports++;
-  }
-  gpr_mu_unlock(&s->mu);
-}
-
-#endif
-#endif
diff --git a/src/core/iomgr/udp_server.h b/src/core/iomgr/udp_server.h
deleted file mode 100644
index a9d0489..0000000
--- a/src/core/iomgr/udp_server.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H
-#define GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H
-
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/iomgr/fd_posix.h"
-
-/* Forward decl of grpc_server */
-typedef struct grpc_server grpc_server;
-
-/* Forward decl of grpc_udp_server */
-typedef struct grpc_udp_server grpc_udp_server;
-
-/* Called when data is available to read from the socket. */
-typedef void (*grpc_udp_server_read_cb)(grpc_exec_ctx *exec_ctx, grpc_fd *emfd,
-                                        grpc_server *server);
-
-/* Create a server, initially not bound to any ports */
-grpc_udp_server *grpc_udp_server_create(void);
-
-/* Start listening to bound ports */
-void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *udp_server,
-                           grpc_pollset **pollsets, size_t pollset_count,
-                           grpc_server *server);
-
-int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned index);
-
-/* Add a port to the server, returning port number on success, or negative
-   on failure.
-
-   The :: and 0.0.0.0 wildcard addresses are treated identically, accepting
-   both IPv4 and IPv6 connections, but :: is the preferred style.  This usually
-   creates one socket, but possibly two on systems which support IPv6,
-   but not dualstack sockets. */
-
-/* TODO(ctiller): deprecate this, and make grpc_udp_server_add_ports to handle
-                  all of the multiple socket port matching logic in one place */
-int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr,
-                             size_t addr_len, grpc_udp_server_read_cb read_cb);
-
-void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *server,
-                             grpc_closure *on_done);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H */
diff --git a/src/core/iomgr/wakeup_fd_eventfd.c b/src/core/iomgr/wakeup_fd_eventfd.c
deleted file mode 100644
index f67379e..0000000
--- a/src/core/iomgr/wakeup_fd_eventfd.c
+++ /dev/null
@@ -1,85 +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/support/port_platform.h>
-
-#ifdef GPR_LINUX_EVENTFD
-
-#include <errno.h>
-#include <sys/eventfd.h>
-#include <unistd.h>
-
-#include <grpc/support/log.h>
-
-#include "src/core/iomgr/wakeup_fd_posix.h"
-#include "src/core/profiling/timers.h"
-
-static void eventfd_create(grpc_wakeup_fd* fd_info) {
-  int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
-  /* TODO(klempner): Handle failure more gracefully */
-  GPR_ASSERT(efd >= 0);
-  fd_info->read_fd = efd;
-  fd_info->write_fd = -1;
-}
-
-static void eventfd_consume(grpc_wakeup_fd* fd_info) {
-  eventfd_t value;
-  int err;
-  do {
-    err = eventfd_read(fd_info->read_fd, &value);
-  } while (err < 0 && errno == EINTR);
-}
-
-static void eventfd_wakeup(grpc_wakeup_fd* fd_info) {
-  int err;
-  GPR_TIMER_BEGIN("eventfd_wakeup", 0);
-  do {
-    err = eventfd_write(fd_info->read_fd, 1);
-  } while (err < 0 && errno == EINTR);
-  GPR_TIMER_END("eventfd_wakeup", 0);
-}
-
-static void eventfd_destroy(grpc_wakeup_fd* fd_info) {
-  if (fd_info->read_fd != 0) close(fd_info->read_fd);
-}
-
-static int eventfd_check_availability(void) {
-  /* TODO(klempner): Actually check if eventfd is available */
-  return 1;
-}
-
-const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = {
-    eventfd_create, eventfd_consume, eventfd_wakeup, eventfd_destroy,
-    eventfd_check_availability};
-
-#endif /* GPR_LINUX_EVENTFD */
diff --git a/src/core/iomgr/wakeup_fd_nospecial.c b/src/core/iomgr/wakeup_fd_nospecial.c
deleted file mode 100644
index 78d763c..0000000
--- a/src/core/iomgr/wakeup_fd_nospecial.c
+++ /dev/null
@@ -1,51 +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.
- *
- */
-
-/*
- * This is a dummy file to provide an invalid specialized_wakeup_fd_vtable on
- * systems without anything better than pipe.
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_NO_SPECIAL_WAKEUP_FD
-
-#include "src/core/iomgr/wakeup_fd_posix.h"
-#include <stddef.h>
-
-static int check_availability_invalid(void) { return 0; }
-
-const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = {
-    NULL, NULL, NULL, NULL, check_availability_invalid};
-
-#endif /* GPR_POSIX_NO_SPECIAL_WAKEUP_FD */
diff --git a/src/core/iomgr/wakeup_fd_pipe.c b/src/core/iomgr/wakeup_fd_pipe.c
deleted file mode 100644
index 80de181..0000000
--- a/src/core/iomgr/wakeup_fd_pipe.c
+++ /dev/null
@@ -1,97 +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/support/port_platform.h>
-
-#ifdef GPR_POSIX_WAKEUP_FD
-
-#include "src/core/iomgr/wakeup_fd_posix.h"
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "src/core/iomgr/socket_utils_posix.h"
-#include <grpc/support/log.h>
-
-static void pipe_init(grpc_wakeup_fd* fd_info) {
-  int pipefd[2];
-  /* TODO(klempner): Make this nonfatal */
-  GPR_ASSERT(0 == pipe(pipefd));
-  GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[0], 1));
-  GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[1], 1));
-  fd_info->read_fd = pipefd[0];
-  fd_info->write_fd = pipefd[1];
-}
-
-static void pipe_consume(grpc_wakeup_fd* fd_info) {
-  char buf[128];
-  ssize_t r;
-
-  for (;;) {
-    r = read(fd_info->read_fd, buf, sizeof(buf));
-    if (r > 0) continue;
-    if (r == 0) return;
-    switch (errno) {
-      case EAGAIN:
-        return;
-      case EINTR:
-        continue;
-      default:
-        gpr_log(GPR_ERROR, "error reading pipe: %s", strerror(errno));
-        return;
-    }
-  }
-}
-
-static void pipe_wakeup(grpc_wakeup_fd* fd_info) {
-  char c = 0;
-  while (write(fd_info->write_fd, &c, 1) != 1 && errno == EINTR)
-    ;
-}
-
-static void pipe_destroy(grpc_wakeup_fd* fd_info) {
-  if (fd_info->read_fd != 0) close(fd_info->read_fd);
-  if (fd_info->write_fd != 0) close(fd_info->write_fd);
-}
-
-static int pipe_check_availability(void) {
-  /* Assume that pipes are always available. */
-  return 1;
-}
-
-const grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable = {
-    pipe_init, pipe_consume, pipe_wakeup, pipe_destroy,
-    pipe_check_availability};
-
-#endif /* GPR_POSIX_WAKUP_FD */
diff --git a/src/core/iomgr/wakeup_fd_pipe.h b/src/core/iomgr/wakeup_fd_pipe.h
deleted file mode 100644
index 01a13a9..0000000
--- a/src/core/iomgr/wakeup_fd_pipe.h
+++ /dev/null
@@ -1,41 +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_WAKEUP_FD_PIPE_H
-#define GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_PIPE_H
-
-#include "src/core/iomgr/wakeup_fd_posix.h"
-
-extern grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable;
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_PIPE_H */
diff --git a/src/core/iomgr/wakeup_fd_posix.c b/src/core/iomgr/wakeup_fd_posix.c
deleted file mode 100644
index f40be08..0000000
--- a/src/core/iomgr/wakeup_fd_posix.c
+++ /dev/null
@@ -1,72 +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/support/port_platform.h>
-
-#ifdef GPR_POSIX_WAKEUP_FD
-
-#include "src/core/iomgr/wakeup_fd_posix.h"
-#include "src/core/iomgr/wakeup_fd_pipe.h"
-#include <stddef.h>
-
-static const grpc_wakeup_fd_vtable *wakeup_fd_vtable = NULL;
-int grpc_allow_specialized_wakeup_fd = 1;
-
-void grpc_wakeup_fd_global_init(void) {
-  if (grpc_allow_specialized_wakeup_fd &&
-      grpc_specialized_wakeup_fd_vtable.check_availability()) {
-    wakeup_fd_vtable = &grpc_specialized_wakeup_fd_vtable;
-  } else {
-    wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable;
-  }
-}
-
-void grpc_wakeup_fd_global_destroy(void) { wakeup_fd_vtable = NULL; }
-
-void grpc_wakeup_fd_init(grpc_wakeup_fd *fd_info) {
-  wakeup_fd_vtable->init(fd_info);
-}
-
-void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd *fd_info) {
-  wakeup_fd_vtable->consume(fd_info);
-}
-
-void grpc_wakeup_fd_wakeup(grpc_wakeup_fd *fd_info) {
-  wakeup_fd_vtable->wakeup(fd_info);
-}
-
-void grpc_wakeup_fd_destroy(grpc_wakeup_fd *fd_info) {
-  wakeup_fd_vtable->destroy(fd_info);
-}
-
-#endif /* GPR_POSIX_WAKEUP_FD */
diff --git a/src/core/iomgr/wakeup_fd_posix.h b/src/core/iomgr/wakeup_fd_posix.h
deleted file mode 100644
index ffd60d1..0000000
--- a/src/core/iomgr/wakeup_fd_posix.h
+++ /dev/null
@@ -1,101 +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.
- *
- */
-
-/*
- * wakeup_fd abstracts the concept of a file descriptor for the purpose of
- * waking up a thread in select()/poll()/epoll_wait()/etc.
-
- * The poll() family of system calls provide a way for a thread to block until
- * there is activity on one (or more) of a set of file descriptors. An
- * application may wish to wake up this thread to do non file related work. The
- * typical way to do this is to add a pipe to the set of file descriptors, then
- * write to the pipe to wake up the thread in poll().
- *
- * Linux has a lighter weight eventfd specifically designed for this purpose.
- * wakeup_fd abstracts the difference between the two.
- *
- * Setup:
- * 1. Before calling anything, call global_init() at least once.
- * 1. Call grpc_wakeup_fd_create() to get a wakeup_fd.
- * 2. Add the result of GRPC_WAKEUP_FD_FD to the set of monitored file
- *    descriptors for the poll() style API you are using. Monitor the file
- *    descriptor for readability.
- * 3. To tear down, call grpc_wakeup_fd_destroy(). This closes the underlying
- *    file descriptor.
- *
- * Usage:
- * 1. To wake up a polling thread, call grpc_wakeup_fd_wakeup() on a wakeup_fd
- *    it is monitoring.
- * 2. If the polling thread was awakened by a wakeup_fd event, call
- *    grpc_wakeup_fd_consume_wakeup() on it.
- */
-#ifndef GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_POSIX_H
-#define GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_POSIX_H
-
-void grpc_wakeup_fd_global_init(void);
-void grpc_wakeup_fd_global_destroy(void);
-
-/* Force using the fallback implementation. This is intended for testing
- * purposes only.*/
-void grpc_wakeup_fd_global_init_force_fallback(void);
-
-typedef struct grpc_wakeup_fd grpc_wakeup_fd;
-
-typedef struct grpc_wakeup_fd_vtable {
-  void (*init)(grpc_wakeup_fd* fd_info);
-  void (*consume)(grpc_wakeup_fd* fd_info);
-  void (*wakeup)(grpc_wakeup_fd* fd_info);
-  void (*destroy)(grpc_wakeup_fd* fd_info);
-  /* Must be called before calling any other functions */
-  int (*check_availability)(void);
-} grpc_wakeup_fd_vtable;
-
-struct grpc_wakeup_fd {
-  int read_fd;
-  int write_fd;
-};
-
-extern int grpc_allow_specialized_wakeup_fd;
-
-#define GRPC_WAKEUP_FD_GET_READ_FD(fd_info) ((fd_info)->read_fd)
-
-void grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info);
-void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info);
-void grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info);
-void grpc_wakeup_fd_destroy(grpc_wakeup_fd* fd_info);
-
-/* Defined in some specialized implementation's .c file, or by
- * wakeup_fd_nospecial.c if no such implementation exists. */
-extern const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable;
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_WAKEUP_FD_POSIX_H */
diff --git a/src/core/iomgr/workqueue.h b/src/core/iomgr/workqueue.h
deleted file mode 100644
index 36dd133..0000000
--- a/src/core/iomgr/workqueue.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_WORKQUEUE_H
-#define GRPC_INTERNAL_CORE_IOMGR_WORKQUEUE_H
-
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/iomgr/pollset.h"
-#include "src/core/iomgr/closure.h"
-#include "src/core/iomgr/exec_ctx.h"
-
-#ifdef GPR_POSIX_SOCKET
-#include "src/core/iomgr/workqueue_posix.h"
-#endif
-
-#ifdef GPR_WIN32
-#include "src/core/iomgr/workqueue_windows.h"
-#endif
-
-/* grpc_workqueue is forward declared in exec_ctx.h */
-
-/** Create a work queue */
-grpc_workqueue *grpc_workqueue_create(grpc_exec_ctx *exec_ctx);
-
-void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
-
-#define GRPC_WORKQUEUE_REFCOUNT_DEBUG
-#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
-#define GRPC_WORKQUEUE_REF(p, r) \
-  grpc_workqueue_ref((p), __FILE__, __LINE__, (r))
-#define GRPC_WORKQUEUE_UNREF(cl, p, r) \
-  grpc_workqueue_unref((cl), (p), __FILE__, __LINE__, (r))
-void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
-                        const char *reason);
-void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
-                          const char *file, int line, const char *reason);
-#else
-#define GRPC_WORKQUEUE_REF(p, r) grpc_workqueue_ref((p))
-#define GRPC_WORKQUEUE_UNREF(cl, p, r) grpc_workqueue_unref((cl), (p))
-void grpc_workqueue_ref(grpc_workqueue *workqueue);
-void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
-#endif
-
-/** Bind this workqueue to a pollset */
-void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx,
-                                   grpc_workqueue *workqueue,
-                                   grpc_pollset *pollset);
-
-/** Add a work item to a workqueue */
-void grpc_workqueue_push(grpc_workqueue *workqueue, grpc_closure *closure,
-                         int success);
-
-#endif
diff --git a/src/core/iomgr/workqueue_posix.c b/src/core/iomgr/workqueue_posix.c
deleted file mode 100644
index c096dbf..0000000
--- a/src/core/iomgr/workqueue_posix.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SOCKET
-
-#include "src/core/iomgr/workqueue.h"
-
-#include <stdio.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/iomgr/fd_posix.h"
-#include "src/core/iomgr/pollset_posix.h"
-
-static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success);
-
-grpc_workqueue *grpc_workqueue_create(grpc_exec_ctx *exec_ctx) {
-  char name[32];
-  grpc_workqueue *workqueue = gpr_malloc(sizeof(grpc_workqueue));
-  gpr_ref_init(&workqueue->refs, 1);
-  gpr_mu_init(&workqueue->mu);
-  workqueue->closure_list.head = workqueue->closure_list.tail = NULL;
-  grpc_wakeup_fd_init(&workqueue->wakeup_fd);
-  sprintf(name, "workqueue:%p", (void *)workqueue);
-  workqueue->wakeup_read_fd =
-      grpc_fd_create(GRPC_WAKEUP_FD_GET_READ_FD(&workqueue->wakeup_fd), name);
-  grpc_closure_init(&workqueue->read_closure, on_readable, workqueue);
-  grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd,
-                         &workqueue->read_closure);
-  return workqueue;
-}
-
-static void workqueue_destroy(grpc_exec_ctx *exec_ctx,
-                              grpc_workqueue *workqueue) {
-  GPR_ASSERT(grpc_closure_list_empty(workqueue->closure_list));
-  grpc_fd_shutdown(exec_ctx, workqueue->wakeup_read_fd);
-}
-
-#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
-void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
-                        const char *reason) {
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p   ref %d -> %d %s",
-          workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count + 1,
-          reason);
-#else
-void grpc_workqueue_ref(grpc_workqueue *workqueue) {
-#endif
-  gpr_ref(&workqueue->refs);
-}
-
-#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
-void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
-                          const char *file, int line, const char *reason) {
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p unref %d -> %d %s",
-          workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count - 1,
-          reason);
-#else
-void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
-#endif
-  if (gpr_unref(&workqueue->refs)) {
-    workqueue_destroy(exec_ctx, workqueue);
-  }
-}
-
-void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx,
-                                   grpc_workqueue *workqueue,
-                                   grpc_pollset *pollset) {
-  grpc_pollset_add_fd(exec_ctx, pollset, workqueue->wakeup_read_fd);
-}
-
-void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
-  gpr_mu_lock(&workqueue->mu);
-  if (grpc_closure_list_empty(workqueue->closure_list)) {
-    grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd);
-  }
-  grpc_closure_list_move(&exec_ctx->closure_list, &workqueue->closure_list);
-  gpr_mu_unlock(&workqueue->mu);
-}
-
-static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  grpc_workqueue *workqueue = arg;
-
-  if (!success) {
-    gpr_mu_destroy(&workqueue->mu);
-    /* HACK: let wakeup_fd code know that we stole the fd */
-    workqueue->wakeup_fd.read_fd = 0;
-    grpc_wakeup_fd_destroy(&workqueue->wakeup_fd);
-    grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, NULL, "destroy");
-    gpr_free(workqueue);
-  } else {
-    gpr_mu_lock(&workqueue->mu);
-    grpc_closure_list_move(&workqueue->closure_list, &exec_ctx->closure_list);
-    grpc_wakeup_fd_consume_wakeup(&workqueue->wakeup_fd);
-    gpr_mu_unlock(&workqueue->mu);
-    grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd,
-                           &workqueue->read_closure);
-  }
-}
-
-void grpc_workqueue_push(grpc_workqueue *workqueue, grpc_closure *closure,
-                         int success) {
-  gpr_mu_lock(&workqueue->mu);
-  if (grpc_closure_list_empty(workqueue->closure_list)) {
-    grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd);
-  }
-  grpc_closure_list_add(&workqueue->closure_list, closure, success);
-  gpr_mu_unlock(&workqueue->mu);
-}
-
-#endif /* GPR_POSIX_SOCKET */
diff --git a/src/core/iomgr/workqueue_posix.h b/src/core/iomgr/workqueue_posix.h
deleted file mode 100644
index 68f195e..0000000
--- a/src/core/iomgr/workqueue_posix.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_WORKQUEUE_POSIX_H
-#define GRPC_INTERNAL_CORE_IOMGR_WORKQUEUE_POSIX_H
-
-#include "src/core/iomgr/wakeup_fd_posix.h"
-
-struct grpc_fd;
-
-struct grpc_workqueue {
-  gpr_refcount refs;
-
-  gpr_mu mu;
-  grpc_closure_list closure_list;
-
-  grpc_wakeup_fd wakeup_fd;
-  struct grpc_fd *wakeup_read_fd;
-
-  grpc_closure read_closure;
-};
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_WORKQUEUE_POSIX_H */
diff --git a/src/core/iomgr/workqueue_windows.c b/src/core/iomgr/workqueue_windows.c
deleted file mode 100644
index f9ca575..0000000
--- a/src/core/iomgr/workqueue_windows.c
+++ /dev/null
@@ -1,40 +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/support/port_platform.h>
-
-#ifdef GPR_WIN32
-
-#include "src/core/iomgr/workqueue.h"
-
-#endif /* GPR_WIN32 */
diff --git a/src/core/iomgr/workqueue_windows.h b/src/core/iomgr/workqueue_windows.h
deleted file mode 100644
index 941f195..0000000
--- a/src/core/iomgr/workqueue_windows.h
+++ /dev/null
@@ -1,37 +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_WORKQUEUE_WINDOWS_H
-#define GRPC_INTERNAL_CORE_IOMGR_WORKQUEUE_WINDOWS_H
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_WORKQUEUE_WINDOWS_H */
diff --git a/src/core/json/json.c b/src/core/json/json.c
deleted file mode 100644
index 96e11ee..0000000
--- a/src/core/json/json.c
+++ /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 <string.h>
-
-#include <grpc/support/alloc.h>
-
-#include "src/core/json/json.h"
-
-grpc_json *grpc_json_create(grpc_json_type type) {
-  grpc_json *json = gpr_malloc(sizeof(*json));
-  memset(json, 0, sizeof(*json));
-  json->type = type;
-
-  return json;
-}
-
-void grpc_json_destroy(grpc_json *json) {
-  while (json->child) {
-    grpc_json_destroy(json->child);
-  }
-
-  if (json->next) {
-    json->next->prev = json->prev;
-  }
-
-  if (json->prev) {
-    json->prev->next = json->next;
-  } else if (json->parent) {
-    json->parent->child = json->next;
-  }
-
-  gpr_free(json);
-}
diff --git a/src/core/json/json.h b/src/core/json/json.h
deleted file mode 100644
index c4df299..0000000
--- a/src/core/json/json.h
+++ /dev/null
@@ -1,88 +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_JSON_JSON_H
-#define GRPC_INTERNAL_CORE_JSON_JSON_H
-
-#include <stdlib.h>
-
-#include "src/core/json/json_common.h"
-
-/* A tree-like structure to hold json values. The key and value pointers
- * are not owned by it.
- */
-typedef struct grpc_json {
-  struct grpc_json *next;
-  struct grpc_json *prev;
-  struct grpc_json *child;
-  struct grpc_json *parent;
-
-  grpc_json_type type;
-  const char *key;
-  const char *value;
-} grpc_json;
-
-/* The next two functions are going to parse the input string, and
- * 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 objects will be strings
- * pointing at your input buffer.
- *
- * Delete the allocated tree afterward using grpc_json_destroy().
- */
-grpc_json *grpc_json_parse_string_with_len(char *input, size_t size);
-grpc_json *grpc_json_parse_string(char *input);
-
-/* This function will create a new string using gpr_realloc, and will
- * deserialize the grpc_json tree into it. It'll be zero-terminated,
- * but will be allocated in chunks of 256 bytes.
- *
- * The indent parameter controls the way the output is formatted.
- * If indent is 0, then newlines will be suppressed as well, and the
- * output will be condensed at its maximum.
- */
-char *grpc_json_dump_to_string(grpc_json *json, int indent);
-
-/* Use these to create or delete a grpc_json object.
- * Deletion is recursive. We will not attempt to free any of the strings
- * in any of the objects of that tree.
- */
-grpc_json *grpc_json_create(grpc_json_type type);
-void grpc_json_destroy(grpc_json *json);
-
-#endif /* GRPC_INTERNAL_CORE_JSON_JSON_H */
diff --git a/src/core/json/json_common.h b/src/core/json/json_common.h
deleted file mode 100644
index 481695b..0000000
--- a/src/core/json/json_common.h
+++ /dev/null
@@ -1,49 +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_JSON_JSON_COMMON_H
-#define GRPC_INTERNAL_CORE_JSON_JSON_COMMON_H
-
-/* The various json types. */
-typedef enum {
-  GRPC_JSON_OBJECT,
-  GRPC_JSON_ARRAY,
-  GRPC_JSON_STRING,
-  GRPC_JSON_NUMBER,
-  GRPC_JSON_TRUE,
-  GRPC_JSON_FALSE,
-  GRPC_JSON_NULL,
-  GRPC_JSON_TOP_LEVEL
-} grpc_json_type;
-
-#endif /* GRPC_INTERNAL_CORE_JSON_JSON_COMMON_H */
diff --git a/src/core/json/json_reader.c b/src/core/json/json_reader.c
deleted file mode 100644
index 30da6f2..0000000
--- a/src/core/json/json_reader.c
+++ /dev/null
@@ -1,659 +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 <string.h>
-
-#include <grpc/support/port_platform.h>
-
-#include <grpc/support/log.h>
-
-#include "src/core/json/json_reader.h"
-
-static void json_reader_string_clear(grpc_json_reader *reader) {
-  reader->vtable->string_clear(reader->userdata);
-}
-
-static void json_reader_string_add_char(grpc_json_reader *reader, uint32_t c) {
-  reader->vtable->string_add_char(reader->userdata, c);
-}
-
-static void json_reader_string_add_utf32(grpc_json_reader *reader,
-                                         uint32_t utf32) {
-  reader->vtable->string_add_utf32(reader->userdata, utf32);
-}
-
-static uint32_t grpc_json_reader_read_char(grpc_json_reader *reader) {
-  return reader->vtable->read_char(reader->userdata);
-}
-
-static void json_reader_container_begins(grpc_json_reader *reader,
-                                         grpc_json_type type) {
-  reader->vtable->container_begins(reader->userdata, type);
-}
-
-static grpc_json_type grpc_json_reader_container_ends(
-    grpc_json_reader *reader) {
-  return reader->vtable->container_ends(reader->userdata);
-}
-
-static void json_reader_set_key(grpc_json_reader *reader) {
-  reader->vtable->set_key(reader->userdata);
-}
-
-static void json_reader_set_string(grpc_json_reader *reader) {
-  reader->vtable->set_string(reader->userdata);
-}
-
-static int json_reader_set_number(grpc_json_reader *reader) {
-  return reader->vtable->set_number(reader->userdata);
-}
-
-static void json_reader_set_true(grpc_json_reader *reader) {
-  reader->vtable->set_true(reader->userdata);
-}
-
-static void json_reader_set_false(grpc_json_reader *reader) {
-  reader->vtable->set_false(reader->userdata);
-}
-
-static void json_reader_set_null(grpc_json_reader *reader) {
-  reader->vtable->set_null(reader->userdata);
-}
-
-/* Call this function to initialize the reader structure. */
-void grpc_json_reader_init(grpc_json_reader *reader,
-                           grpc_json_reader_vtable *vtable, void *userdata) {
-  memset(reader, 0, sizeof(*reader));
-  reader->vtable = vtable;
-  reader->userdata = userdata;
-  json_reader_string_clear(reader);
-  reader->state = GRPC_JSON_STATE_VALUE_BEGIN;
-}
-
-int grpc_json_reader_is_complete(grpc_json_reader *reader) {
-  return ((reader->depth == 0) &&
-          ((reader->state == GRPC_JSON_STATE_END) ||
-           (reader->state == GRPC_JSON_STATE_VALUE_END)));
-}
-
-grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader) {
-  uint32_t c, success;
-
-  /* This state-machine is a strict implementation of ECMA-404 */
-  for (;;) {
-    c = grpc_json_reader_read_char(reader);
-    switch (c) {
-      /* Let's process the error cases first. */
-      case GRPC_JSON_READ_CHAR_ERROR:
-        return GRPC_JSON_READ_ERROR;
-
-      case GRPC_JSON_READ_CHAR_EAGAIN:
-        return GRPC_JSON_EAGAIN;
-
-      case GRPC_JSON_READ_CHAR_EOF:
-        if (grpc_json_reader_is_complete(reader)) {
-          return GRPC_JSON_DONE;
-        } else {
-          return GRPC_JSON_PARSE_ERROR;
-        }
-        break;
-
-      /* Processing whitespaces. */
-      case ' ':
-      case '\t':
-      case '\n':
-      case '\r':
-        switch (reader->state) {
-          case GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
-          case GRPC_JSON_STATE_OBJECT_KEY_END:
-          case GRPC_JSON_STATE_VALUE_BEGIN:
-          case GRPC_JSON_STATE_VALUE_END:
-          case GRPC_JSON_STATE_END:
-            break;
-
-          case GRPC_JSON_STATE_OBJECT_KEY_STRING:
-          case GRPC_JSON_STATE_VALUE_STRING:
-            if (c != ' ') return GRPC_JSON_PARSE_ERROR;
-            if (reader->unicode_high_surrogate != 0)
-              return GRPC_JSON_PARSE_ERROR;
-            json_reader_string_add_char(reader, c);
-            break;
-
-          case GRPC_JSON_STATE_VALUE_NUMBER:
-          case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
-          case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
-          case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
-            success = (uint32_t)json_reader_set_number(reader);
-            if (!success) return GRPC_JSON_PARSE_ERROR;
-            json_reader_string_clear(reader);
-            reader->state = GRPC_JSON_STATE_VALUE_END;
-            break;
-
-          default:
-            return GRPC_JSON_PARSE_ERROR;
-        }
-        break;
-
-      /* Value, object or array terminations. */
-      case ',':
-      case '}':
-      case ']':
-        switch (reader->state) {
-          case GRPC_JSON_STATE_OBJECT_KEY_STRING:
-          case GRPC_JSON_STATE_VALUE_STRING:
-            if (reader->unicode_high_surrogate != 0)
-              return GRPC_JSON_PARSE_ERROR;
-            json_reader_string_add_char(reader, c);
-            break;
-
-          case GRPC_JSON_STATE_VALUE_NUMBER:
-          case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
-          case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
-          case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
-            success = (uint32_t)json_reader_set_number(reader);
-            if (!success) return GRPC_JSON_PARSE_ERROR;
-            json_reader_string_clear(reader);
-            reader->state = GRPC_JSON_STATE_VALUE_END;
-          /* The missing break here is intentional. */
-
-          case GRPC_JSON_STATE_VALUE_END:
-          case GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
-          case GRPC_JSON_STATE_VALUE_BEGIN:
-            if (c == ',') {
-              if (reader->state != GRPC_JSON_STATE_VALUE_END) {
-                return GRPC_JSON_PARSE_ERROR;
-              }
-              if (reader->in_object) {
-                reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN;
-              } else {
-                reader->state = GRPC_JSON_STATE_VALUE_BEGIN;
-              }
-            } else {
-              if (reader->depth-- == 0) return GRPC_JSON_PARSE_ERROR;
-              if ((c == '}') && !reader->in_object) {
-                return GRPC_JSON_PARSE_ERROR;
-              }
-              if ((c == '}') &&
-                  (reader->state == GRPC_JSON_STATE_OBJECT_KEY_BEGIN) &&
-                  !reader->container_just_begun) {
-                return GRPC_JSON_PARSE_ERROR;
-              }
-              if ((c == ']') && !reader->in_array) return GRPC_JSON_PARSE_ERROR;
-              if ((c == ']') &&
-                  (reader->state == GRPC_JSON_STATE_VALUE_BEGIN) &&
-                  !reader->container_just_begun) {
-                return GRPC_JSON_PARSE_ERROR;
-              }
-              reader->state = GRPC_JSON_STATE_VALUE_END;
-              switch (grpc_json_reader_container_ends(reader)) {
-                case GRPC_JSON_OBJECT:
-                  reader->in_object = 1;
-                  reader->in_array = 0;
-                  break;
-                case GRPC_JSON_ARRAY:
-                  reader->in_object = 0;
-                  reader->in_array = 1;
-                  break;
-                case GRPC_JSON_TOP_LEVEL:
-                  GPR_ASSERT(reader->depth == 0);
-                  reader->in_object = 0;
-                  reader->in_array = 0;
-                  reader->state = GRPC_JSON_STATE_END;
-                  break;
-                default:
-                  GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR);
-              }
-            }
-            break;
-
-          default:
-            return GRPC_JSON_PARSE_ERROR;
-        }
-        break;
-
-      /* In-string escaping. */
-      case '\\':
-        switch (reader->state) {
-          case GRPC_JSON_STATE_OBJECT_KEY_STRING:
-            reader->escaped_string_was_key = 1;
-            reader->state = GRPC_JSON_STATE_STRING_ESCAPE;
-            break;
-
-          case GRPC_JSON_STATE_VALUE_STRING:
-            reader->escaped_string_was_key = 0;
-            reader->state = GRPC_JSON_STATE_STRING_ESCAPE;
-            break;
-
-          /* This is the \\ case. */
-          case GRPC_JSON_STATE_STRING_ESCAPE:
-            if (reader->unicode_high_surrogate != 0)
-              return GRPC_JSON_PARSE_ERROR;
-            json_reader_string_add_char(reader, '\\');
-            if (reader->escaped_string_was_key) {
-              reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
-            } else {
-              reader->state = GRPC_JSON_STATE_VALUE_STRING;
-            }
-            break;
-
-          default:
-            return GRPC_JSON_PARSE_ERROR;
-        }
-        break;
-
-      default:
-        reader->container_just_begun = 0;
-        switch (reader->state) {
-          case GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
-            if (c != '"') return GRPC_JSON_PARSE_ERROR;
-            reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
-            break;
-
-          case GRPC_JSON_STATE_OBJECT_KEY_STRING:
-            GPR_ASSERT(reader->unicode_high_surrogate == 0);
-            if (c == '"') {
-              reader->state = GRPC_JSON_STATE_OBJECT_KEY_END;
-              json_reader_set_key(reader);
-              json_reader_string_clear(reader);
-            } else {
-              if (c <= 0x001f) return GRPC_JSON_PARSE_ERROR;
-              json_reader_string_add_char(reader, c);
-            }
-            break;
-
-          case GRPC_JSON_STATE_VALUE_STRING:
-            if (reader->unicode_high_surrogate != 0)
-              return GRPC_JSON_PARSE_ERROR;
-            if (c == '"') {
-              reader->state = GRPC_JSON_STATE_VALUE_END;
-              json_reader_set_string(reader);
-              json_reader_string_clear(reader);
-            } else {
-              if (c < 32) return GRPC_JSON_PARSE_ERROR;
-              json_reader_string_add_char(reader, c);
-            }
-            break;
-
-          case GRPC_JSON_STATE_OBJECT_KEY_END:
-            if (c != ':') return GRPC_JSON_PARSE_ERROR;
-            reader->state = GRPC_JSON_STATE_VALUE_BEGIN;
-            break;
-
-          case GRPC_JSON_STATE_VALUE_BEGIN:
-            switch (c) {
-              case 't':
-                reader->state = GRPC_JSON_STATE_VALUE_TRUE_R;
-                break;
-
-              case 'f':
-                reader->state = GRPC_JSON_STATE_VALUE_FALSE_A;
-                break;
-
-              case 'n':
-                reader->state = GRPC_JSON_STATE_VALUE_NULL_U;
-                break;
-
-              case '"':
-                reader->state = GRPC_JSON_STATE_VALUE_STRING;
-                break;
-
-              case '0':
-                json_reader_string_add_char(reader, c);
-                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_ZERO;
-                break;
-
-              case '1':
-              case '2':
-              case '3':
-              case '4':
-              case '5':
-              case '6':
-              case '7':
-              case '8':
-              case '9':
-              case '-':
-                json_reader_string_add_char(reader, c);
-                reader->state = GRPC_JSON_STATE_VALUE_NUMBER;
-                break;
-
-              case '{':
-                reader->container_just_begun = 1;
-                json_reader_container_begins(reader, GRPC_JSON_OBJECT);
-                reader->depth++;
-                reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN;
-                reader->in_object = 1;
-                reader->in_array = 0;
-                break;
-
-              case '[':
-                reader->container_just_begun = 1;
-                json_reader_container_begins(reader, GRPC_JSON_ARRAY);
-                reader->depth++;
-                reader->in_object = 0;
-                reader->in_array = 1;
-                break;
-            }
-            break;
-
-          case GRPC_JSON_STATE_STRING_ESCAPE:
-            if (reader->escaped_string_was_key) {
-              reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
-            } else {
-              reader->state = GRPC_JSON_STATE_VALUE_STRING;
-            }
-            if (reader->unicode_high_surrogate && c != 'u')
-              return GRPC_JSON_PARSE_ERROR;
-            switch (c) {
-              case '"':
-              case '/':
-                json_reader_string_add_char(reader, c);
-                break;
-              case 'b':
-                json_reader_string_add_char(reader, '\b');
-                break;
-              case 'f':
-                json_reader_string_add_char(reader, '\f');
-                break;
-              case 'n':
-                json_reader_string_add_char(reader, '\n');
-                break;
-              case 'r':
-                json_reader_string_add_char(reader, '\r');
-                break;
-              case 't':
-                json_reader_string_add_char(reader, '\t');
-                break;
-              case 'u':
-                reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U1;
-                reader->unicode_char = 0;
-                break;
-              default:
-                return GRPC_JSON_PARSE_ERROR;
-            }
-            break;
-
-          case GRPC_JSON_STATE_STRING_ESCAPE_U1:
-          case GRPC_JSON_STATE_STRING_ESCAPE_U2:
-          case GRPC_JSON_STATE_STRING_ESCAPE_U3:
-          case GRPC_JSON_STATE_STRING_ESCAPE_U4:
-            if ((c >= '0') && (c <= '9')) {
-              c -= '0';
-            } else if ((c >= 'A') && (c <= 'F')) {
-              c -= 'A' - 10;
-            } else if ((c >= 'a') && (c <= 'f')) {
-              c -= 'a' - 10;
-            } else {
-              return GRPC_JSON_PARSE_ERROR;
-            }
-            reader->unicode_char = (uint16_t)(reader->unicode_char << 4);
-            reader->unicode_char = (uint16_t)(reader->unicode_char | c);
-
-            switch (reader->state) {
-              case GRPC_JSON_STATE_STRING_ESCAPE_U1:
-                reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U2;
-                break;
-              case GRPC_JSON_STATE_STRING_ESCAPE_U2:
-                reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U3;
-                break;
-              case GRPC_JSON_STATE_STRING_ESCAPE_U3:
-                reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U4;
-                break;
-              case GRPC_JSON_STATE_STRING_ESCAPE_U4:
-                /* See grpc_json_writer_escape_string to have a description
-                 * of what's going on here.
-                 */
-                if ((reader->unicode_char & 0xfc00) == 0xd800) {
-                  /* high surrogate utf-16 */
-                  if (reader->unicode_high_surrogate != 0)
-                    return GRPC_JSON_PARSE_ERROR;
-                  reader->unicode_high_surrogate = reader->unicode_char;
-                } else if ((reader->unicode_char & 0xfc00) == 0xdc00) {
-                  /* low surrogate utf-16 */
-                  uint32_t utf32;
-                  if (reader->unicode_high_surrogate == 0)
-                    return GRPC_JSON_PARSE_ERROR;
-                  utf32 = 0x10000;
-                  utf32 += (uint32_t)(
-                      (reader->unicode_high_surrogate - 0xd800) * 0x400);
-                  utf32 += (uint32_t)(reader->unicode_char - 0xdc00);
-                  json_reader_string_add_utf32(reader, utf32);
-                  reader->unicode_high_surrogate = 0;
-                } else {
-                  /* anything else */
-                  if (reader->unicode_high_surrogate != 0)
-                    return GRPC_JSON_PARSE_ERROR;
-                  json_reader_string_add_utf32(reader, reader->unicode_char);
-                }
-                if (reader->escaped_string_was_key) {
-                  reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
-                } else {
-                  reader->state = GRPC_JSON_STATE_VALUE_STRING;
-                }
-                break;
-              default:
-                GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR);
-            }
-            break;
-
-          case GRPC_JSON_STATE_VALUE_NUMBER:
-            json_reader_string_add_char(reader, c);
-            switch (c) {
-              case '0':
-              case '1':
-              case '2':
-              case '3':
-              case '4':
-              case '5':
-              case '6':
-              case '7':
-              case '8':
-              case '9':
-                break;
-              case 'e':
-              case 'E':
-                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E;
-                break;
-              case '.':
-                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT;
-                break;
-              default:
-                return GRPC_JSON_PARSE_ERROR;
-            }
-            break;
-
-          case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
-            json_reader_string_add_char(reader, c);
-            switch (c) {
-              case '0':
-              case '1':
-              case '2':
-              case '3':
-              case '4':
-              case '5':
-              case '6':
-              case '7':
-              case '8':
-              case '9':
-                break;
-              case 'e':
-              case 'E':
-                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E;
-                break;
-              default:
-                return GRPC_JSON_PARSE_ERROR;
-            }
-            break;
-
-          case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
-            if (c != '.') return GRPC_JSON_PARSE_ERROR;
-            json_reader_string_add_char(reader, c);
-            reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT;
-            break;
-
-          case GRPC_JSON_STATE_VALUE_NUMBER_DOT:
-            json_reader_string_add_char(reader, c);
-            switch (c) {
-              case '0':
-              case '1':
-              case '2':
-              case '3':
-              case '4':
-              case '5':
-              case '6':
-              case '7':
-              case '8':
-              case '9':
-                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL;
-                break;
-              default:
-                return GRPC_JSON_PARSE_ERROR;
-            }
-            break;
-
-          case GRPC_JSON_STATE_VALUE_NUMBER_E:
-            json_reader_string_add_char(reader, c);
-            switch (c) {
-              case '0':
-              case '1':
-              case '2':
-              case '3':
-              case '4':
-              case '5':
-              case '6':
-              case '7':
-              case '8':
-              case '9':
-              case '+':
-              case '-':
-                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_EPM;
-                break;
-              default:
-                return GRPC_JSON_PARSE_ERROR;
-            }
-            break;
-
-          case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
-            json_reader_string_add_char(reader, c);
-            switch (c) {
-              case '0':
-              case '1':
-              case '2':
-              case '3':
-              case '4':
-              case '5':
-              case '6':
-              case '7':
-              case '8':
-              case '9':
-                break;
-              default:
-                return GRPC_JSON_PARSE_ERROR;
-            }
-            break;
-
-          case GRPC_JSON_STATE_VALUE_TRUE_R:
-            if (c != 'r') return GRPC_JSON_PARSE_ERROR;
-            reader->state = GRPC_JSON_STATE_VALUE_TRUE_U;
-            break;
-
-          case GRPC_JSON_STATE_VALUE_TRUE_U:
-            if (c != 'u') return GRPC_JSON_PARSE_ERROR;
-            reader->state = GRPC_JSON_STATE_VALUE_TRUE_E;
-            break;
-
-          case GRPC_JSON_STATE_VALUE_TRUE_E:
-            if (c != 'e') return GRPC_JSON_PARSE_ERROR;
-            json_reader_set_true(reader);
-            reader->state = GRPC_JSON_STATE_VALUE_END;
-            break;
-
-          case GRPC_JSON_STATE_VALUE_FALSE_A:
-            if (c != 'a') return GRPC_JSON_PARSE_ERROR;
-            reader->state = GRPC_JSON_STATE_VALUE_FALSE_L;
-            break;
-
-          case GRPC_JSON_STATE_VALUE_FALSE_L:
-            if (c != 'l') return GRPC_JSON_PARSE_ERROR;
-            reader->state = GRPC_JSON_STATE_VALUE_FALSE_S;
-            break;
-
-          case GRPC_JSON_STATE_VALUE_FALSE_S:
-            if (c != 's') return GRPC_JSON_PARSE_ERROR;
-            reader->state = GRPC_JSON_STATE_VALUE_FALSE_E;
-            break;
-
-          case GRPC_JSON_STATE_VALUE_FALSE_E:
-            if (c != 'e') return GRPC_JSON_PARSE_ERROR;
-            json_reader_set_false(reader);
-            reader->state = GRPC_JSON_STATE_VALUE_END;
-            break;
-
-          case GRPC_JSON_STATE_VALUE_NULL_U:
-            if (c != 'u') return GRPC_JSON_PARSE_ERROR;
-            reader->state = GRPC_JSON_STATE_VALUE_NULL_L1;
-            break;
-
-          case GRPC_JSON_STATE_VALUE_NULL_L1:
-            if (c != 'l') return GRPC_JSON_PARSE_ERROR;
-            reader->state = GRPC_JSON_STATE_VALUE_NULL_L2;
-            break;
-
-          case GRPC_JSON_STATE_VALUE_NULL_L2:
-            if (c != 'l') return GRPC_JSON_PARSE_ERROR;
-            json_reader_set_null(reader);
-            reader->state = GRPC_JSON_STATE_VALUE_END;
-            break;
-
-          /* All of the VALUE_END cases are handled in the specialized case
-           * above. */
-          case GRPC_JSON_STATE_VALUE_END:
-            switch (c) {
-              case ',':
-              case '}':
-              case ']':
-                GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR);
-                break;
-
-              default:
-                return GRPC_JSON_PARSE_ERROR;
-            }
-            break;
-
-          case GRPC_JSON_STATE_END:
-            return GRPC_JSON_PARSE_ERROR;
-        }
-    }
-  }
-
-  GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR);
-}
diff --git a/src/core/json/json_reader.h b/src/core/json/json_reader.h
deleted file mode 100644
index 90b9f1f..0000000
--- a/src/core/json/json_reader.h
+++ /dev/null
@@ -1,160 +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_JSON_JSON_READER_H
-#define GRPC_INTERNAL_CORE_JSON_JSON_READER_H
-
-#include <grpc/support/port_platform.h>
-#include "src/core/json/json_common.h"
-
-typedef enum {
-  GRPC_JSON_STATE_OBJECT_KEY_BEGIN,
-  GRPC_JSON_STATE_OBJECT_KEY_STRING,
-  GRPC_JSON_STATE_OBJECT_KEY_END,
-  GRPC_JSON_STATE_VALUE_BEGIN,
-  GRPC_JSON_STATE_VALUE_STRING,
-  GRPC_JSON_STATE_STRING_ESCAPE,
-  GRPC_JSON_STATE_STRING_ESCAPE_U1,
-  GRPC_JSON_STATE_STRING_ESCAPE_U2,
-  GRPC_JSON_STATE_STRING_ESCAPE_U3,
-  GRPC_JSON_STATE_STRING_ESCAPE_U4,
-  GRPC_JSON_STATE_VALUE_NUMBER,
-  GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL,
-  GRPC_JSON_STATE_VALUE_NUMBER_ZERO,
-  GRPC_JSON_STATE_VALUE_NUMBER_DOT,
-  GRPC_JSON_STATE_VALUE_NUMBER_E,
-  GRPC_JSON_STATE_VALUE_NUMBER_EPM,
-  GRPC_JSON_STATE_VALUE_TRUE_R,
-  GRPC_JSON_STATE_VALUE_TRUE_U,
-  GRPC_JSON_STATE_VALUE_TRUE_E,
-  GRPC_JSON_STATE_VALUE_FALSE_A,
-  GRPC_JSON_STATE_VALUE_FALSE_L,
-  GRPC_JSON_STATE_VALUE_FALSE_S,
-  GRPC_JSON_STATE_VALUE_FALSE_E,
-  GRPC_JSON_STATE_VALUE_NULL_U,
-  GRPC_JSON_STATE_VALUE_NULL_L1,
-  GRPC_JSON_STATE_VALUE_NULL_L2,
-  GRPC_JSON_STATE_VALUE_END,
-  GRPC_JSON_STATE_END
-} grpc_json_reader_state;
-
-enum {
-  /* The first non-unicode value is 0x110000. But let's pick
-   * a value high enough to start our error codes from. These
-   * values are safe to return from the read_char function.
-   */
-  GRPC_JSON_READ_CHAR_EOF = 0x7ffffff0,
-  GRPC_JSON_READ_CHAR_EAGAIN,
-  GRPC_JSON_READ_CHAR_ERROR
-};
-
-struct grpc_json_reader;
-
-typedef struct grpc_json_reader_vtable {
-  /* Clears your internal string scratchpad. */
-  void (*string_clear)(void *userdata);
-  /* Adds a char to the string scratchpad. */
-  void (*string_add_char)(void *userdata, uint32_t c);
-  /* Adds a utf32 char to the string scratchpad. */
-  void (*string_add_utf32)(void *userdata, uint32_t c);
-  /* Reads a character from your input. May be utf-8, 16 or 32. */
-  uint32_t (*read_char)(void *userdata);
-  /* Starts a container of type GRPC_JSON_ARRAY or GRPC_JSON_OBJECT. */
-  void (*container_begins)(void *userdata, grpc_json_type type);
-  /* Ends the current container. Must return the type of its parent. */
-  grpc_json_type (*container_ends)(void *userdata);
-  /* Your internal string scratchpad is an object's key. */
-  void (*set_key)(void *userdata);
-  /* Your internal string scratchpad is a string value. */
-  void (*set_string)(void *userdata);
-  /* Your internal string scratchpad is a numerical value. Return 1 if valid. */
-  int (*set_number)(void *userdata);
-  /* Sets the values true, false or null. */
-  void (*set_true)(void *userdata);
-  void (*set_false)(void *userdata);
-  void (*set_null)(void *userdata);
-} grpc_json_reader_vtable;
-
-typedef struct grpc_json_reader {
-  /* That structure is fully private, and initialized by grpc_json_reader_init.
-   * The definition is public so you can put it on your stack.
-   */
-
-  void *userdata;
-  grpc_json_reader_vtable *vtable;
-  int depth;
-  int in_object;
-  int in_array;
-  int escaped_string_was_key;
-  int container_just_begun;
-  uint16_t unicode_char, unicode_high_surrogate;
-  grpc_json_reader_state state;
-} grpc_json_reader;
-
-/* The return type of the parser. */
-typedef enum {
-  GRPC_JSON_DONE,          /* The parser finished successfully. */
-  GRPC_JSON_EAGAIN,        /* The parser yields to get more data. */
-  GRPC_JSON_READ_ERROR,    /* The parser passes through a read error. */
-  GRPC_JSON_PARSE_ERROR,   /* The parser found an error in the json stream. */
-  GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */
-} grpc_json_reader_status;
-
-/* Call this function to start parsing the input. It will return the following:
- *    . GRPC_JSON_DONE if the input got eof, and the parsing finished
- *      successfully.
- *    . GRPC_JSON_EAGAIN if the read_char function returned again. Call the
- *      parser again as needed. It is okay to call the parser in polling mode,
- *      although a bit dull.
- *    . GRPC_JSON_READ_ERROR if the read_char function returned an error. The
- *      state isn't broken however, and the function can be called again if the
- *      error has been corrected. But please use the EAGAIN feature instead for
- *      consistency.
- *    . GRPC_JSON_PARSE_ERROR if the input was somehow invalid.
- *    . GRPC_JSON_INTERNAL_ERROR if the parser somehow ended into an invalid
- *      internal state.
- */
-grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader);
-
-/* Call this function to initialize the reader structure. */
-void grpc_json_reader_init(grpc_json_reader *reader,
-                           grpc_json_reader_vtable *vtable, void *userdata);
-
-/* You may call this from the read_char callback if you don't know where is the
- * end of your input stream, and you'd like the json reader to hint you that it
- * has completed reading its input, so you can return an EOF to it. Note that
- * there might still be trailing whitespaces after that point.
- */
-int grpc_json_reader_is_complete(grpc_json_reader *reader);
-
-#endif /* GRPC_INTERNAL_CORE_JSON_JSON_READER_H */
diff --git a/src/core/json/json_string.c b/src/core/json/json_string.c
deleted file mode 100644
index 2bc0b51..0000000
--- a/src/core/json/json_string.c
+++ /dev/null
@@ -1,379 +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 <string.h>
-#include <stdlib.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/json/json.h"
-#include "src/core/json/json_reader.h"
-#include "src/core/json/json_writer.h"
-
-/* The json reader will construct a bunch of grpc_json objects and
- * link them all up together in a tree-like structure that will represent
- * the json data in memory.
- *
- * It also uses its own input as a scratchpad to store all of the decoded,
- * unescaped strings. So we need to keep track of all these pointers in
- * that opaque structure the reader will carry for us.
- *
- * Note that this works because the act of parsing json always reduces its
- * input size, and never expands it.
- */
-typedef struct {
-  grpc_json *top;
-  grpc_json *current_container;
-  grpc_json *current_value;
-  uint8_t *input;
-  uint8_t *key;
-  uint8_t *string;
-  uint8_t *string_ptr;
-  size_t remaining_input;
-} json_reader_userdata;
-
-/* This json writer will put everything in a big string.
- * The point is that we allocate that string in chunks of 256 bytes.
- */
-typedef struct {
-  char *output;
-  size_t free_space;
-  size_t string_len;
-  size_t allocated;
-} json_writer_userdata;
-
-/* This function checks if there's enough space left in the output buffer,
- * and will enlarge it if necessary. We're only allocating chunks of 256
- * bytes at a time (or multiples thereof).
- */
-static void json_writer_output_check(void *userdata, size_t needed) {
-  json_writer_userdata *state = userdata;
-  if (state->free_space >= needed) return;
-  needed -= state->free_space;
-  /* Round up by 256 bytes. */
-  needed = (needed + 0xff) & ~0xffU;
-  state->output = gpr_realloc(state->output, state->allocated + needed);
-  state->free_space += needed;
-  state->allocated += needed;
-}
-
-/* These are needed by the writer's implementation. */
-static void json_writer_output_char(void *userdata, char c) {
-  json_writer_userdata *state = userdata;
-  json_writer_output_check(userdata, 1);
-  state->output[state->string_len++] = c;
-  state->free_space--;
-}
-
-static void json_writer_output_string_with_len(void *userdata, const char *str,
-                                               size_t len) {
-  json_writer_userdata *state = userdata;
-  json_writer_output_check(userdata, len);
-  memcpy(state->output + state->string_len, str, len);
-  state->string_len += len;
-  state->free_space -= len;
-}
-
-static void json_writer_output_string(void *userdata, const char *str) {
-  size_t len = strlen(str);
-  json_writer_output_string_with_len(userdata, str, len);
-}
-
-/* The reader asks us to clear our scratchpad. In our case, we'll simply mark
- * the end of the current string, and advance our output pointer.
- */
-static void json_reader_string_clear(void *userdata) {
-  json_reader_userdata *state = userdata;
-  if (state->string) {
-    GPR_ASSERT(state->string_ptr < state->input);
-    *state->string_ptr++ = 0;
-  }
-  state->string = state->string_ptr;
-}
-
-static void json_reader_string_add_char(void *userdata, uint32_t c) {
-  json_reader_userdata *state = userdata;
-  GPR_ASSERT(state->string_ptr < state->input);
-  GPR_ASSERT(c <= 0xff);
-  *state->string_ptr++ = (uint8_t)c;
-}
-
-/* We are converting a UTF-32 character into UTF-8 here,
- * as described by RFC3629.
- */
-static void json_reader_string_add_utf32(void *userdata, uint32_t c) {
-  if (c <= 0x7f) {
-    json_reader_string_add_char(userdata, c);
-  } else if (c <= 0x7ff) {
-    uint32_t b1 = 0xc0 | ((c >> 6) & 0x1f);
-    uint32_t b2 = 0x80 | (c & 0x3f);
-    json_reader_string_add_char(userdata, b1);
-    json_reader_string_add_char(userdata, b2);
-  } else if (c <= 0xffff) {
-    uint32_t b1 = 0xe0 | ((c >> 12) & 0x0f);
-    uint32_t b2 = 0x80 | ((c >> 6) & 0x3f);
-    uint32_t 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) {
-    uint32_t b1 = 0xf0 | ((c >> 18) & 0x07);
-    uint32_t b2 = 0x80 | ((c >> 12) & 0x3f);
-    uint32_t b3 = 0x80 | ((c >> 6) & 0x3f);
-    uint32_t 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);
-    json_reader_string_add_char(userdata, b4);
-  }
-}
-
-/* We consider that the input may be a zero-terminated string. So we
- * can end up hitting eof before the end of the alleged string length.
- */
-static uint32_t json_reader_read_char(void *userdata) {
-  uint32_t r;
-  json_reader_userdata *state = userdata;
-
-  if (state->remaining_input == 0) return GRPC_JSON_READ_CHAR_EOF;
-
-  r = *state->input++;
-  state->remaining_input--;
-
-  if (r == 0) {
-    state->remaining_input = 0;
-    return GRPC_JSON_READ_CHAR_EOF;
-  }
-
-  return r;
-}
-
-/* Helper function to create a new grpc_json object and link it into
- * our tree-in-progress inside our opaque structure.
- */
-static grpc_json *json_create_and_link(void *userdata, grpc_json_type type) {
-  json_reader_userdata *state = userdata;
-  grpc_json *json = grpc_json_create(type);
-
-  json->parent = state->current_container;
-  json->prev = state->current_value;
-  state->current_value = json;
-
-  if (json->prev) {
-    json->prev->next = json;
-  }
-  if (json->parent) {
-    if (!json->parent->child) {
-      json->parent->child = json;
-    }
-    if (json->parent->type == GRPC_JSON_OBJECT) {
-      json->key = (char *)state->key;
-    }
-  }
-  if (!state->top) {
-    state->top = json;
-  }
-
-  return json;
-}
-
-static void json_reader_container_begins(void *userdata, grpc_json_type type) {
-  json_reader_userdata *state = userdata;
-  grpc_json *container;
-
-  GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT);
-
-  container = json_create_and_link(userdata, type);
-  state->current_container = container;
-  state->current_value = NULL;
-}
-
-/* It's important to remember that the reader is mostly stateless, so it
- * isn't trying to remember what the container was prior the one that just
- * ends. Since we're keeping track of these for our own purpose, we are
- * able to return that information back, which is useful for it to validate
- * the input json stream.
- *
- * Also note that if we're at the top of the tree, and the last container
- * ends, we have to return GRPC_JSON_TOP_LEVEL.
- */
-static grpc_json_type json_reader_container_ends(void *userdata) {
-  grpc_json_type container_type = GRPC_JSON_TOP_LEVEL;
-  json_reader_userdata *state = userdata;
-
-  GPR_ASSERT(state->current_container);
-
-  state->current_value = state->current_container;
-  state->current_container = state->current_container->parent;
-
-  if (state->current_container) {
-    container_type = state->current_container->type;
-  }
-
-  return container_type;
-}
-
-/* The next 3 functions basically are the reader asking us to use our string
- * scratchpad for one of these 3 purposes.
- *
- * Note that in the set_number case, we're not going to try interpreting it.
- * We'll keep it as a string, and leave it to the caller to evaluate it.
- */
-static void json_reader_set_key(void *userdata) {
-  json_reader_userdata *state = userdata;
-  state->key = state->string;
-}
-
-static void json_reader_set_string(void *userdata) {
-  json_reader_userdata *state = userdata;
-  grpc_json *json = json_create_and_link(userdata, GRPC_JSON_STRING);
-  json->value = (char *)state->string;
-}
-
-static int json_reader_set_number(void *userdata) {
-  json_reader_userdata *state = userdata;
-  grpc_json *json = json_create_and_link(userdata, GRPC_JSON_NUMBER);
-  json->value = (char *)state->string;
-  return 1;
-}
-
-/* The object types true, false and null are self-sufficient, and don't need
- * any more information beside their type.
- */
-static void json_reader_set_true(void *userdata) {
-  json_create_and_link(userdata, GRPC_JSON_TRUE);
-}
-
-static void json_reader_set_false(void *userdata) {
-  json_create_and_link(userdata, GRPC_JSON_FALSE);
-}
-
-static void json_reader_set_null(void *userdata) {
-  json_create_and_link(userdata, GRPC_JSON_NULL);
-}
-
-static grpc_json_reader_vtable reader_vtable = {
-    json_reader_string_clear,     json_reader_string_add_char,
-    json_reader_string_add_utf32, json_reader_read_char,
-    json_reader_container_begins, json_reader_container_ends,
-    json_reader_set_key,          json_reader_set_string,
-    json_reader_set_number,       json_reader_set_true,
-    json_reader_set_false,        json_reader_set_null};
-
-/* And finally, let's define our public API. */
-grpc_json *grpc_json_parse_string_with_len(char *input, size_t size) {
-  grpc_json_reader reader;
-  json_reader_userdata state;
-  grpc_json *json = NULL;
-  grpc_json_reader_status status;
-
-  if (!input) return NULL;
-
-  state.top = state.current_container = state.current_value = NULL;
-  state.string = state.key = NULL;
-  state.string_ptr = state.input = (uint8_t *)input;
-  state.remaining_input = size;
-  grpc_json_reader_init(&reader, &reader_vtable, &state);
-
-  status = grpc_json_reader_run(&reader);
-  json = state.top;
-
-  if ((status != GRPC_JSON_DONE) && json) {
-    grpc_json_destroy(json);
-    json = NULL;
-  }
-
-  return json;
-}
-
-#define UNBOUND_JSON_STRING_LENGTH 0x7fffffff
-
-grpc_json *grpc_json_parse_string(char *input) {
-  return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH);
-}
-
-static void json_dump_recursive(grpc_json_writer *writer, grpc_json *json,
-                                int in_object) {
-  while (json) {
-    if (in_object) grpc_json_writer_object_key(writer, json->key);
-
-    switch (json->type) {
-      case GRPC_JSON_OBJECT:
-      case GRPC_JSON_ARRAY:
-        grpc_json_writer_container_begins(writer, json->type);
-        if (json->child)
-          json_dump_recursive(writer, json->child,
-                              json->type == GRPC_JSON_OBJECT);
-        grpc_json_writer_container_ends(writer, json->type);
-        break;
-      case GRPC_JSON_STRING:
-        grpc_json_writer_value_string(writer, json->value);
-        break;
-      case GRPC_JSON_NUMBER:
-        grpc_json_writer_value_raw(writer, json->value);
-        break;
-      case GRPC_JSON_TRUE:
-        grpc_json_writer_value_raw_with_len(writer, "true", 4);
-        break;
-      case GRPC_JSON_FALSE:
-        grpc_json_writer_value_raw_with_len(writer, "false", 5);
-        break;
-      case GRPC_JSON_NULL:
-        grpc_json_writer_value_raw_with_len(writer, "null", 4);
-        break;
-      default:
-        GPR_UNREACHABLE_CODE(abort());
-    }
-    json = json->next;
-  }
-}
-
-static grpc_json_writer_vtable writer_vtable = {
-    json_writer_output_char, json_writer_output_string,
-    json_writer_output_string_with_len};
-
-char *grpc_json_dump_to_string(grpc_json *json, int indent) {
-  grpc_json_writer writer;
-  json_writer_userdata state;
-
-  state.output = NULL;
-  state.free_space = state.string_len = state.allocated = 0;
-  grpc_json_writer_init(&writer, indent, &writer_vtable, &state);
-
-  json_dump_recursive(&writer, json, 0);
-
-  json_writer_output_char(&state, 0);
-
-  return state.output;
-}
diff --git a/src/core/json/json_writer.c b/src/core/json/json_writer.c
deleted file mode 100644
index 326ec2d..0000000
--- a/src/core/json/json_writer.c
+++ /dev/null
@@ -1,258 +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 <string.h>
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/json/json_writer.h"
-
-static void json_writer_output_char(grpc_json_writer *writer, char c) {
-  writer->vtable->output_char(writer->userdata, c);
-}
-
-static void json_writer_output_string(grpc_json_writer *writer,
-                                      const char *str) {
-  writer->vtable->output_string(writer->userdata, str);
-}
-
-static void json_writer_output_string_with_len(grpc_json_writer *writer,
-                                               const char *str, size_t len) {
-  writer->vtable->output_string_with_len(writer->userdata, str, len);
-}
-
-void grpc_json_writer_init(grpc_json_writer *writer, int indent,
-                           grpc_json_writer_vtable *vtable, void *userdata) {
-  memset(writer, 0, sizeof(*writer));
-  writer->container_empty = 1;
-  writer->indent = indent;
-  writer->vtable = vtable;
-  writer->userdata = userdata;
-}
-
-static void json_writer_output_indent(grpc_json_writer *writer) {
-  static const char spacesstr[] =
-      "                "
-      "                "
-      "                "
-      "                ";
-
-  unsigned spaces = (unsigned)(writer->depth * writer->indent);
-
-  if (writer->indent == 0) return;
-
-  if (writer->got_key) {
-    json_writer_output_char(writer, ' ');
-    return;
-  }
-
-  while (spaces >= (sizeof(spacesstr) - 1)) {
-    json_writer_output_string_with_len(writer, spacesstr,
-                                       sizeof(spacesstr) - 1);
-    spaces -= (unsigned)(sizeof(spacesstr) - 1);
-  }
-
-  if (spaces == 0) return;
-
-  json_writer_output_string_with_len(
-      writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces);
-}
-
-static void json_writer_value_end(grpc_json_writer *writer) {
-  if (writer->container_empty) {
-    writer->container_empty = 0;
-    if ((writer->indent == 0) || (writer->depth == 0)) return;
-    json_writer_output_char(writer, '\n');
-  } else {
-    json_writer_output_char(writer, ',');
-    if (writer->indent == 0) return;
-    json_writer_output_char(writer, '\n');
-  }
-}
-
-static void json_writer_escape_utf16(grpc_json_writer *writer, uint16_t utf16) {
-  static const char hex[] = "0123456789abcdef";
-
-  json_writer_output_string_with_len(writer, "\\u", 2);
-  json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]);
-  json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]);
-  json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]);
-  json_writer_output_char(writer, hex[(utf16)&0x0f]);
-}
-
-static void json_writer_escape_string(grpc_json_writer *writer,
-                                      const char *string) {
-  json_writer_output_char(writer, '"');
-
-  for (;;) {
-    uint8_t c = (uint8_t)*string++;
-    if (c == 0) {
-      break;
-    } else if ((c >= 32) && (c <= 126)) {
-      if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\');
-      json_writer_output_char(writer, (char)c);
-    } else if ((c < 32) || (c == 127)) {
-      switch (c) {
-        case '\b':
-          json_writer_output_string_with_len(writer, "\\b", 2);
-          break;
-        case '\f':
-          json_writer_output_string_with_len(writer, "\\f", 2);
-          break;
-        case '\n':
-          json_writer_output_string_with_len(writer, "\\n", 2);
-          break;
-        case '\r':
-          json_writer_output_string_with_len(writer, "\\r", 2);
-          break;
-        case '\t':
-          json_writer_output_string_with_len(writer, "\\t", 2);
-          break;
-        default:
-          json_writer_escape_utf16(writer, c);
-          break;
-      }
-    } else {
-      uint32_t utf32 = 0;
-      int extra = 0;
-      int i;
-      int valid = 1;
-      if ((c & 0xe0) == 0xc0) {
-        utf32 = c & 0x1f;
-        extra = 1;
-      } else if ((c & 0xf0) == 0xe0) {
-        utf32 = c & 0x0f;
-        extra = 2;
-      } else if ((c & 0xf8) == 0xf0) {
-        utf32 = c & 0x07;
-        extra = 3;
-      } else {
-        break;
-      }
-      for (i = 0; i < extra; i++) {
-        utf32 <<= 6;
-        c = (uint8_t)(*string++);
-        /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */
-        if ((c & 0xc0) != 0x80) {
-          valid = 0;
-          break;
-        }
-        utf32 |= c & 0x3f;
-      }
-      if (!valid) break;
-      /* The range 0xd800 - 0xdfff is reserved by the surrogates ad vitam.
-       * Any other range is technically reserved for future usage, so if we
-       * don't want the software to break in the future, we have to allow
-       * anything else. The first non-unicode character is 0x110000. */
-      if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000))
-        break;
-      if (utf32 >= 0x10000) {
-        /* If utf32 contains a character that is above 0xffff, it needs to be
-         * broken down into a utf-16 surrogate pair. A surrogate pair is first
-         * a high surrogate, followed by a low surrogate. Each surrogate holds
-         * 10 bits of usable data, thus allowing a total of 20 bits of data.
-         * The high surrogate marker is 0xd800, while the low surrogate marker
-         * is 0xdc00. The low 10 bits of each will be the usable data.
-         *
-         * After re-combining the 20 bits of data, one has to add 0x10000 to
-         * the resulting value, in order to obtain the original character.
-         * This is obviously because the range 0x0000 - 0xffff can be written
-         * without any special trick.
-         *
-         * Since 0x10ffff is the highest allowed character, we're working in
-         * the range 0x00000 - 0xfffff after we decrement it by 0x10000.
-         * That range is exactly 20 bits.
-         */
-        utf32 -= 0x10000;
-        json_writer_escape_utf16(writer, (uint16_t)(0xd800 | (utf32 >> 10)));
-        json_writer_escape_utf16(writer, (uint16_t)(0xdc00 | (utf32 & 0x3ff)));
-      } else {
-        json_writer_escape_utf16(writer, (uint16_t)utf32);
-      }
-    }
-  }
-
-  json_writer_output_char(writer, '"');
-}
-
-void grpc_json_writer_container_begins(grpc_json_writer *writer,
-                                       grpc_json_type type) {
-  if (!writer->got_key) json_writer_value_end(writer);
-  json_writer_output_indent(writer);
-  json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '[');
-  writer->container_empty = 1;
-  writer->got_key = 0;
-  writer->depth++;
-}
-
-void grpc_json_writer_container_ends(grpc_json_writer *writer,
-                                     grpc_json_type type) {
-  if (writer->indent && !writer->container_empty)
-    json_writer_output_char(writer, '\n');
-  writer->depth--;
-  if (!writer->container_empty) json_writer_output_indent(writer);
-  json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']');
-  writer->container_empty = 0;
-  writer->got_key = 0;
-}
-
-void grpc_json_writer_object_key(grpc_json_writer *writer, const char *string) {
-  json_writer_value_end(writer);
-  json_writer_output_indent(writer);
-  json_writer_escape_string(writer, string);
-  json_writer_output_char(writer, ':');
-  writer->got_key = 1;
-}
-
-void grpc_json_writer_value_raw(grpc_json_writer *writer, const char *string) {
-  if (!writer->got_key) json_writer_value_end(writer);
-  json_writer_output_indent(writer);
-  json_writer_output_string(writer, string);
-  writer->got_key = 0;
-}
-
-void grpc_json_writer_value_raw_with_len(grpc_json_writer *writer,
-                                         const char *string, size_t len) {
-  if (!writer->got_key) json_writer_value_end(writer);
-  json_writer_output_indent(writer);
-  json_writer_output_string_with_len(writer, string, len);
-  writer->got_key = 0;
-}
-
-void grpc_json_writer_value_string(grpc_json_writer *writer,
-                                   const char *string) {
-  if (!writer->got_key) json_writer_value_end(writer);
-  json_writer_output_indent(writer);
-  json_writer_escape_string(writer, string);
-  writer->got_key = 0;
-}
diff --git a/src/core/json/json_writer.h b/src/core/json/json_writer.h
deleted file mode 100644
index 9ef04aa..0000000
--- a/src/core/json/json_writer.h
+++ /dev/null
@@ -1,97 +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.
- *
- */
-
-/* The idea of the writer is basically symmetrical of the reader. While the
- * reader emits various calls to your code, the writer takes basically the
- * same calls and emit json out of it. It doesn't try to make any check on
- * the order of the calls you do on it. Meaning you can theorically force
- * it to generate invalid json.
- *
- * Also, unlike the reader, the writer expects UTF-8 encoded input strings.
- * These strings will be UTF-8 validated, and any invalid character will
- * cut the conversion short, before any invalid UTF-8 sequence, thus forming
- * a valid UTF-8 string overall.
- */
-
-#ifndef GRPC_INTERNAL_CORE_JSON_JSON_WRITER_H
-#define GRPC_INTERNAL_CORE_JSON_JSON_WRITER_H
-
-#include <stdlib.h>
-
-#include "src/core/json/json_common.h"
-
-typedef struct grpc_json_writer_vtable {
-  /* Adds a character to the output stream. */
-  void (*output_char)(void *userdata, char);
-  /* Adds a zero-terminated string to the output stream. */
-  void (*output_string)(void *userdata, const char *str);
-  /* Adds a fixed-length string to the output stream. */
-  void (*output_string_with_len)(void *userdata, const char *str, size_t len);
-
-} grpc_json_writer_vtable;
-
-typedef struct grpc_json_writer {
-  void *userdata;
-  grpc_json_writer_vtable *vtable;
-  int indent;
-  int depth;
-  int container_empty;
-  int got_key;
-} grpc_json_writer;
-
-/* Call this to initialize your writer structure. The indent parameter is
- * specifying the number of spaces to use for indenting the output. If you
- * use indent=0, then the output will not have any newlines either, thus
- * emitting a condensed json output.
- */
-void grpc_json_writer_init(grpc_json_writer *writer, int indent,
-                           grpc_json_writer_vtable *vtable, void *userdata);
-
-/* Signals the beginning of a container. */
-void grpc_json_writer_container_begins(grpc_json_writer *writer,
-                                       grpc_json_type type);
-/* Signals the end of a container. */
-void grpc_json_writer_container_ends(grpc_json_writer *writer,
-                                     grpc_json_type type);
-/* Writes down an object key for the next value. */
-void grpc_json_writer_object_key(grpc_json_writer *writer, const char *string);
-/* Sets a raw value. Useful for numbers. */
-void grpc_json_writer_value_raw(grpc_json_writer *writer, const char *string);
-/* Sets a raw value with its length. Useful for values like true or false. */
-void grpc_json_writer_value_raw_with_len(grpc_json_writer *writer,
-                                         const char *string, size_t len);
-/* Sets a string value. It'll be escaped, and utf-8 validated. */
-void grpc_json_writer_value_string(grpc_json_writer *writer,
-                                   const char *string);
-
-#endif /* GRPC_INTERNAL_CORE_JSON_JSON_WRITER_H */
diff --git a/src/core/census/README.md b/src/core/lib/census/README.md
similarity index 100%
rename from src/core/census/README.md
rename to src/core/lib/census/README.md
diff --git a/src/core/lib/census/aggregation.h b/src/core/lib/census/aggregation.h
new file mode 100644
index 0000000..f353368
--- /dev/null
+++ b/src/core/lib/census/aggregation.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stddef.h>
+
+#ifndef GRPC_CORE_LIB_CENSUS_AGGREGATION_H
+#define GRPC_CORE_LIB_CENSUS_AGGREGATION_H
+
+/** Structure used to describe an aggregation type. */
+struct census_aggregation_ops {
+  /* Create a new aggregation. The pointer returned can be used in future calls
+     to clone(), free(), record(), data() and reset(). */
+  void *(*create)(const void *create_arg);
+  /* Make a copy of an aggregation created by create() */
+  void *(*clone)(const void *aggregation);
+  /* Destroy an aggregation created by create() */
+  void (*free)(void *aggregation);
+  /* Record a new value against aggregation. */
+  void (*record)(void *aggregation, double value);
+  /* Return current aggregation data. The caller must cast this object into
+     the correct type for the aggregation result. The object returned can be
+     freed by using free_data(). */
+  void *(*data)(const void *aggregation);
+  /* free data returned by data() */
+  void (*free_data)(void *data);
+  /* Reset an aggregation to default (zero) values. */
+  void (*reset)(void *aggregation);
+  /* Merge 'from' aggregation into 'to'. Both aggregations must be compatible */
+  void (*merge)(void *to, const void *from);
+  /* Fill buffer with printable string version of aggregation contents. For
+     debugging only. Returns the number of bytes added to buffer (a value == n
+     implies the buffer was of insufficient size). */
+  size_t (*print)(const void *aggregation, char *buffer, size_t n);
+};
+
+#endif /* GRPC_CORE_LIB_CENSUS_AGGREGATION_H */
diff --git a/src/core/lib/census/context.c b/src/core/lib/census/context.c
new file mode 100644
index 0000000..5a118f4
--- /dev/null
+++ b/src/core/lib/census/context.c
@@ -0,0 +1,509 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/census.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/useful.h>
+#include <stdbool.h>
+#include <string.h>
+#include "src/core/lib/support/string.h"
+
+// Functions in this file support the public context API, including
+// encoding/decoding as part of context propagation across RPC's. The overall
+// requirements (in approximate priority order) for the
+// context representation:
+// 1. Efficient conversion to/from wire format
+// 2. Minimal bytes used on-wire
+// 3. Efficient context creation
+// 4. Efficient lookup of tag value for a key
+// 5. Efficient iteration over tags
+// 6. Minimal memory footprint
+//
+// Notes on tradeoffs/decisions:
+// * tag includes 1 byte length of key, as well as nil-terminating byte. These
+//   are to aid in efficient parsing and the ability to directly return key
+//   strings. This is more important than saving a single byte/tag on the wire.
+// * The wire encoding uses only single byte values. This eliminates the need
+//   to handle endian-ness conversions. It also means there is a hard upper
+//   limit of 255 for both CENSUS_MAX_TAG_KV_LEN and CENSUS_MAX_PROPAGATED_TAGS.
+// * Keep all tag information (keys/values/flags) in a single memory buffer,
+//   that can be directly copied to the wire.
+
+// min and max valid chars in tag keys and values. All printable ASCII is OK.
+#define MIN_VALID_TAG_CHAR 32   // ' '
+#define MAX_VALID_TAG_CHAR 126  // '~'
+
+// Structure representing a set of tags. Essentially a count of number of tags
+// present, and pointer to a chunk of memory that contains the per-tag details.
+struct tag_set {
+  int ntags;        // number of tags.
+  int ntags_alloc;  // ntags + number of deleted tags (total number of tags
+  // in all of kvm). This will always be == ntags, except during the process
+  // of building a new tag set.
+  size_t kvm_size;  // number of bytes allocated for key/value storage.
+  size_t kvm_used;  // number of bytes of used key/value memory
+  char *kvm;        // key/value memory. Consists of repeated entries of:
+  //   Offset  Size  Description
+  //     0      1    Key length, including trailing 0. (K)
+  //     1      1    Value length, including trailing 0 (V)
+  //     2      1    Flags
+  //     3      K    Key bytes
+  //     3 + K  V    Value bytes
+  //
+  // We refer to the first 3 entries as the 'tag header'. If extra values are
+  // introduced in the header, you will need to modify the TAG_HEADER_SIZE
+  // constant, the raw_tag structure (and everything that uses it) and the
+  // encode/decode functions appropriately.
+};
+
+// Number of bytes in tag header.
+#define TAG_HEADER_SIZE 3  // key length (1) + value length (1) + flags (1)
+// Offsets to tag header entries.
+#define KEY_LEN_OFFSET 0
+#define VALUE_LEN_OFFSET 1
+#define FLAG_OFFSET 2
+
+// raw_tag represents the raw-storage form of a tag in the kvm of a tag_set.
+struct raw_tag {
+  uint8_t key_len;
+  uint8_t value_len;
+  uint8_t flags;
+  char *key;
+  char *value;
+};
+
+// Use a reserved flag bit for indication of deleted tag.
+#define CENSUS_TAG_DELETED CENSUS_TAG_RESERVED
+#define CENSUS_TAG_IS_DELETED(flags) (flags & CENSUS_TAG_DELETED)
+
+// Primary representation of a context. Composed of 2 underlying tag_set
+// structs, one each for propagated and local (non-propagated) tags. This is
+// to efficiently support tag encoding/decoding.
+// TODO(aveitch): need to add tracing id's/structure.
+struct census_context {
+  struct tag_set tags[2];
+  census_context_status status;
+};
+
+// Indices into the tags member of census_context
+#define PROPAGATED_TAGS 0
+#define LOCAL_TAGS 1
+
+// Validate (check all characters are in range and size is less than limit) a
+// key or value string. Returns 0 if the string is invalid, or the length
+// (including terminator) if valid.
+static size_t validate_tag(const char *kv) {
+  size_t len = 1;
+  char ch;
+  while ((ch = *kv++) != 0) {
+    if (ch < MIN_VALID_TAG_CHAR || ch > MAX_VALID_TAG_CHAR) {
+      return 0;
+    }
+    len++;
+  }
+  if (len > CENSUS_MAX_TAG_KV_LEN) {
+    return 0;
+  }
+  return len;
+}
+
+// Extract a raw tag given a pointer (raw) to the tag header. Allow for some
+// extra bytes in the tag header (see encode/decode functions for usage: this
+// allows for future expansion of the tag header).
+static char *decode_tag(struct raw_tag *tag, char *header, int offset) {
+  tag->key_len = (uint8_t)(*header++);
+  tag->value_len = (uint8_t)(*header++);
+  tag->flags = (uint8_t)(*header++);
+  header += offset;
+  tag->key = header;
+  header += tag->key_len;
+  tag->value = header;
+  return header + tag->value_len;
+}
+
+// Make a copy (in 'to') of an existing tag_set.
+static void tag_set_copy(struct tag_set *to, const struct tag_set *from) {
+  memcpy(to, from, sizeof(struct tag_set));
+  to->kvm = gpr_malloc(to->kvm_size);
+  memcpy(to->kvm, from->kvm, from->kvm_used);
+}
+
+// Delete a tag from a tag_set, if it exists (returns true if it did).
+static bool tag_set_delete_tag(struct tag_set *tags, const char *key,
+                               size_t key_len) {
+  char *kvp = tags->kvm;
+  for (int i = 0; i < tags->ntags_alloc; i++) {
+    uint8_t *flags = (uint8_t *)(kvp + FLAG_OFFSET);
+    struct raw_tag tag;
+    kvp = decode_tag(&tag, kvp, 0);
+    if (CENSUS_TAG_IS_DELETED(tag.flags)) continue;
+    if ((key_len == tag.key_len) && (memcmp(key, tag.key, key_len) == 0)) {
+      *flags |= CENSUS_TAG_DELETED;
+      tags->ntags--;
+      return true;
+    }
+  }
+  return false;
+}
+
+// Delete a tag from a context, return true if it existed.
+static bool context_delete_tag(census_context *context, const census_tag *tag,
+                               size_t key_len) {
+  return (
+      tag_set_delete_tag(&context->tags[LOCAL_TAGS], tag->key, key_len) ||
+      tag_set_delete_tag(&context->tags[PROPAGATED_TAGS], tag->key, key_len));
+}
+
+// Add a tag to a tag_set. Return true on success, false if the tag could
+// not be added because of constraints on tag set size. This function should
+// not be called if the tag may already exist (in a non-deleted state) in
+// the tag_set, as that would result in two tags with the same key.
+static bool tag_set_add_tag(struct tag_set *tags, const census_tag *tag,
+                            size_t key_len, size_t value_len) {
+  if (tags->ntags == CENSUS_MAX_PROPAGATED_TAGS) {
+    return false;
+  }
+  const size_t tag_size = key_len + value_len + TAG_HEADER_SIZE;
+  if (tags->kvm_used + tag_size > tags->kvm_size) {
+    // allocate new memory if needed
+    tags->kvm_size += 2 * CENSUS_MAX_TAG_KV_LEN + TAG_HEADER_SIZE;
+    char *new_kvm = gpr_malloc(tags->kvm_size);
+    memcpy(new_kvm, tags->kvm, tags->kvm_used);
+    gpr_free(tags->kvm);
+    tags->kvm = new_kvm;
+  }
+  char *kvp = tags->kvm + tags->kvm_used;
+  *kvp++ = (char)key_len;
+  *kvp++ = (char)value_len;
+  // ensure reserved flags are not used.
+  *kvp++ = (char)(tag->flags & (CENSUS_TAG_PROPAGATE | CENSUS_TAG_STATS));
+  memcpy(kvp, tag->key, key_len);
+  kvp += key_len;
+  memcpy(kvp, tag->value, value_len);
+  tags->kvm_used += tag_size;
+  tags->ntags++;
+  tags->ntags_alloc++;
+  return true;
+}
+
+// Add/modify/delete a tag to/in a context. Caller must validate that tag key
+// etc. are valid.
+static void context_modify_tag(census_context *context, const census_tag *tag,
+                               size_t key_len, size_t value_len) {
+  // First delete the tag if it is already present.
+  bool deleted = context_delete_tag(context, tag, key_len);
+  bool added = false;
+  if (CENSUS_TAG_IS_PROPAGATED(tag->flags)) {
+    added = tag_set_add_tag(&context->tags[PROPAGATED_TAGS], tag, key_len,
+                            value_len);
+  } else {
+    added =
+        tag_set_add_tag(&context->tags[LOCAL_TAGS], tag, key_len, value_len);
+  }
+
+  if (deleted) {
+    context->status.n_modified_tags++;
+  } else {
+    if (added) {
+      context->status.n_added_tags++;
+    } else {
+      context->status.n_ignored_tags++;
+    }
+  }
+}
+
+// Remove memory used for deleted tags from a tag set. Basic algorithm:
+// 1) Walk through tag set to find first deleted tag. Record where it is.
+// 2) Find the next not-deleted tag. Copy all of kvm from there to the end
+//    "over" the deleted tags
+// 3) repeat #1 and #2 until we have seen all tags
+// 4) if we are still looking for a not-deleted tag, then all the end portion
+//    of the kvm is deleted. Just reduce the used amount of memory by the
+//    appropriate amount.
+static void tag_set_flatten(struct tag_set *tags) {
+  if (tags->ntags == tags->ntags_alloc) return;
+  bool found_deleted = false;  // found a deleted tag.
+  char *kvp = tags->kvm;
+  char *dbase = NULL;  // record location of deleted tag
+  for (int i = 0; i < tags->ntags_alloc; i++) {
+    struct raw_tag tag;
+    char *next_kvp = decode_tag(&tag, kvp, 0);
+    if (found_deleted) {
+      if (!CENSUS_TAG_IS_DELETED(tag.flags)) {
+        ptrdiff_t reduce = kvp - dbase;  // #bytes in deleted tags
+        GPR_ASSERT(reduce > 0);
+        ptrdiff_t copy_size = tags->kvm + tags->kvm_used - kvp;
+        GPR_ASSERT(copy_size > 0);
+        memmove(dbase, kvp, (size_t)copy_size);
+        tags->kvm_used -= (size_t)reduce;
+        next_kvp -= reduce;
+        found_deleted = false;
+      }
+    } else {
+      if (CENSUS_TAG_IS_DELETED(tag.flags)) {
+        dbase = kvp;
+        found_deleted = true;
+      }
+    }
+    kvp = next_kvp;
+  }
+  if (found_deleted) {
+    GPR_ASSERT(dbase > tags->kvm);
+    tags->kvm_used = (size_t)(dbase - tags->kvm);
+  }
+  tags->ntags_alloc = tags->ntags;
+}
+
+census_context *census_context_create(const census_context *base,
+                                      const census_tag *tags, int ntags,
+                                      census_context_status const **status) {
+  census_context *context = gpr_malloc(sizeof(census_context));
+  // If we are given a base, copy it into our new tag set. Otherwise set it
+  // to zero/NULL everything.
+  if (base == NULL) {
+    memset(context, 0, sizeof(census_context));
+  } else {
+    tag_set_copy(&context->tags[PROPAGATED_TAGS], &base->tags[PROPAGATED_TAGS]);
+    tag_set_copy(&context->tags[LOCAL_TAGS], &base->tags[LOCAL_TAGS]);
+    memset(&context->status, 0, sizeof(context->status));
+  }
+  // Walk over the additional tags and, for those that aren't invalid, modify
+  // the context to add/replace/delete as required.
+  for (int i = 0; i < ntags; i++) {
+    const census_tag *tag = &tags[i];
+    size_t key_len = validate_tag(tag->key);
+    // ignore the tag if it is invalid or too short.
+    if (key_len <= 1) {
+      context->status.n_invalid_tags++;
+    } else {
+      if (tag->value != NULL) {
+        size_t value_len = validate_tag(tag->value);
+        if (value_len != 0) {
+          context_modify_tag(context, tag, key_len, value_len);
+        } else {
+          context->status.n_invalid_tags++;
+        }
+      } else {
+        if (context_delete_tag(context, tag, key_len)) {
+          context->status.n_deleted_tags++;
+        }
+      }
+    }
+  }
+  // Remove any deleted tags, update status if needed, and return.
+  tag_set_flatten(&context->tags[PROPAGATED_TAGS]);
+  tag_set_flatten(&context->tags[LOCAL_TAGS]);
+  context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags;
+  context->status.n_local_tags = context->tags[LOCAL_TAGS].ntags;
+  if (status) {
+    *status = &context->status;
+  }
+  return context;
+}
+
+const census_context_status *census_context_get_status(
+    const census_context *context) {
+  return &context->status;
+}
+
+void census_context_destroy(census_context *context) {
+  gpr_free(context->tags[PROPAGATED_TAGS].kvm);
+  gpr_free(context->tags[LOCAL_TAGS].kvm);
+  gpr_free(context);
+}
+
+void census_context_initialize_iterator(const census_context *context,
+                                        census_context_iterator *iterator) {
+  iterator->context = context;
+  iterator->index = 0;
+  if (context->tags[PROPAGATED_TAGS].ntags != 0) {
+    iterator->base = PROPAGATED_TAGS;
+    iterator->kvm = context->tags[PROPAGATED_TAGS].kvm;
+  } else if (context->tags[LOCAL_TAGS].ntags != 0) {
+    iterator->base = LOCAL_TAGS;
+    iterator->kvm = context->tags[LOCAL_TAGS].kvm;
+  } else {
+    iterator->base = -1;
+  }
+}
+
+int census_context_next_tag(census_context_iterator *iterator,
+                            census_tag *tag) {
+  if (iterator->base < 0) {
+    return 0;
+  }
+  struct raw_tag raw;
+  iterator->kvm = decode_tag(&raw, iterator->kvm, 0);
+  tag->key = raw.key;
+  tag->value = raw.value;
+  tag->flags = raw.flags;
+  if (++iterator->index == iterator->context->tags[iterator->base].ntags) {
+    do {
+      if (iterator->base == LOCAL_TAGS) {
+        iterator->base = -1;
+        return 1;
+      }
+    } while (iterator->context->tags[++iterator->base].ntags == 0);
+    iterator->index = 0;
+    iterator->kvm = iterator->context->tags[iterator->base].kvm;
+  }
+  return 1;
+}
+
+// Find a tag in a tag_set by key. Return true if found, false otherwise.
+static bool tag_set_get_tag(const struct tag_set *tags, const char *key,
+                            size_t key_len, census_tag *tag) {
+  char *kvp = tags->kvm;
+  for (int i = 0; i < tags->ntags; i++) {
+    struct raw_tag raw;
+    kvp = decode_tag(&raw, kvp, 0);
+    if (key_len == raw.key_len && memcmp(raw.key, key, key_len) == 0) {
+      tag->key = raw.key;
+      tag->value = raw.value;
+      tag->flags = raw.flags;
+      return true;
+    }
+  }
+  return false;
+}
+
+int census_context_get_tag(const census_context *context, const char *key,
+                           census_tag *tag) {
+  size_t key_len = strlen(key) + 1;
+  if (key_len == 1) {
+    return 0;
+  }
+  if (tag_set_get_tag(&context->tags[PROPAGATED_TAGS], key, key_len, tag) ||
+      tag_set_get_tag(&context->tags[LOCAL_TAGS], key, key_len, tag)) {
+    return 1;
+  }
+  return 0;
+}
+
+// Context encoding and decoding functions.
+//
+// Wire format for tag_set's on the wire:
+//
+// First, a tag set header:
+//
+// offset   bytes  description
+//   0        1    version number
+//   1        1    number of bytes in this header. This allows for future
+//                 expansion.
+//   2        1    number of bytes in each tag header.
+//   3        1    ntags value from tag set.
+//
+//   This is followed by the key/value memory from struct tag_set.
+
+#define ENCODED_VERSION 0      // Version number
+#define ENCODED_HEADER_SIZE 4  // size of tag set header
+
+// Encode a tag set. Returns 0 if buffer is too small.
+static size_t tag_set_encode(const struct tag_set *tags, char *buffer,
+                             size_t buf_size) {
+  if (buf_size < ENCODED_HEADER_SIZE + tags->kvm_used) {
+    return 0;
+  }
+  buf_size -= ENCODED_HEADER_SIZE;
+  *buffer++ = (char)ENCODED_VERSION;
+  *buffer++ = (char)ENCODED_HEADER_SIZE;
+  *buffer++ = (char)TAG_HEADER_SIZE;
+  *buffer++ = (char)tags->ntags;
+  if (tags->ntags == 0) {
+    return ENCODED_HEADER_SIZE;
+  }
+  memcpy(buffer, tags->kvm, tags->kvm_used);
+  return ENCODED_HEADER_SIZE + tags->kvm_used;
+}
+
+size_t census_context_encode(const census_context *context, char *buffer,
+                             size_t buf_size) {
+  return tag_set_encode(&context->tags[PROPAGATED_TAGS], buffer, buf_size);
+}
+
+// Decode a tag set.
+static void tag_set_decode(struct tag_set *tags, const char *buffer,
+                           size_t size) {
+  uint8_t version = (uint8_t)(*buffer++);
+  uint8_t header_size = (uint8_t)(*buffer++);
+  uint8_t tag_header_size = (uint8_t)(*buffer++);
+  tags->ntags = tags->ntags_alloc = (int)(*buffer++);
+  if (tags->ntags == 0) {
+    tags->ntags_alloc = 0;
+    tags->kvm_size = 0;
+    tags->kvm_used = 0;
+    tags->kvm = NULL;
+    return;
+  }
+  if (header_size != ENCODED_HEADER_SIZE) {
+    GPR_ASSERT(version != ENCODED_VERSION);
+    GPR_ASSERT(ENCODED_HEADER_SIZE < header_size);
+    buffer += (header_size - ENCODED_HEADER_SIZE);
+  }
+  tags->kvm_used = size - header_size;
+  tags->kvm_size = tags->kvm_used + CENSUS_MAX_TAG_KV_LEN;
+  tags->kvm = gpr_malloc(tags->kvm_size);
+  if (tag_header_size != TAG_HEADER_SIZE) {
+    // something new in the tag information. I don't understand it, so
+    // don't copy it over.
+    GPR_ASSERT(version != ENCODED_VERSION);
+    GPR_ASSERT(tag_header_size > TAG_HEADER_SIZE);
+    char *kvp = tags->kvm;
+    for (int i = 0; i < tags->ntags; i++) {
+      memcpy(kvp, buffer, TAG_HEADER_SIZE);
+      kvp += header_size;
+      struct raw_tag raw;
+      buffer =
+          decode_tag(&raw, (char *)buffer, tag_header_size - TAG_HEADER_SIZE);
+      memcpy(kvp, raw.key, (size_t)raw.key_len + raw.value_len);
+      kvp += raw.key_len + raw.value_len;
+    }
+  } else {
+    memcpy(tags->kvm, buffer, tags->kvm_used);
+  }
+}
+
+census_context *census_context_decode(const char *buffer, size_t size) {
+  census_context *context = gpr_malloc(sizeof(census_context));
+  memset(&context->tags[LOCAL_TAGS], 0, sizeof(struct tag_set));
+  if (buffer == NULL) {
+    memset(&context->tags[PROPAGATED_TAGS], 0, sizeof(struct tag_set));
+  } else {
+    tag_set_decode(&context->tags[PROPAGATED_TAGS], buffer, size);
+  }
+  memset(&context->status, 0, sizeof(context->status));
+  context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags;
+  return context;
+}
diff --git a/src/core/lib/census/grpc_context.c b/src/core/lib/census/grpc_context.c
new file mode 100644
index 0000000..457c176
--- /dev/null
+++ b/src/core/lib/census/grpc_context.c
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/census.h>
+#include <grpc/grpc.h>
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/call.h"
+
+void grpc_census_call_set_context(grpc_call *call, census_context *context) {
+  GRPC_API_TRACE("grpc_census_call_set_context(call=%p, census_context=%p)", 2,
+                 (call, context));
+  if (census_enabled() == CENSUS_FEATURE_NONE) {
+    return;
+  }
+  if (context != NULL) {
+    grpc_call_context_set(call, GRPC_CONTEXT_TRACING, context, NULL);
+  }
+}
+
+census_context *grpc_census_call_get_context(grpc_call *call) {
+  GRPC_API_TRACE("grpc_census_call_get_context(call=%p)", 1, (call));
+  return (census_context *)grpc_call_context_get(call, GRPC_CONTEXT_TRACING);
+}
diff --git a/src/core/lib/census/grpc_filter.c b/src/core/lib/census/grpc_filter.c
new file mode 100644
index 0000000..d27d789
--- /dev/null
+++ b/src/core/lib/census/grpc_filter.c
@@ -0,0 +1,198 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/census/grpc_filter.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/census.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/statistics/census_interface.h"
+#include "src/core/lib/statistics/census_rpc_stats.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+typedef struct call_data {
+  census_op_id op_id;
+  census_context *ctxt;
+  gpr_timespec start_ts;
+  int error;
+
+  /* recv callback */
+  grpc_metadata_batch *recv_initial_metadata;
+  grpc_closure *on_done_recv;
+  grpc_closure finish_recv;
+} call_data;
+
+typedef struct channel_data { uint8_t unused; } channel_data;
+
+static void extract_and_annotate_method_tag(grpc_metadata_batch *md,
+                                            call_data *calld,
+                                            channel_data *chand) {
+  grpc_linked_mdelem *m;
+  for (m = md->list.head; m != NULL; m = m->next) {
+    if (m->md->key == GRPC_MDSTR_PATH) {
+      gpr_log(GPR_DEBUG, "%s",
+              (const char *)GPR_SLICE_START_PTR(m->md->value->slice));
+      /* Add method tag here */
+    }
+  }
+}
+
+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_initial_metadata) {
+    extract_and_annotate_method_tag(op->send_initial_metadata, calld, chand);
+  }
+}
+
+static void client_start_transport_op(grpc_exec_ctx *exec_ctx,
+                                      grpc_call_element *elem,
+                                      grpc_transport_stream_op *op) {
+  client_mutate_op(elem, op);
+  grpc_call_next_op(exec_ctx, elem, op);
+}
+
+static void server_on_done_recv(grpc_exec_ctx *exec_ctx, void *ptr,
+                                bool success) {
+  grpc_call_element *elem = ptr;
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  if (success) {
+    extract_and_annotate_method_tag(calld->recv_initial_metadata, calld, chand);
+  }
+  calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success);
+}
+
+static void server_mutate_op(grpc_call_element *elem,
+                             grpc_transport_stream_op *op) {
+  call_data *calld = elem->call_data;
+  if (op->recv_initial_metadata) {
+    /* substitute our callback for the op callback */
+    calld->recv_initial_metadata = op->recv_initial_metadata;
+    calld->on_done_recv = op->recv_initial_metadata_ready;
+    op->recv_initial_metadata_ready = &calld->finish_recv;
+  }
+}
+
+static void server_start_transport_op(grpc_exec_ctx *exec_ctx,
+                                      grpc_call_element *elem,
+                                      grpc_transport_stream_op *op) {
+  /* TODO(ctiller): this code fails. I don't know why. I expect it's
+                    incomplete, and someone should look at it soon.
+
+  call_data *calld = elem->call_data;
+  GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); */
+  server_mutate_op(elem, op);
+  grpc_call_next_op(exec_ctx, elem, op);
+}
+
+static void client_init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
+  call_data *d = elem->call_data;
+  GPR_ASSERT(d != NULL);
+  memset(d, 0, sizeof(*d));
+  d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
+}
+
+static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_call_element *elem) {
+  call_data *d = elem->call_data;
+  GPR_ASSERT(d != NULL);
+  /* TODO(hongyu): record rpc client stats and census_rpc_end_op here */
+}
+
+static void server_init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
+  call_data *d = elem->call_data;
+  GPR_ASSERT(d != NULL);
+  memset(d, 0, sizeof(*d));
+  d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
+  /* TODO(hongyu): call census_tracing_start_op here. */
+  grpc_closure_init(&d->finish_recv, server_on_done_recv, elem);
+}
+
+static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_call_element *elem) {
+  call_data *d = elem->call_data;
+  GPR_ASSERT(d != NULL);
+  /* TODO(hongyu): record rpc server stats and census_tracing_end_op here */
+}
+
+static void init_channel_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_channel_element *elem,
+                              grpc_channel_element_args *args) {
+  channel_data *chand = elem->channel_data;
+  GPR_ASSERT(chand != NULL);
+}
+
+static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem) {
+  channel_data *chand = elem->channel_data;
+  GPR_ASSERT(chand != NULL);
+}
+
+const grpc_channel_filter grpc_client_census_filter = {
+    client_start_transport_op,
+    grpc_channel_next_op,
+    sizeof(call_data),
+    client_init_call_elem,
+    grpc_call_stack_ignore_set_pollset,
+    client_destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    grpc_call_next_get_peer,
+    "census-client"};
+
+const grpc_channel_filter grpc_server_census_filter = {
+    server_start_transport_op,
+    grpc_channel_next_op,
+    sizeof(call_data),
+    server_init_call_elem,
+    grpc_call_stack_ignore_set_pollset,
+    server_destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    grpc_call_next_get_peer,
+    "census-server"};
diff --git a/src/core/lib/census/grpc_filter.h b/src/core/lib/census/grpc_filter.h
new file mode 100644
index 0000000..7ceafe5
--- /dev/null
+++ b/src/core/lib/census/grpc_filter.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CENSUS_GRPC_FILTER_H
+#define GRPC_CORE_LIB_CENSUS_GRPC_FILTER_H
+
+#include "src/core/lib/channel/channel_stack.h"
+
+/* Census filters: provides tracing and stats collection functionalities. It
+   needs to reside right below the surface filter in the channel stack. */
+extern const grpc_channel_filter grpc_client_census_filter;
+extern const grpc_channel_filter grpc_server_census_filter;
+
+#endif /* GRPC_CORE_LIB_CENSUS_GRPC_FILTER_H */
diff --git a/src/core/lib/census/grpc_plugin.c b/src/core/lib/census/grpc_plugin.c
new file mode 100644
index 0000000..12aca76
--- /dev/null
+++ b/src/core/lib/census/grpc_plugin.c
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/census/grpc_plugin.h"
+
+#include <limits.h>
+
+#include <grpc/census.h>
+
+#include "src/core/lib/census/grpc_filter.h"
+#include "src/core/lib/channel/channel_stack_builder.h"
+#include "src/core/lib/surface/channel_init.h"
+
+static bool maybe_add_census_filter(grpc_channel_stack_builder *builder,
+                                    void *arg_must_be_null) {
+  const grpc_channel_args *args =
+      grpc_channel_stack_builder_get_channel_arguments(builder);
+  if (grpc_channel_args_is_census_enabled(args)) {
+    return grpc_channel_stack_builder_prepend_filter(
+        builder, &grpc_client_census_filter, NULL, NULL);
+  }
+  return true;
+}
+
+void census_grpc_plugin_init(void) {
+  /* Only initialize census if no one else has and some features are
+   * available. */
+  if (census_enabled() == CENSUS_FEATURE_NONE &&
+      census_supported() != CENSUS_FEATURE_NONE) {
+    if (census_initialize(census_supported())) { /* enable all features. */
+      gpr_log(GPR_ERROR, "Could not initialize census.");
+    }
+  }
+  grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX,
+                                   maybe_add_census_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
+                                   maybe_add_census_filter, NULL);
+}
+
+void census_grpc_plugin_destroy(void) { census_shutdown(); }
diff --git a/src/core/lib/census/grpc_plugin.h b/src/core/lib/census/grpc_plugin.h
new file mode 100644
index 0000000..33e5f0b
--- /dev/null
+++ b/src/core/lib/census/grpc_plugin.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CENSUS_GRPC_PLUGIN_H
+#define GRPC_CORE_LIB_CENSUS_GRPC_PLUGIN_H
+
+void census_grpc_plugin_init(void);
+void census_grpc_plugin_destroy(void);
+
+#endif /* GRPC_CORE_LIB_CENSUS_GRPC_PLUGIN_H */
diff --git a/src/core/census/initialize.c b/src/core/lib/census/initialize.c
similarity index 100%
rename from src/core/census/initialize.c
rename to src/core/lib/census/initialize.c
diff --git a/src/core/lib/census/mlog.c b/src/core/lib/census/mlog.c
new file mode 100644
index 0000000..9d47e80
--- /dev/null
+++ b/src/core/lib/census/mlog.c
@@ -0,0 +1,600 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+// Implements an efficient in-memory log, optimized for multiple writers and
+// a single reader. Available log space is divided up in blocks of
+// CENSUS_LOG_2_MAX_RECORD_SIZE bytes. A block can be in one of the following
+// three data structures:
+// - Free blocks (free_block_list)
+// - Blocks with unread data (dirty_block_list)
+// - Blocks currently attached to cores (core_local_blocks[])
+//
+// census_log_start_write() moves a block from core_local_blocks[] to the end of
+// dirty_block_list when block:
+// - is out-of-space OR
+// - has an incomplete record (an incomplete record occurs when a thread calls
+//   census_log_start_write() and is context-switched before calling
+//   census_log_end_write()
+// So, blocks in dirty_block_list are ordered, from oldest to newest, by the
+// time when block is detached from the core.
+//
+// census_log_read_next() first iterates over dirty_block_list and then
+// core_local_blocks[]. It moves completely read blocks from dirty_block_list
+// to free_block_list. Blocks in core_local_blocks[] are not freed, even when
+// completely read.
+//
+// If the log is configured to discard old records and free_block_list is empty,
+// census_log_start_write() iterates over dirty_block_list to allocate a
+// new block. It moves the oldest available block (no pending read/write) to
+// core_local_blocks[].
+//
+// core_local_block_struct is used to implement a map from core id to the block
+// associated with that core. This mapping is advisory. It is possible that the
+// block returned by this mapping is no longer associated with that core. This
+// mapping is updated, lazily, by census_log_start_write().
+//
+// Locking in block struct:
+//
+// Exclusive g_log.lock must be held before calling any functions operating on
+// block structs except census_log_start_write() and census_log_end_write().
+//
+// Writes to a block are serialized via writer_lock. census_log_start_write()
+// acquires this lock and census_log_end_write() releases it. On failure to
+// acquire the lock, writer allocates a new block for the current core and
+// updates core_local_block accordingly.
+//
+// Simultaneous read and write access is allowed. Readers can safely read up to
+// committed bytes (bytes_committed).
+//
+// reader_lock protects the block, currently being read, from getting recycled.
+// start_read() acquires reader_lock and end_read() releases the lock.
+//
+// Read/write access to a block is disabled via try_disable_access(). It returns
+// with both writer_lock and reader_lock held. These locks are subsequently
+// released by enable_access() to enable access to the block.
+//
+// A note on naming: Most function/struct names are prepended by cl_
+// (shorthand for census_log). Further, functions that manipulate structures
+// include the name of the structure, which will be passed as the first
+// argument. E.g. cl_block_initialize() will initialize a cl_block.
+
+#include "src/core/lib/census/mlog.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/cpu.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/useful.h>
+#include <stdbool.h>
+#include <string.h>
+
+// End of platform specific code
+
+typedef struct census_log_block_list_struct {
+  struct census_log_block_list_struct* next;
+  struct census_log_block_list_struct* prev;
+  struct census_log_block* block;
+} cl_block_list_struct;
+
+typedef struct census_log_block {
+  // Pointer to underlying buffer.
+  char* buffer;
+  gpr_atm writer_lock;
+  gpr_atm reader_lock;
+  // Keeps completely written bytes. Declared atomic because accessed
+  // simultaneously by reader and writer.
+  gpr_atm bytes_committed;
+  // Bytes already read.
+  size_t bytes_read;
+  // Links for list.
+  cl_block_list_struct link;
+// We want this structure to be cacheline aligned. We assume the following
+// sizes for the various parts on 32/64bit systems:
+// type                 32b size    64b size
+// char*                   4           8
+// 3x gpr_atm             12          24
+// size_t                  4           8
+// cl_block_list_struct   12          24
+// TOTAL                  32          64
+//
+// Depending on the size of our cacheline and the architecture, we
+// selectively add char buffering to this structure. The size is checked
+// via assert in census_log_initialize().
+#if defined(GPR_ARCH_64)
+#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 64)
+#else
+#if defined(GPR_ARCH_32)
+#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 32)
+#else
+#error "Unknown architecture"
+#endif
+#endif
+#if CL_BLOCK_PAD_SIZE > 0
+  char padding[CL_BLOCK_PAD_SIZE];
+#endif
+} cl_block;
+
+// A list of cl_blocks, doubly-linked through cl_block::link.
+typedef struct census_log_block_list {
+  int32_t count;            // Number of items in list.
+  cl_block_list_struct ht;  // head/tail of linked list.
+} cl_block_list;
+
+// Cacheline aligned block pointers to avoid false sharing. Block pointer must
+// be initialized via set_block(), before calling other functions
+typedef struct census_log_core_local_block {
+  gpr_atm block;
+// Ensure cachline alignment: we assume sizeof(gpr_atm) == 4 or 8
+#if defined(GPR_ARCH_64)
+#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 8)
+#else
+#if defined(GPR_ARCH_32)
+#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 4)
+#else
+#error "Unknown architecture"
+#endif
+#endif
+#if CL_CORE_LOCAL_BLOCK_PAD_SIZE > 0
+  char padding[CL_CORE_LOCAL_BLOCK_PAD_SIZE];
+#endif
+} cl_core_local_block;
+
+struct census_log {
+  int discard_old_records;
+  // Number of cores (aka hardware-contexts)
+  unsigned num_cores;
+  // number of CENSUS_LOG_2_MAX_RECORD_SIZE blocks in log
+  uint32_t num_blocks;
+  cl_block* blocks;                        // Block metadata.
+  cl_core_local_block* core_local_blocks;  // Keeps core to block mappings.
+  gpr_mu lock;
+  int initialized;  // has log been initialized?
+  // Keeps the state of the reader iterator. A value of 0 indicates that
+  // iterator has reached the end. census_log_init_reader() resets the value
+  // to num_core to restart iteration.
+  uint32_t read_iterator_state;
+  // Points to the block being read. If non-NULL, the block is locked for
+  // reading(block_being_read_->reader_lock is held).
+  cl_block* block_being_read;
+  char* buffer;
+  cl_block_list free_block_list;
+  cl_block_list dirty_block_list;
+  gpr_atm out_of_space_count;
+};
+
+// Single internal log.
+static struct census_log g_log;
+
+// Functions that operate on an atomic memory location used as a lock.
+
+// Returns non-zero if lock is acquired.
+static int cl_try_lock(gpr_atm* lock) { return gpr_atm_acq_cas(lock, 0, 1); }
+
+static void cl_unlock(gpr_atm* lock) { gpr_atm_rel_store(lock, 0); }
+
+// Functions that operate on cl_core_local_block's.
+
+static void cl_core_local_block_set_block(cl_core_local_block* clb,
+                                          cl_block* block) {
+  gpr_atm_rel_store(&clb->block, (gpr_atm)block);
+}
+
+static cl_block* cl_core_local_block_get_block(cl_core_local_block* clb) {
+  return (cl_block*)gpr_atm_acq_load(&clb->block);
+}
+
+// Functions that operate on cl_block_list_struct's.
+
+static void cl_block_list_struct_initialize(cl_block_list_struct* bls,
+                                            cl_block* block) {
+  bls->next = bls->prev = bls;
+  bls->block = block;
+}
+
+// Functions that operate on cl_block_list's.
+
+static void cl_block_list_initialize(cl_block_list* list) {
+  list->count = 0;
+  cl_block_list_struct_initialize(&list->ht, NULL);
+}
+
+// Returns head of *this, or NULL if empty.
+static cl_block* cl_block_list_head(cl_block_list* list) {
+  return list->ht.next->block;
+}
+
+// Insert element *e after *pos.
+static void cl_block_list_insert(cl_block_list* list, cl_block_list_struct* pos,
+                                 cl_block_list_struct* e) {
+  list->count++;
+  e->next = pos->next;
+  e->prev = pos;
+  e->next->prev = e;
+  e->prev->next = e;
+}
+
+// Insert block at the head of the list
+static void cl_block_list_insert_at_head(cl_block_list* list, cl_block* block) {
+  cl_block_list_insert(list, &list->ht, &block->link);
+}
+
+// Insert block at the tail of the list.
+static void cl_block_list_insert_at_tail(cl_block_list* list, cl_block* block) {
+  cl_block_list_insert(list, list->ht.prev, &block->link);
+}
+
+// Removes block *b. Requires *b be in the list.
+static void cl_block_list_remove(cl_block_list* list, cl_block* b) {
+  list->count--;
+  b->link.next->prev = b->link.prev;
+  b->link.prev->next = b->link.next;
+}
+
+// Functions that operate on cl_block's
+
+static void cl_block_initialize(cl_block* block, char* buffer) {
+  block->buffer = buffer;
+  gpr_atm_rel_store(&block->writer_lock, 0);
+  gpr_atm_rel_store(&block->reader_lock, 0);
+  gpr_atm_rel_store(&block->bytes_committed, 0);
+  block->bytes_read = 0;
+  cl_block_list_struct_initialize(&block->link, block);
+}
+
+// Guards against exposing partially written buffer to the reader.
+static void cl_block_set_bytes_committed(cl_block* block,
+                                         size_t bytes_committed) {
+  gpr_atm_rel_store(&block->bytes_committed, (gpr_atm)bytes_committed);
+}
+
+static size_t cl_block_get_bytes_committed(cl_block* block) {
+  return (size_t)gpr_atm_acq_load(&block->bytes_committed);
+}
+
+// Tries to disable future read/write access to this block. Succeeds if:
+// - no in-progress write AND
+// - no in-progress read AND
+// - 'discard_data' set to true OR no unread data
+// On success, clears the block state and returns with writer_lock_ and
+// reader_lock_ held. These locks are released by a subsequent
+// cl_block_access_enable() call.
+static bool cl_block_try_disable_access(cl_block* block, int discard_data) {
+  if (!cl_try_lock(&block->writer_lock)) {
+    return false;
+  }
+  if (!cl_try_lock(&block->reader_lock)) {
+    cl_unlock(&block->writer_lock);
+    return false;
+  }
+  if (!discard_data &&
+      (block->bytes_read != cl_block_get_bytes_committed(block))) {
+    cl_unlock(&block->reader_lock);
+    cl_unlock(&block->writer_lock);
+    return false;
+  }
+  cl_block_set_bytes_committed(block, 0);
+  block->bytes_read = 0;
+  return true;
+}
+
+static void cl_block_enable_access(cl_block* block) {
+  cl_unlock(&block->reader_lock);
+  cl_unlock(&block->writer_lock);
+}
+
+// Returns with writer_lock held.
+static void* cl_block_start_write(cl_block* block, size_t size) {
+  if (!cl_try_lock(&block->writer_lock)) {
+    return NULL;
+  }
+  size_t bytes_committed = cl_block_get_bytes_committed(block);
+  if (bytes_committed + size > CENSUS_LOG_MAX_RECORD_SIZE) {
+    cl_unlock(&block->writer_lock);
+    return NULL;
+  }
+  return block->buffer + bytes_committed;
+}
+
+// Releases writer_lock and increments committed bytes by 'bytes_written'.
+// 'bytes_written' must be <= 'size' specified in the corresponding
+// StartWrite() call. This function is thread-safe.
+static void cl_block_end_write(cl_block* block, size_t bytes_written) {
+  cl_block_set_bytes_committed(
+      block, cl_block_get_bytes_committed(block) + bytes_written);
+  cl_unlock(&block->writer_lock);
+}
+
+// Returns a pointer to the first unread byte in buffer. The number of bytes
+// available are returned in 'bytes_available'. Acquires reader lock that is
+// released by a subsequent cl_block_end_read() call. Returns NULL if:
+// - read in progress
+// - no data available
+static void* cl_block_start_read(cl_block* block, size_t* bytes_available) {
+  if (!cl_try_lock(&block->reader_lock)) {
+    return NULL;
+  }
+  // bytes_committed may change from under us. Use bytes_available to update
+  // bytes_read below.
+  size_t bytes_committed = cl_block_get_bytes_committed(block);
+  GPR_ASSERT(bytes_committed >= block->bytes_read);
+  *bytes_available = bytes_committed - block->bytes_read;
+  if (*bytes_available == 0) {
+    cl_unlock(&block->reader_lock);
+    return NULL;
+  }
+  void* record = block->buffer + block->bytes_read;
+  block->bytes_read += *bytes_available;
+  return record;
+}
+
+static void cl_block_end_read(cl_block* block) {
+  cl_unlock(&block->reader_lock);
+}
+
+// Internal functions operating on g_log
+
+// Allocates a new free block (or recycles an available dirty block if log is
+// configured to discard old records). Returns NULL if out-of-space.
+static cl_block* cl_allocate_block(void) {
+  cl_block* block = cl_block_list_head(&g_log.free_block_list);
+  if (block != NULL) {
+    cl_block_list_remove(&g_log.free_block_list, block);
+    return block;
+  }
+  if (!g_log.discard_old_records) {
+    // No free block and log is configured to keep old records.
+    return NULL;
+  }
+  // Recycle dirty block. Start from the oldest.
+  for (block = cl_block_list_head(&g_log.dirty_block_list); block != NULL;
+       block = block->link.next->block) {
+    if (cl_block_try_disable_access(block, 1 /* discard data */)) {
+      cl_block_list_remove(&g_log.dirty_block_list, block);
+      return block;
+    }
+  }
+  return NULL;
+}
+
+// Allocates a new block and updates core id => block mapping. 'old_block'
+// points to the block that the caller thinks is attached to
+// 'core_id'. 'old_block' may be NULL. Returns true if:
+// - allocated a new block OR
+// - 'core_id' => 'old_block' mapping changed (another thread allocated a
+//   block before lock was acquired).
+static bool cl_allocate_core_local_block(uint32_t core_id,
+                                         cl_block* old_block) {
+  // Now that we have the lock, check if core-local mapping has changed.
+  cl_core_local_block* core_local_block = &g_log.core_local_blocks[core_id];
+  cl_block* block = cl_core_local_block_get_block(core_local_block);
+  if ((block != NULL) && (block != old_block)) {
+    return true;
+  }
+  if (block != NULL) {
+    cl_core_local_block_set_block(core_local_block, NULL);
+    cl_block_list_insert_at_tail(&g_log.dirty_block_list, block);
+  }
+  block = cl_allocate_block();
+  if (block == NULL) {
+    return false;
+  }
+  cl_core_local_block_set_block(core_local_block, block);
+  cl_block_enable_access(block);
+  return true;
+}
+
+static cl_block* cl_get_block(void* record) {
+  uintptr_t p = (uintptr_t)((char*)record - g_log.buffer);
+  uintptr_t index = p >> CENSUS_LOG_2_MAX_RECORD_SIZE;
+  return &g_log.blocks[index];
+}
+
+// Gets the next block to read and tries to free 'prev' block (if not NULL).
+// Returns NULL if reached the end.
+static cl_block* cl_next_block_to_read(cl_block* prev) {
+  cl_block* block = NULL;
+  if (g_log.read_iterator_state == g_log.num_cores) {
+    // We are traversing dirty list; find the next dirty block.
+    if (prev != NULL) {
+      // Try to free the previous block if there is no unread data. This
+      // block
+      // may have unread data if previously incomplete record completed
+      // between
+      // read_next() calls.
+      block = prev->link.next->block;
+      if (cl_block_try_disable_access(prev, 0 /* do not discard data */)) {
+        cl_block_list_remove(&g_log.dirty_block_list, prev);
+        cl_block_list_insert_at_head(&g_log.free_block_list, prev);
+      }
+    } else {
+      block = cl_block_list_head(&g_log.dirty_block_list);
+    }
+    if (block != NULL) {
+      return block;
+    }
+    // We are done with the dirty list; moving on to core-local blocks.
+  }
+  while (g_log.read_iterator_state > 0) {
+    g_log.read_iterator_state--;
+    block = cl_core_local_block_get_block(
+        &g_log.core_local_blocks[g_log.read_iterator_state]);
+    if (block != NULL) {
+      return block;
+    }
+  }
+  return NULL;
+}
+
+#define CL_LOG_2_MB 20  // 2^20 = 1MB
+
+// External functions: primary stats_log interface
+void census_log_initialize(size_t size_in_mb, int discard_old_records) {
+  // Check cacheline alignment.
+  GPR_ASSERT(sizeof(cl_block) % GPR_CACHELINE_SIZE == 0);
+  GPR_ASSERT(sizeof(cl_core_local_block) % GPR_CACHELINE_SIZE == 0);
+  GPR_ASSERT(!g_log.initialized);
+  g_log.discard_old_records = discard_old_records;
+  g_log.num_cores = gpr_cpu_num_cores();
+  // Ensure that we will not get any overflow in calaculating num_blocks
+  GPR_ASSERT(CL_LOG_2_MB >= CENSUS_LOG_2_MAX_RECORD_SIZE);
+  GPR_ASSERT(size_in_mb < 1000);
+  // Ensure at least 2x as many blocks as there are cores.
+  g_log.num_blocks =
+      (uint32_t)GPR_MAX(2 * g_log.num_cores, (size_in_mb << CL_LOG_2_MB) >>
+                                                 CENSUS_LOG_2_MAX_RECORD_SIZE);
+  gpr_mu_init(&g_log.lock);
+  g_log.read_iterator_state = 0;
+  g_log.block_being_read = NULL;
+  g_log.core_local_blocks = (cl_core_local_block*)gpr_malloc_aligned(
+      g_log.num_cores * sizeof(cl_core_local_block), GPR_CACHELINE_SIZE_LOG);
+  memset(g_log.core_local_blocks, 0,
+         g_log.num_cores * sizeof(cl_core_local_block));
+  g_log.blocks = (cl_block*)gpr_malloc_aligned(
+      g_log.num_blocks * sizeof(cl_block), GPR_CACHELINE_SIZE_LOG);
+  memset(g_log.blocks, 0, g_log.num_blocks * sizeof(cl_block));
+  g_log.buffer = gpr_malloc(g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE);
+  memset(g_log.buffer, 0, g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE);
+  cl_block_list_initialize(&g_log.free_block_list);
+  cl_block_list_initialize(&g_log.dirty_block_list);
+  for (uint32_t i = 0; i < g_log.num_blocks; ++i) {
+    cl_block* block = g_log.blocks + i;
+    cl_block_initialize(block, g_log.buffer + (CENSUS_LOG_MAX_RECORD_SIZE * i));
+    cl_block_try_disable_access(block, 1 /* discard data */);
+    cl_block_list_insert_at_tail(&g_log.free_block_list, block);
+  }
+  gpr_atm_rel_store(&g_log.out_of_space_count, 0);
+  g_log.initialized = 1;
+}
+
+void census_log_shutdown(void) {
+  GPR_ASSERT(g_log.initialized);
+  gpr_mu_destroy(&g_log.lock);
+  gpr_free_aligned(g_log.core_local_blocks);
+  g_log.core_local_blocks = NULL;
+  gpr_free_aligned(g_log.blocks);
+  g_log.blocks = NULL;
+  gpr_free(g_log.buffer);
+  g_log.buffer = NULL;
+  g_log.initialized = 0;
+}
+
+void* census_log_start_write(size_t size) {
+  // Used to bound number of times block allocation is attempted.
+  GPR_ASSERT(size > 0);
+  GPR_ASSERT(g_log.initialized);
+  if (size > CENSUS_LOG_MAX_RECORD_SIZE) {
+    return NULL;
+  }
+  uint32_t attempts_remaining = g_log.num_blocks;
+  uint32_t core_id = gpr_cpu_current_cpu();
+  do {
+    void* record = NULL;
+    cl_block* block =
+        cl_core_local_block_get_block(&g_log.core_local_blocks[core_id]);
+    if (block && (record = cl_block_start_write(block, size))) {
+      return record;
+    }
+    // Need to allocate a new block. We are here if:
+    // - No block associated with the core OR
+    // - Write in-progress on the block OR
+    // - block is out of space
+    gpr_mu_lock(&g_log.lock);
+    bool allocated = cl_allocate_core_local_block(core_id, block);
+    gpr_mu_unlock(&g_log.lock);
+    if (!allocated) {
+      gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
+      return NULL;
+    }
+  } while (attempts_remaining--);
+  // Give up.
+  gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
+  return NULL;
+}
+
+void census_log_end_write(void* record, size_t bytes_written) {
+  GPR_ASSERT(g_log.initialized);
+  cl_block_end_write(cl_get_block(record), bytes_written);
+}
+
+void census_log_init_reader(void) {
+  GPR_ASSERT(g_log.initialized);
+  gpr_mu_lock(&g_log.lock);
+  // If a block is locked for reading unlock it.
+  if (g_log.block_being_read != NULL) {
+    cl_block_end_read(g_log.block_being_read);
+    g_log.block_being_read = NULL;
+  }
+  g_log.read_iterator_state = g_log.num_cores;
+  gpr_mu_unlock(&g_log.lock);
+}
+
+const void* census_log_read_next(size_t* bytes_available) {
+  GPR_ASSERT(g_log.initialized);
+  gpr_mu_lock(&g_log.lock);
+  if (g_log.block_being_read != NULL) {
+    cl_block_end_read(g_log.block_being_read);
+  }
+  do {
+    g_log.block_being_read = cl_next_block_to_read(g_log.block_being_read);
+    if (g_log.block_being_read != NULL) {
+      void* record =
+          cl_block_start_read(g_log.block_being_read, bytes_available);
+      if (record != NULL) {
+        gpr_mu_unlock(&g_log.lock);
+        return record;
+      }
+    }
+  } while (g_log.block_being_read != NULL);
+  gpr_mu_unlock(&g_log.lock);
+  return NULL;
+}
+
+size_t census_log_remaining_space(void) {
+  GPR_ASSERT(g_log.initialized);
+  size_t space = 0;
+  gpr_mu_lock(&g_log.lock);
+  if (g_log.discard_old_records) {
+    // Remaining space is not meaningful; just return the entire log space.
+    space = g_log.num_blocks << CENSUS_LOG_2_MAX_RECORD_SIZE;
+  } else {
+    GPR_ASSERT(g_log.free_block_list.count >= 0);
+    space = (size_t)g_log.free_block_list.count * CENSUS_LOG_MAX_RECORD_SIZE;
+  }
+  gpr_mu_unlock(&g_log.lock);
+  return space;
+}
+
+int64_t census_log_out_of_space_count(void) {
+  GPR_ASSERT(g_log.initialized);
+  return gpr_atm_acq_load(&g_log.out_of_space_count);
+}
diff --git a/src/core/lib/census/mlog.h b/src/core/lib/census/mlog.h
new file mode 100644
index 0000000..7fbdeda
--- /dev/null
+++ b/src/core/lib/census/mlog.h
@@ -0,0 +1,95 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* A very fast in-memory log, optimized for multiple writers. */
+
+#ifndef GRPC_CORE_LIB_CENSUS_MLOG_H
+#define GRPC_CORE_LIB_CENSUS_MLOG_H
+
+#include <grpc/support/port_platform.h>
+#include <stddef.h>
+
+/* Maximum record size, in bytes. */
+#define CENSUS_LOG_2_MAX_RECORD_SIZE 14 /* 2^14 = 16KB */
+#define CENSUS_LOG_MAX_RECORD_SIZE (1 << CENSUS_LOG_2_MAX_RECORD_SIZE)
+
+/* Initialize the statistics logging subsystem with the given log size. A log
+   size of 0 will result in the smallest possible log for the platform
+   (approximately CENSUS_LOG_MAX_RECORD_SIZE * gpr_cpu_num_cores()). If
+   discard_old_records is non-zero, then new records will displace older ones
+   when the log is full. This function must be called before any other
+   census_log functions.
+*/
+void census_log_initialize(size_t size_in_mb, int discard_old_records);
+
+/* Shutdown the logging subsystem. Caller must ensure that:
+   - no in progress or future call to any census_log functions
+   - no incomplete records
+*/
+void census_log_shutdown(void);
+
+/* Allocates and returns a 'size' bytes record and marks it in use. A
+   subsequent census_log_end_write() marks the record complete. The
+   'bytes_written' census_log_end_write() argument must be <=
+   'size'. Returns NULL if out-of-space AND:
+       - log is configured to keep old records OR
+       - all blocks are pinned by incomplete records.
+*/
+void* census_log_start_write(size_t size);
+
+void census_log_end_write(void* record, size_t bytes_written);
+
+void census_log_init_reader(void);
+
+/* census_log_read_next() iterates over blocks with data and for each block
+   returns a pointer to the first unread byte. The number of bytes that can be
+   read are returned in 'bytes_available'. Reader is expected to read all
+   available data. Reading the data consumes it i.e. it cannot be read again.
+   census_log_read_next() returns NULL if the end is reached i.e last block
+   is read. census_log_init_reader() starts the iteration or aborts the
+   current iteration.
+*/
+const void* census_log_read_next(size_t* bytes_available);
+
+/* Returns estimated remaining space across all blocks, in bytes. If log is
+   configured to discard old records, returns total log space. Otherwise,
+   returns space available in empty blocks (partially filled blocks are
+   treated as full).
+*/
+size_t census_log_remaining_space(void);
+
+/* Returns the number of times gprc_stats_log_start_write() failed due to
+   out-of-space. */
+int64_t census_log_out_of_space_count(void);
+
+#endif /* GRPC_CORE_LIB_CENSUS_MLOG_H */
diff --git a/src/core/lib/census/operation.c b/src/core/lib/census/operation.c
new file mode 100644
index 0000000..315f9c3
--- /dev/null
+++ b/src/core/lib/census/operation.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/census.h>
+
+/* TODO(aveitch): These are all placeholder implementations. */
+
+census_timestamp census_start_rpc_op_timestamp(void) {
+  census_timestamp ct;
+  /* TODO(aveitch): assumes gpr_timespec implementation of census_timestamp. */
+  ct.ts = gpr_now(GPR_CLOCK_MONOTONIC);
+  return ct;
+}
+
+census_context *census_start_client_rpc_op(
+    const census_context *context, int64_t rpc_name_id,
+    const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask,
+    const census_timestamp *start_time) {
+  return NULL;
+}
+
+census_context *census_start_server_rpc_op(
+    const char *buffer, int64_t rpc_name_id,
+    const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask,
+    census_timestamp *start_time) {
+  return NULL;
+}
+
+census_context *census_start_op(census_context *context, const char *family,
+                                const char *name, int trace_mask) {
+  return NULL;
+}
+
+void census_end_op(census_context *context, int status) {}
diff --git a/src/core/census/placeholders.c b/src/core/lib/census/placeholders.c
similarity index 100%
rename from src/core/census/placeholders.c
rename to src/core/lib/census/placeholders.c
diff --git a/src/core/lib/census/rpc_metric_id.h b/src/core/lib/census/rpc_metric_id.h
new file mode 100644
index 0000000..aad0588
--- /dev/null
+++ b/src/core/lib/census/rpc_metric_id.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CENSUS_RPC_METRIC_ID_H
+#define GRPC_CORE_LIB_CENSUS_RPC_METRIC_ID_H
+
+/* Metric ID's used for RPC measurements. */
+/* Count of client requests sent. */
+#define CENSUS_METRIC_RPC_CLIENT_REQUESTS ((uint32_t)0)
+/* Count of server requests sent. */
+#define CENSUS_METRIC_RPC_SERVER_REQUESTS ((uint32_t)1)
+/* Client error counts. */
+#define CENSUS_METRIC_RPC_CLIENT_ERRORS ((uint32_t)2)
+/* Server error counts. */
+#define CENSUS_METRIC_RPC_SERVER_ERRORS ((uint32_t)3)
+/* Client side request latency. */
+#define CENSUS_METRIC_RPC_CLIENT_LATENCY ((uint32_t)4)
+/* Server side request latency. */
+#define CENSUS_METRIC_RPC_SERVER_LATENCY ((uint32_t)5)
+
+#endif /* GRPC_CORE_LIB_CENSUS_RPC_METRIC_ID_H */
diff --git a/src/core/lib/census/tracing.c b/src/core/lib/census/tracing.c
new file mode 100644
index 0000000..e508996
--- /dev/null
+++ b/src/core/lib/census/tracing.c
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/census.h>
+
+/* TODO(aveitch): These are all placeholder implementations. */
+
+int census_trace_mask(const census_context *context) {
+  return CENSUS_TRACE_MASK_NONE;
+}
+
+void census_set_trace_mask(int trace_mask) {}
+
+void census_trace_print(census_context *context, uint32_t type,
+                        const char *buffer, size_t n) {}
diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c
new file mode 100644
index 0000000..1a02f1f
--- /dev/null
+++ b/src/core/lib/channel/channel_args.c
@@ -0,0 +1,271 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/channel/channel_args.h"
+#include <grpc/grpc.h>
+#include "src/core/lib/support/string.h"
+
+#include <grpc/census.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+
+#include <string.h>
+
+static grpc_arg copy_arg(const grpc_arg *src) {
+  grpc_arg dst;
+  dst.type = src->type;
+  dst.key = gpr_strdup(src->key);
+  switch (dst.type) {
+    case GRPC_ARG_STRING:
+      dst.value.string = gpr_strdup(src->value.string);
+      break;
+    case GRPC_ARG_INTEGER:
+      dst.value.integer = src->value.integer;
+      break;
+    case GRPC_ARG_POINTER:
+      dst.value.pointer = src->value.pointer;
+      dst.value.pointer.p =
+          src->value.pointer.vtable->copy(src->value.pointer.p);
+      break;
+  }
+  return dst;
+}
+
+grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
+                                                  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;
+  if (!src && !to_add) {
+    dst->num_args = 0;
+    dst->args = NULL;
+    return dst;
+  }
+  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]);
+  }
+  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, 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);
+}
+
+static int cmp_arg(const grpc_arg *a, const grpc_arg *b) {
+  int c = GPR_ICMP(a->type, b->type);
+  if (c != 0) return c;
+  c = strcmp(a->key, b->key);
+  if (c != 0) return c;
+  switch (a->type) {
+    case GRPC_ARG_STRING:
+      return strcmp(a->value.string, b->value.string);
+    case GRPC_ARG_INTEGER:
+      return GPR_ICMP(a->value.integer, b->value.integer);
+    case GRPC_ARG_POINTER:
+      c = GPR_ICMP(a->value.pointer.p, b->value.pointer.p);
+      if (c != 0) {
+        c = GPR_ICMP(a->value.pointer.vtable, b->value.pointer.vtable);
+        if (c == 0) {
+          c = a->value.pointer.vtable->cmp(a->value.pointer.p,
+                                           b->value.pointer.p);
+        }
+      }
+      return c;
+  }
+  GPR_UNREACHABLE_CODE(return 0);
+}
+
+/* stabilizing comparison function: since channel_args ordering matters for
+ * keys with the same name, we need to preserve that ordering */
+static int cmp_key_stable(const void *ap, const void *bp) {
+  const grpc_arg *const *a = ap;
+  const grpc_arg *const *b = bp;
+  int c = strcmp((*a)->key, (*b)->key);
+  if (c == 0) c = GPR_ICMP(*a, *b);
+  return c;
+}
+
+grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a) {
+  grpc_arg **args = gpr_malloc(sizeof(grpc_arg *) * a->num_args);
+  for (size_t i = 0; i < a->num_args; i++) {
+    args[i] = &a->args[i];
+  }
+  qsort(args, a->num_args, sizeof(grpc_arg *), cmp_key_stable);
+
+  grpc_channel_args *b = gpr_malloc(sizeof(grpc_channel_args));
+  b->num_args = a->num_args;
+  b->args = gpr_malloc(sizeof(grpc_arg) * b->num_args);
+  for (size_t i = 0; i < a->num_args; i++) {
+    b->args[i] = copy_arg(args[i]);
+  }
+
+  gpr_free(args);
+  return b;
+}
+
+void grpc_channel_args_destroy(grpc_channel_args *a) {
+  size_t i;
+  for (i = 0; i < a->num_args; i++) {
+    switch (a->args[i].type) {
+      case GRPC_ARG_STRING:
+        gpr_free(a->args[i].value.string);
+        break;
+      case GRPC_ARG_INTEGER:
+        break;
+      case GRPC_ARG_POINTER:
+        a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p);
+        break;
+    }
+    gpr_free(a->args[i].key);
+  }
+  gpr_free(a->args);
+  gpr_free(a);
+}
+
+int grpc_channel_args_is_census_enabled(const grpc_channel_args *a) {
+  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)) {
+      return a->args[i].value.integer != 0 && census_enabled();
+    }
+  }
+  return census_enabled();
+}
+
+grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
+    const grpc_channel_args *a) {
+  size_t i;
+  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 (grpc_compression_algorithm)a->args[i].value.integer;
+      break;
+    }
+  }
+  return GRPC_COMPRESS_NONE;
+}
+
+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_ALGORITHM_ARG;
+  tmp.value.integer = algorithm;
+  return grpc_channel_args_copy_and_add(a, &tmp, 1);
+}
+
+/** Returns 1 if the argument for compression algorithm's enabled states bitset
+ * was found in \a a, returning the arg's value in \a states. Otherwise, returns
+ * 0. */
+static int find_compression_algorithm_states_bitset(const grpc_channel_args *a,
+                                                    int **states_arg) {
+  if (a != NULL) {
+    size_t i;
+    for (i = 0; i < a->num_args; ++i) {
+      if (a->args[i].type == GRPC_ARG_INTEGER &&
+          !strcmp(GRPC_COMPRESSION_ALGORITHM_STATE_ARG, a->args[i].key)) {
+        *states_arg = &a->args[i].value.integer;
+        return 1; /* GPR_TRUE */
+      }
+    }
+  }
+  return 0; /* GPR_FALSE */
+}
+
+grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
+    grpc_channel_args **a, grpc_compression_algorithm algorithm, int state) {
+  int *states_arg;
+  grpc_channel_args *result = *a;
+  const int states_arg_found =
+      find_compression_algorithm_states_bitset(*a, &states_arg);
+
+  if (states_arg_found) {
+    if (state != 0) {
+      GPR_BITSET((unsigned *)states_arg, algorithm);
+    } else {
+      GPR_BITCLEAR((unsigned *)states_arg, algorithm);
+    }
+  } else {
+    /* create a new arg */
+    grpc_arg tmp;
+    tmp.type = GRPC_ARG_INTEGER;
+    tmp.key = GRPC_COMPRESSION_ALGORITHM_STATE_ARG;
+    /* all enabled by default */
+    tmp.value.integer = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
+    if (state != 0) {
+      GPR_BITSET((unsigned *)&tmp.value.integer, algorithm);
+    } else {
+      GPR_BITCLEAR((unsigned *)&tmp.value.integer, algorithm);
+    }
+    result = grpc_channel_args_copy_and_add(*a, &tmp, 1);
+    grpc_channel_args_destroy(*a);
+    *a = result;
+  }
+  return result;
+}
+
+int grpc_channel_args_compression_algorithm_get_states(
+    const grpc_channel_args *a) {
+  int *states_arg;
+  if (find_compression_algorithm_states_bitset(a, &states_arg)) {
+    return *states_arg;
+  } else {
+    return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */
+  }
+}
+
+int grpc_channel_args_compare(const grpc_channel_args *a,
+                              const grpc_channel_args *b) {
+  int c = GPR_ICMP(a->num_args, b->num_args);
+  if (c != 0) return c;
+  for (size_t i = 0; i < a->num_args; i++) {
+    c = cmp_arg(&a->args[i], &b->args[i]);
+    if (c != 0) return c;
+  }
+  return 0;
+}
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
new file mode 100644
index 0000000..1ea202c
--- /dev/null
+++ b/src/core/lib/channel/channel_args.h
@@ -0,0 +1,94 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_CHANNEL_ARGS_H
+#define GRPC_CORE_LIB_CHANNEL_CHANNEL_ARGS_H
+
+#include <grpc/compression.h>
+#include <grpc/grpc.h>
+
+/** Copy the arguments in \a src into a new instance */
+grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src);
+
+/** Copy the arguments in \a src into a new instance, stably sorting keys */
+grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *src);
+
+/** Copy the arguments in \a src and append \a to_add. If \a to_add is NULL, it
+ * is equivalent to calling \a grpc_channel_args_copy. */
+grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src,
+                                                  const grpc_arg *to_add,
+                                                  size_t num_to_add);
+
+/** Concatenate args from \a a and \a b into a new instance */
+grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a,
+                                           const grpc_channel_args *b);
+
+/** Destroy arguments created by \a grpc_channel_args_copy */
+void grpc_channel_args_destroy(grpc_channel_args *a);
+
+/** Reads census_enabled settings from channel args. Returns 1 if census_enabled
+ * is specified in channel args, otherwise returns 0. */
+int grpc_channel_args_is_census_enabled(const grpc_channel_args *a);
+
+/** Returns the compression algorithm set in \a a. */
+grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
+    const grpc_channel_args *a);
+
+/** 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);
+
+/** Sets the support for the given compression algorithm. By default, all
+ * compression algorithms are enabled. It's an error to disable an algorithm set
+ * by grpc_channel_args_set_compression_algorithm.
+ *
+ * Returns an instance with the updated algorithm states. The \a a pointer is
+ * modified to point to the returned instance (which may be different from the
+ * input value of \a a). */
+grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
+    grpc_channel_args **a, grpc_compression_algorithm algorithm, int enabled);
+
+/** Returns the bitset representing the support state (true for enabled, false
+ * for disabled) for compression algorithms.
+ *
+ * The i-th bit of the returned bitset corresponds to the i-th entry in the
+ * grpc_compression_algorithm enum. */
+int grpc_channel_args_compression_algorithm_get_states(
+    const grpc_channel_args *a);
+
+int grpc_channel_args_compare(const grpc_channel_args *a,
+                              const grpc_channel_args *b);
+
+#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_ARGS_H */
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
new file mode 100644
index 0000000..52283e3
--- /dev/null
+++ b/src/core/lib/channel/channel_stack.c
@@ -0,0 +1,262 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/channel/channel_stack.h"
+#include <grpc/support/log.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+int grpc_trace_channel = 0;
+
+/* Memory layouts.
+
+   Channel stack is laid out as: {
+     grpc_channel_stack stk;
+     padding to GPR_MAX_ALIGNMENT
+     grpc_channel_element[stk.count];
+     per-filter memory, aligned to GPR_MAX_ALIGNMENT
+   }
+
+   Call stack is laid out as: {
+     grpc_call_stack stk;
+     padding to GPR_MAX_ALIGNMENT
+     grpc_call_element[stk.count];
+     per-filter memory, aligned to GPR_MAX_ALIGNMENT
+   } */
+
+/* Given a size, round up to the next multiple of sizeof(void*) */
+#define ROUND_UP_TO_ALIGNMENT_SIZE(x) \
+  (((x) + GPR_MAX_ALIGNMENT - 1u) & ~(GPR_MAX_ALIGNMENT - 1u))
+
+size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
+                               size_t filter_count) {
+  /* always need the header, and size for the channel elements */
+  size_t size =
+      ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)) +
+      ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element));
+  size_t i;
+
+  GPR_ASSERT((GPR_MAX_ALIGNMENT & (GPR_MAX_ALIGNMENT - 1)) == 0 &&
+             "GPR_MAX_ALIGNMENT must be a power of two");
+
+  /* add the size for each filter */
+  for (i = 0; i < filter_count; i++) {
+    size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
+  }
+
+  return size;
+}
+
+#define CHANNEL_ELEMS_FROM_STACK(stk)                                   \
+  ((grpc_channel_element *)((char *)(stk) + ROUND_UP_TO_ALIGNMENT_SIZE( \
+                                                sizeof(grpc_channel_stack))))
+
+#define CALL_ELEMS_FROM_STACK(stk)       \
+  ((grpc_call_element *)((char *)(stk) + \
+                         ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack))))
+
+grpc_channel_element *grpc_channel_stack_element(
+    grpc_channel_stack *channel_stack, size_t index) {
+  return CHANNEL_ELEMS_FROM_STACK(channel_stack) + index;
+}
+
+grpc_channel_element *grpc_channel_stack_last_element(
+    grpc_channel_stack *channel_stack) {
+  return grpc_channel_stack_element(channel_stack, channel_stack->count - 1);
+}
+
+grpc_call_element *grpc_call_stack_element(grpc_call_stack *call_stack,
+                                           size_t index) {
+  return CALL_ELEMS_FROM_STACK(call_stack) + index;
+}
+
+void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
+                             grpc_iomgr_cb_func destroy, void *destroy_arg,
+                             const grpc_channel_filter **filters,
+                             size_t filter_count,
+                             const grpc_channel_args *channel_args,
+                             const char *name, grpc_channel_stack *stack) {
+  size_t call_size =
+      ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
+      ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element));
+  grpc_channel_element *elems;
+  grpc_channel_element_args args;
+  char *user_data;
+  size_t i;
+
+  stack->count = filter_count;
+  GRPC_STREAM_REF_INIT(&stack->refcount, initial_refs, destroy, destroy_arg,
+                       name);
+  elems = CHANNEL_ELEMS_FROM_STACK(stack);
+  user_data =
+      ((char *)elems) +
+      ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element));
+
+  /* init per-filter data */
+  for (i = 0; i < filter_count; i++) {
+    args.channel_stack = stack;
+    args.channel_args = channel_args;
+    args.is_first = i == 0;
+    args.is_last = i == (filter_count - 1);
+    elems[i].filter = filters[i];
+    elems[i].channel_data = user_data;
+    elems[i].filter->init_channel_elem(exec_ctx, &elems[i], &args);
+    user_data += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
+    call_size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_call_data);
+  }
+
+  GPR_ASSERT(user_data > (char *)stack);
+  GPR_ASSERT((uintptr_t)(user_data - (char *)stack) ==
+             grpc_channel_stack_size(filters, filter_count));
+
+  stack->call_stack_size = call_size;
+}
+
+void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
+                                grpc_channel_stack *stack) {
+  grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(stack);
+  size_t count = stack->count;
+  size_t i;
+
+  /* destroy per-filter data */
+  for (i = 0; i < count; i++) {
+    channel_elems[i].filter->destroy_channel_elem(exec_ctx, &channel_elems[i]);
+  }
+}
+
+void grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
+                          grpc_channel_stack *channel_stack, int initial_refs,
+                          grpc_iomgr_cb_func destroy, void *destroy_arg,
+                          grpc_call_context_element *context,
+                          const void *transport_server_data,
+                          grpc_call_stack *call_stack) {
+  grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
+  grpc_call_element_args args;
+  size_t count = channel_stack->count;
+  grpc_call_element *call_elems;
+  char *user_data;
+  size_t i;
+
+  call_stack->count = count;
+  GRPC_STREAM_REF_INIT(&call_stack->refcount, initial_refs, destroy,
+                       destroy_arg, "CALL_STACK");
+  call_elems = CALL_ELEMS_FROM_STACK(call_stack);
+  user_data = ((char *)call_elems) +
+              ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
+
+  /* init per-filter data */
+  for (i = 0; i < count; i++) {
+    args.call_stack = call_stack;
+    args.server_transport_data = transport_server_data;
+    args.context = context;
+    call_elems[i].filter = channel_elems[i].filter;
+    call_elems[i].channel_data = channel_elems[i].channel_data;
+    call_elems[i].call_data = user_data;
+    call_elems[i].filter->init_call_elem(exec_ctx, &call_elems[i], &args);
+    user_data +=
+        ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
+  }
+}
+
+void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx,
+                                 grpc_call_stack *call_stack,
+                                 grpc_pollset *pollset) {
+  size_t count = call_stack->count;
+  grpc_call_element *call_elems;
+  char *user_data;
+  size_t i;
+
+  call_elems = CALL_ELEMS_FROM_STACK(call_stack);
+  user_data = ((char *)call_elems) +
+              ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
+
+  /* init per-filter data */
+  for (i = 0; i < count; i++) {
+    call_elems[i].filter->set_pollset(exec_ctx, &call_elems[i], pollset);
+    user_data +=
+        ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
+  }
+}
+
+void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx,
+                                        grpc_call_element *elem,
+                                        grpc_pollset *pollset) {}
+
+void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack) {
+  grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack);
+  size_t count = stack->count;
+  size_t i;
+
+  /* destroy per-filter data */
+  for (i = 0; i < count; i++) {
+    elems[i].filter->destroy_call_elem(exec_ctx, &elems[i]);
+  }
+}
+
+void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                       grpc_transport_stream_op *op) {
+  grpc_call_element *next_elem = elem + 1;
+  next_elem->filter->start_transport_stream_op(exec_ctx, next_elem, op);
+}
+
+char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx,
+                              grpc_call_element *elem) {
+  grpc_call_element *next_elem = elem + 1;
+  return next_elem->filter->get_peer(exec_ctx, next_elem);
+}
+
+void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
+                          grpc_transport_op *op) {
+  grpc_channel_element *next_elem = elem + 1;
+  next_elem->filter->start_transport_op(exec_ctx, next_elem, op);
+}
+
+grpc_channel_stack *grpc_channel_stack_from_top_element(
+    grpc_channel_element *elem) {
+  return (grpc_channel_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE(
+      sizeof(grpc_channel_stack)));
+}
+
+grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) {
+  return (grpc_call_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE(
+      sizeof(grpc_call_stack)));
+}
+
+void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx,
+                                   grpc_call_element *cur_elem) {
+  grpc_transport_stream_op op;
+  memset(&op, 0, sizeof(op));
+  op.cancel_with_status = GRPC_STATUS_CANCELLED;
+  grpc_call_next_op(exec_ctx, cur_elem, &op);
+}
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
new file mode 100644
index 0000000..b29bee4
--- /dev/null
+++ b/src/core/lib/channel/channel_stack.h
@@ -0,0 +1,260 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_H
+#define GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_H
+
+/* A channel filter defines how operations on a channel are implemented.
+   Channel filters are chained together to create full channels, and if those
+   chains are linear, then channel stacks provide a mechanism to minimize
+   allocations for that chain.
+   Call stacks are created by channel stacks and represent the per-call data
+   for that stack. */
+
+#include <stddef.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/transport/transport.h"
+
+typedef struct grpc_channel_element grpc_channel_element;
+typedef struct grpc_call_element grpc_call_element;
+
+typedef struct grpc_channel_stack grpc_channel_stack;
+typedef struct grpc_call_stack grpc_call_stack;
+
+typedef struct {
+  grpc_channel_stack *channel_stack;
+  const grpc_channel_args *channel_args;
+  int is_first;
+  int is_last;
+} grpc_channel_element_args;
+
+typedef struct {
+  grpc_call_stack *call_stack;
+  const void *server_transport_data;
+  grpc_call_context_element *context;
+} grpc_call_element_args;
+
+/* Channel filters specify:
+   1. the amount of memory needed in the channel & call (via the sizeof_XXX
+      members)
+   2. functions to initialize and destroy channel & call data
+      (init_XXX, destroy_XXX)
+   3. functions to implement call operations and channel operations (call_op,
+      channel_op)
+   4. a name, which is useful when debugging
+
+   Members are laid out in approximate frequency of use order. */
+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_stream_op)(grpc_exec_ctx *exec_ctx,
+                                    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 (*start_transport_op)(grpc_exec_ctx *exec_ctx,
+                             grpc_channel_element *elem, grpc_transport_op *op);
+
+  /* sizeof(per call data) */
+  size_t sizeof_call_data;
+  /* Initialize per call data.
+     elem is initialized at the start of the call, and elem->call_data is what
+     needs initializing.
+     The filter does not need to do any chaining.
+     server_transport_data is an opaque pointer. If it is NULL, this call is
+     on a client; if it is non-NULL, then it points to memory owned by the
+     transport and is on the server. Most filters want to ignore this
+     argument. */
+  void (*init_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                         grpc_call_element_args *args);
+  void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                      grpc_pollset *pollset);
+  /* Destroy per call data.
+     The filter does not need to do any chaining */
+  void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
+
+  /* sizeof(per channel data) */
+  size_t sizeof_channel_data;
+  /* Initialize per-channel data.
+     elem is initialized at the start of the call, and elem->channel_data is
+     what needs initializing.
+     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_exec_ctx *exec_ctx, grpc_channel_element *elem,
+                            grpc_channel_element_args *args);
+  /* Destroy per channel data.
+     The filter does not need to do any chaining */
+  void (*destroy_channel_elem)(grpc_exec_ctx *exec_ctx,
+                               grpc_channel_element *elem);
+
+  /* Implement grpc_call_get_peer() */
+  char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
+
+  /* The name of this filter */
+  const char *name;
+} grpc_channel_filter;
+
+/* A channel_element tracks its filter and the filter requested memory within
+   a channel allocation */
+struct grpc_channel_element {
+  const grpc_channel_filter *filter;
+  void *channel_data;
+};
+
+/* A call_element tracks its filter, the filter requested memory within
+   a channel allocation, and the filter requested memory within a call
+   allocation */
+struct grpc_call_element {
+  const grpc_channel_filter *filter;
+  void *channel_data;
+  void *call_data;
+};
+
+/* A channel stack tracks a set of related filters for one channel, and
+   guarantees they live within a single malloc() allocation */
+struct grpc_channel_stack {
+  grpc_stream_refcount refcount;
+  size_t count;
+  /* Memory required for a call stack (computed at channel stack
+     initialization) */
+  size_t call_stack_size;
+};
+
+/* A call stack tracks a set of related filters for one call, and guarantees
+   they live within a single malloc() allocation */
+struct grpc_call_stack {
+  /* shared refcount for this channel stack.
+     MUST be the first element: the underlying code calls destroy
+     with the address of the refcount, but higher layers prefer to think
+     about the address of the call stack itself. */
+  grpc_stream_refcount refcount;
+  size_t count;
+};
+
+/* Get a channel element given a channel stack and its index */
+grpc_channel_element *grpc_channel_stack_element(grpc_channel_stack *stack,
+                                                 size_t i);
+/* Get the last channel element in a channel stack */
+grpc_channel_element *grpc_channel_stack_last_element(
+    grpc_channel_stack *stack);
+/* Get a call stack element given a call stack and an index */
+grpc_call_element *grpc_call_stack_element(grpc_call_stack *stack, size_t i);
+
+/* Determine memory required for a channel stack containing a set of filters */
+size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
+                               size_t filter_count);
+/* Initialize a channel stack given some filters */
+void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
+                             grpc_iomgr_cb_func destroy, void *destroy_arg,
+                             const grpc_channel_filter **filters,
+                             size_t filter_count, const grpc_channel_args *args,
+                             const char *name, grpc_channel_stack *stack);
+/* Destroy a channel stack */
+void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
+                                grpc_channel_stack *stack);
+
+/* Initialize a call stack given a channel stack. transport_server_data is
+   expected to be NULL on a client, or an opaque transport owned pointer on the
+   server. */
+void grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
+                          grpc_channel_stack *channel_stack, int initial_refs,
+                          grpc_iomgr_cb_func destroy, void *destroy_arg,
+                          grpc_call_context_element *context,
+                          const void *transport_server_data,
+                          grpc_call_stack *call_stack);
+/* Set a pollset for a call stack: must occur before the first op is started */
+void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx,
+                                 grpc_call_stack *call_stack,
+                                 grpc_pollset *pollset);
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+#define GRPC_CALL_STACK_REF(call_stack, reason) \
+  grpc_stream_ref(&(call_stack)->refcount, reason)
+#define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \
+  grpc_stream_unref(exec_ctx, &(call_stack)->refcount, reason)
+#define GRPC_CHANNEL_STACK_REF(channel_stack, reason) \
+  grpc_stream_ref(&(channel_stack)->refcount, reason)
+#define GRPC_CHANNEL_STACK_UNREF(exec_ctx, channel_stack, reason) \
+  grpc_stream_unref(exec_ctx, &(channel_stack)->refcount, reason)
+#else
+#define GRPC_CALL_STACK_REF(call_stack, reason) \
+  grpc_stream_ref(&(call_stack)->refcount)
+#define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \
+  grpc_stream_unref(exec_ctx, &(call_stack)->refcount)
+#define GRPC_CHANNEL_STACK_REF(channel_stack, reason) \
+  grpc_stream_ref(&(channel_stack)->refcount)
+#define GRPC_CHANNEL_STACK_UNREF(exec_ctx, channel_stack, reason) \
+  grpc_stream_unref(exec_ctx, &(channel_stack)->refcount)
+#endif
+
+/* Destroy a call stack */
+void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack);
+
+/* Ignore set pollset - used by filters to implement the set_pollset method
+   if they don't care about pollsets at all. Does nothing. */
+void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx,
+                                        grpc_call_element *elem,
+                                        grpc_pollset *pollset);
+/* Call the next operation in a call stack */
+void grpc_call_next_op(grpc_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx, grpc_channel_element *elem,
+                          grpc_transport_op *op);
+/* Pass through a request to get_peer to the next child element */
+char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
+
+/* Given the top element of a channel stack, get the channel stack itself */
+grpc_channel_stack *grpc_channel_stack_from_top_element(
+    grpc_channel_element *elem);
+/* Given the top element of a call stack, get the call stack itself */
+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_stream_op *op);
+
+void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx,
+                                   grpc_call_element *cur_elem);
+
+extern int grpc_trace_channel;
+
+#define GRPC_CALL_LOG_OP(sev, elem, op) \
+  if (grpc_trace_channel) grpc_call_log_op(sev, elem, op)
+
+#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_H */
diff --git a/src/core/lib/channel/channel_stack_builder.c b/src/core/lib/channel/channel_stack_builder.c
new file mode 100644
index 0000000..1ce0c4e
--- /dev/null
+++ b/src/core/lib/channel/channel_stack_builder.c
@@ -0,0 +1,258 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/channel/channel_stack_builder.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+int grpc_trace_channel_stack_builder = 0;
+
+typedef struct filter_node {
+  struct filter_node *next;
+  struct filter_node *prev;
+  const grpc_channel_filter *filter;
+  grpc_post_filter_create_init_func init;
+  void *init_arg;
+} filter_node;
+
+struct grpc_channel_stack_builder {
+  // sentinel nodes for filters that have been added
+  filter_node begin;
+  filter_node end;
+  // various set/get-able parameters
+  const grpc_channel_args *args;
+  grpc_transport *transport;
+  const char *name;
+};
+
+struct grpc_channel_stack_builder_iterator {
+  grpc_channel_stack_builder *builder;
+  filter_node *node;
+};
+
+grpc_channel_stack_builder *grpc_channel_stack_builder_create(void) {
+  grpc_channel_stack_builder *b = gpr_malloc(sizeof(*b));
+  memset(b, 0, sizeof(*b));
+
+  b->begin.filter = NULL;
+  b->end.filter = NULL;
+  b->begin.next = &b->end;
+  b->begin.prev = &b->end;
+  b->end.next = &b->begin;
+  b->end.prev = &b->begin;
+
+  return b;
+}
+
+static grpc_channel_stack_builder_iterator *create_iterator_at_filter_node(
+    grpc_channel_stack_builder *builder, filter_node *node) {
+  grpc_channel_stack_builder_iterator *it = gpr_malloc(sizeof(*it));
+  it->builder = builder;
+  it->node = node;
+  return it;
+}
+
+void grpc_channel_stack_builder_iterator_destroy(
+    grpc_channel_stack_builder_iterator *it) {
+  gpr_free(it);
+}
+
+grpc_channel_stack_builder_iterator *
+grpc_channel_stack_builder_create_iterator_at_first(
+    grpc_channel_stack_builder *builder) {
+  return create_iterator_at_filter_node(builder, &builder->begin);
+}
+
+grpc_channel_stack_builder_iterator *
+grpc_channel_stack_builder_create_iterator_at_last(
+    grpc_channel_stack_builder *builder) {
+  return create_iterator_at_filter_node(builder, &builder->end);
+}
+
+bool grpc_channel_stack_builder_move_next(
+    grpc_channel_stack_builder_iterator *iterator) {
+  if (iterator->node == &iterator->builder->end) return false;
+  iterator->node = iterator->node->next;
+  return true;
+}
+
+bool grpc_channel_stack_builder_move_prev(
+    grpc_channel_stack_builder_iterator *iterator) {
+  if (iterator->node == &iterator->builder->begin) return false;
+  iterator->node = iterator->node->prev;
+  return true;
+}
+
+bool grpc_channel_stack_builder_move_prev(
+    grpc_channel_stack_builder_iterator *iterator);
+
+void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder,
+                                         const char *name) {
+  GPR_ASSERT(builder->name == NULL);
+  builder->name = name;
+}
+
+void grpc_channel_stack_builder_set_channel_arguments(
+    grpc_channel_stack_builder *builder, const grpc_channel_args *args) {
+  GPR_ASSERT(builder->args == NULL);
+  builder->args = args;
+}
+
+void grpc_channel_stack_builder_set_transport(
+    grpc_channel_stack_builder *builder, grpc_transport *transport) {
+  GPR_ASSERT(builder->transport == NULL);
+  builder->transport = transport;
+}
+
+grpc_transport *grpc_channel_stack_builder_get_transport(
+    grpc_channel_stack_builder *builder) {
+  return builder->transport;
+}
+
+const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments(
+    grpc_channel_stack_builder *builder) {
+  return builder->args;
+}
+
+bool grpc_channel_stack_builder_append_filter(
+    grpc_channel_stack_builder *builder, const grpc_channel_filter *filter,
+    grpc_post_filter_create_init_func post_init_func, void *user_data) {
+  grpc_channel_stack_builder_iterator *it =
+      grpc_channel_stack_builder_create_iterator_at_last(builder);
+  bool ok = grpc_channel_stack_builder_add_filter_before(
+      it, filter, post_init_func, user_data);
+  grpc_channel_stack_builder_iterator_destroy(it);
+  return ok;
+}
+
+bool grpc_channel_stack_builder_prepend_filter(
+    grpc_channel_stack_builder *builder, const grpc_channel_filter *filter,
+    grpc_post_filter_create_init_func post_init_func, void *user_data) {
+  grpc_channel_stack_builder_iterator *it =
+      grpc_channel_stack_builder_create_iterator_at_first(builder);
+  bool ok = grpc_channel_stack_builder_add_filter_after(
+      it, filter, post_init_func, user_data);
+  grpc_channel_stack_builder_iterator_destroy(it);
+  return ok;
+}
+
+static void add_after(filter_node *before, const grpc_channel_filter *filter,
+                      grpc_post_filter_create_init_func post_init_func,
+                      void *user_data) {
+  filter_node *new = gpr_malloc(sizeof(*new));
+  new->next = before->next;
+  new->prev = before;
+  new->next->prev = new->prev->next = new;
+  new->filter = filter;
+  new->init = post_init_func;
+  new->init_arg = user_data;
+}
+
+bool grpc_channel_stack_builder_add_filter_before(
+    grpc_channel_stack_builder_iterator *iterator,
+    const grpc_channel_filter *filter,
+    grpc_post_filter_create_init_func post_init_func, void *user_data) {
+  if (iterator->node == &iterator->builder->begin) return false;
+  add_after(iterator->node->prev, filter, post_init_func, user_data);
+  return true;
+}
+
+bool grpc_channel_stack_builder_add_filter_after(
+    grpc_channel_stack_builder_iterator *iterator,
+    const grpc_channel_filter *filter,
+    grpc_post_filter_create_init_func post_init_func, void *user_data) {
+  if (iterator->node == &iterator->builder->end) return false;
+  add_after(iterator->node, filter, post_init_func, user_data);
+  return true;
+}
+
+void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder) {
+  filter_node *p = builder->begin.next;
+  while (p != &builder->end) {
+    filter_node *next = p->next;
+    gpr_free(p);
+    p = next;
+  }
+  gpr_free(builder);
+}
+
+void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx,
+                                        grpc_channel_stack_builder *builder,
+                                        size_t prefix_bytes, int initial_refs,
+                                        grpc_iomgr_cb_func destroy,
+                                        void *destroy_arg) {
+  // count the number of filters
+  size_t num_filters = 0;
+  for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) {
+    num_filters++;
+  }
+
+  // create an array of filters
+  const grpc_channel_filter **filters =
+      gpr_malloc(sizeof(*filters) * num_filters);
+  size_t i = 0;
+  for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) {
+    filters[i++] = p->filter;
+  }
+
+  // calculate the size of the channel stack
+  size_t channel_stack_size = grpc_channel_stack_size(filters, num_filters);
+
+  // allocate memory, with prefix_bytes followed by channel_stack_size
+  char *result = gpr_malloc(prefix_bytes + channel_stack_size);
+  // fetch a pointer to the channel stack
+  grpc_channel_stack *channel_stack =
+      (grpc_channel_stack *)(result + prefix_bytes);
+  // and initialize it
+  grpc_channel_stack_init(exec_ctx, initial_refs, destroy,
+                          destroy_arg == NULL ? result : destroy_arg, filters,
+                          num_filters, builder->args, builder->name,
+                          channel_stack);
+
+  // run post-initialization functions
+  i = 0;
+  for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) {
+    if (p->init != NULL) {
+      p->init(channel_stack, grpc_channel_stack_element(channel_stack, i),
+              p->init_arg);
+    }
+    i++;
+  }
+
+  grpc_channel_stack_builder_destroy(builder);
+  gpr_free((grpc_channel_filter **)filters);
+
+  return result;
+}
diff --git a/src/core/lib/channel/channel_stack_builder.h b/src/core/lib/channel/channel_stack_builder.h
new file mode 100644
index 0000000..8532c44
--- /dev/null
+++ b/src/core/lib/channel/channel_stack_builder.h
@@ -0,0 +1,155 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_BUILDER_H
+#define GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_BUILDER_H
+
+#include <stdbool.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/channel_stack.h"
+
+/// grpc_channel_stack_builder offers a programmatic interface to selected
+/// and order channel filters
+typedef struct grpc_channel_stack_builder grpc_channel_stack_builder;
+typedef struct grpc_channel_stack_builder_iterator
+    grpc_channel_stack_builder_iterator;
+
+/// Create a new channel stack builder
+grpc_channel_stack_builder *grpc_channel_stack_builder_create(void);
+
+/// Assign a name to the channel stack: \a name must be statically allocated
+void grpc_channel_stack_builder_set_name(grpc_channel_stack_builder *builder,
+                                         const char *name);
+
+/// Attach \a transport to the builder (does not take ownership)
+void grpc_channel_stack_builder_set_transport(
+    grpc_channel_stack_builder *builder, grpc_transport *transport);
+
+/// Fetch attached transport
+grpc_transport *grpc_channel_stack_builder_get_transport(
+    grpc_channel_stack_builder *builder);
+
+/// Set channel arguments: \a args must continue to exist until after
+/// grpc_channel_stack_builder_finish returns
+void grpc_channel_stack_builder_set_channel_arguments(
+    grpc_channel_stack_builder *builder, const grpc_channel_args *args);
+
+/// Return a borrowed pointer to the channel arguments
+const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments(
+    grpc_channel_stack_builder *builder);
+
+/// Begin iterating over already defined filters in the builder at the beginning
+grpc_channel_stack_builder_iterator *
+grpc_channel_stack_builder_create_iterator_at_first(
+    grpc_channel_stack_builder *builder);
+
+/// Begin iterating over already defined filters in the builder at the end
+grpc_channel_stack_builder_iterator *
+grpc_channel_stack_builder_create_iterator_at_last(
+    grpc_channel_stack_builder *builder);
+
+/// Is an iterator at the first element?
+bool grpc_channel_stack_builder_iterator_is_first(
+    grpc_channel_stack_builder_iterator *iterator);
+
+/// Is an iterator at the end?
+bool grpc_channel_stack_builder_iterator_is_end(
+    grpc_channel_stack_builder_iterator *iterator);
+
+/// Move an iterator to the next item
+bool grpc_channel_stack_builder_move_next(
+    grpc_channel_stack_builder_iterator *iterator);
+
+/// Move an iterator to the previous item
+bool grpc_channel_stack_builder_move_prev(
+    grpc_channel_stack_builder_iterator *iterator);
+
+typedef void (*grpc_post_filter_create_init_func)(
+    grpc_channel_stack *channel_stack, grpc_channel_element *elem, void *arg);
+
+/// Add \a filter to the stack, after \a iterator.
+/// Call \a post_init_func(..., \a user_data) once the channel stack is
+/// created.
+bool grpc_channel_stack_builder_add_filter_after(
+    grpc_channel_stack_builder_iterator *iterator,
+    const grpc_channel_filter *filter,
+    grpc_post_filter_create_init_func post_init_func,
+    void *user_data) GRPC_MUST_USE_RESULT;
+
+/// Add \a filter to the stack, before \a iterator.
+/// Call \a post_init_func(..., \a user_data) once the channel stack is
+/// created.
+bool grpc_channel_stack_builder_add_filter_before(
+    grpc_channel_stack_builder_iterator *iterator,
+    const grpc_channel_filter *filter,
+    grpc_post_filter_create_init_func post_init_func,
+    void *user_data) GRPC_MUST_USE_RESULT;
+
+/// Add \a filter to the beginning of the filter list.
+/// Call \a post_init_func(..., \a user_data) once the channel stack is
+/// created.
+bool grpc_channel_stack_builder_prepend_filter(
+    grpc_channel_stack_builder *builder, const grpc_channel_filter *filter,
+    grpc_post_filter_create_init_func post_init_func,
+    void *user_data) GRPC_MUST_USE_RESULT;
+
+/// Add \a filter to the end of the filter list.
+/// Call \a post_init_func(..., \a user_data) once the channel stack is
+/// created.
+bool grpc_channel_stack_builder_append_filter(
+    grpc_channel_stack_builder *builder, const grpc_channel_filter *filter,
+    grpc_post_filter_create_init_func post_init_func,
+    void *user_data) GRPC_MUST_USE_RESULT;
+
+/// Terminate iteration and destroy \a iterator
+void grpc_channel_stack_builder_iterator_destroy(
+    grpc_channel_stack_builder_iterator *iterator);
+
+/// Destroy the builder, return the freshly minted channel stack
+/// Allocates \a prefix_bytes bytes before the channel stack
+/// Returns the base pointer of the allocated block
+/// \a initial_refs, \a destroy, \a destroy_arg are as per
+/// grpc_channel_stack_init
+void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx,
+                                        grpc_channel_stack_builder *builder,
+                                        size_t prefix_bytes, int initial_refs,
+                                        grpc_iomgr_cb_func destroy,
+                                        void *destroy_arg);
+
+/// Destroy the builder without creating a channel stack
+void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder);
+
+extern int grpc_trace_channel_stack_builder;
+
+#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_BUILDER_H */
diff --git a/src/core/lib/channel/client_channel.c b/src/core/lib/channel/client_channel.c
new file mode 100644
index 0000000..9fdf803
--- /dev/null
+++ b/src/core/lib/channel/client_channel.c
@@ -0,0 +1,526 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/channel/client_channel.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/subchannel_call_holder.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/transport/connectivity_state.h"
+
+/* Client channel implementation */
+
+typedef grpc_subchannel_call_holder call_data;
+
+typedef struct client_channel_channel_data {
+  /** resolver for this channel */
+  grpc_resolver *resolver;
+  /** have we started resolving this channel */
+  int started_resolving;
+
+  /** 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_closure_list waiting_for_config_closures;
+  /** resolver callback */
+  grpc_closure on_config_changed;
+  /** connectivity state being tracked */
+  grpc_connectivity_state_tracker state_tracker;
+  /** when an lb_policy arrives, should we try to exit idle */
+  int exit_idle_when_lb_policy_arrives;
+  /** owning stack */
+  grpc_channel_stack *owning_stack;
+  /** interested parties (owned) */
+  grpc_pollset_set *interested_parties;
+} channel_data;
+
+/** We create one watcher for each new lb_policy that is returned from a
+   resolver,
+    to watch for state changes from the lb_policy. When a state change is seen,
+   we
+    update the channel, and create a new watcher */
+typedef struct {
+  channel_data *chand;
+  grpc_closure on_changed;
+  grpc_connectivity_state state;
+  grpc_lb_policy *lb_policy;
+} lb_policy_connectivity_watcher;
+
+typedef struct {
+  grpc_closure closure;
+  grpc_call_element *elem;
+} waiting_call;
+
+static char *cc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
+  return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data);
+}
+
+static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
+                                         grpc_call_element *elem,
+                                         grpc_transport_stream_op *op) {
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+  grpc_subchannel_call_holder_perform_op(exec_ctx, elem->call_data, op);
+}
+
+static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
+                            grpc_lb_policy *lb_policy,
+                            grpc_connectivity_state current_state);
+
+static void on_lb_policy_state_changed_locked(
+    grpc_exec_ctx *exec_ctx, lb_policy_connectivity_watcher *w) {
+  grpc_connectivity_state publish_state = w->state;
+  /* check if the notification is for a stale policy */
+  if (w->lb_policy != w->chand->lb_policy) return;
+
+  if (publish_state == GRPC_CHANNEL_FATAL_FAILURE &&
+      w->chand->resolver != NULL) {
+    publish_state = GRPC_CHANNEL_TRANSIENT_FAILURE;
+    grpc_resolver_channel_saw_error(exec_ctx, w->chand->resolver);
+    GRPC_LB_POLICY_UNREF(exec_ctx, w->chand->lb_policy, "channel");
+    w->chand->lb_policy = NULL;
+  }
+  grpc_connectivity_state_set(exec_ctx, &w->chand->state_tracker, publish_state,
+                              "lb_changed");
+  if (w->state != GRPC_CHANNEL_FATAL_FAILURE) {
+    watch_lb_policy(exec_ctx, w->chand, w->lb_policy, w->state);
+  }
+}
+
+static void on_lb_policy_state_changed(grpc_exec_ctx *exec_ctx, void *arg,
+                                       bool iomgr_success) {
+  lb_policy_connectivity_watcher *w = arg;
+
+  gpr_mu_lock(&w->chand->mu_config);
+  on_lb_policy_state_changed_locked(exec_ctx, w);
+  gpr_mu_unlock(&w->chand->mu_config);
+
+  GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy");
+  gpr_free(w);
+}
+
+static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
+                            grpc_lb_policy *lb_policy,
+                            grpc_connectivity_state current_state) {
+  lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w));
+  GRPC_CHANNEL_STACK_REF(chand->owning_stack, "watch_lb_policy");
+
+  w->chand = chand;
+  grpc_closure_init(&w->on_changed, on_lb_policy_state_changed, w);
+  w->state = current_state;
+  w->lb_policy = lb_policy;
+  grpc_lb_policy_notify_on_state_change(exec_ctx, lb_policy, &w->state,
+                                        &w->on_changed);
+}
+
+static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
+                                 bool iomgr_success) {
+  channel_data *chand = arg;
+  grpc_lb_policy *lb_policy = NULL;
+  grpc_lb_policy *old_lb_policy;
+  grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
+  int exit_idle = 0;
+
+  if (chand->incoming_configuration != NULL) {
+    lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration);
+    if (lb_policy != NULL) {
+      GRPC_LB_POLICY_REF(lb_policy, "channel");
+      GRPC_LB_POLICY_REF(lb_policy, "config_change");
+      state = grpc_lb_policy_check_connectivity(exec_ctx, lb_policy);
+    }
+
+    grpc_client_config_unref(exec_ctx, chand->incoming_configuration);
+  }
+
+  chand->incoming_configuration = NULL;
+
+  if (lb_policy != NULL) {
+    grpc_pollset_set_add_pollset_set(exec_ctx, lb_policy->interested_parties,
+                                     chand->interested_parties);
+  }
+
+  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 */) {
+    grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures,
+                               NULL);
+  }
+  if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) {
+    GRPC_LB_POLICY_REF(lb_policy, "exit_idle");
+    exit_idle = 1;
+    chand->exit_idle_when_lb_policy_arrives = 0;
+  }
+
+  if (iomgr_success && chand->resolver) {
+    grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state,
+                                "new_lb+resolver");
+    if (lb_policy != NULL) {
+      watch_lb_policy(exec_ctx, chand, lb_policy, state);
+    }
+    GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
+    grpc_resolver_next(exec_ctx, chand->resolver,
+                       &chand->incoming_configuration,
+                       &chand->on_config_changed);
+    gpr_mu_unlock(&chand->mu_config);
+  } else {
+    if (chand->resolver != NULL) {
+      grpc_resolver_shutdown(exec_ctx, chand->resolver);
+      GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
+      chand->resolver = NULL;
+    }
+    grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
+                                GRPC_CHANNEL_FATAL_FAILURE, "resolver_gone");
+    gpr_mu_unlock(&chand->mu_config);
+  }
+
+  if (exit_idle) {
+    grpc_lb_policy_exit_idle(exec_ctx, lb_policy);
+    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "exit_idle");
+  }
+
+  if (old_lb_policy != NULL) {
+    grpc_pollset_set_del_pollset_set(
+        exec_ctx, old_lb_policy->interested_parties, chand->interested_parties);
+    GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel");
+  }
+
+  if (lb_policy != NULL) {
+    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "config_change");
+  }
+
+  GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver");
+}
+
+static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
+                                  grpc_channel_element *elem,
+                                  grpc_transport_op *op) {
+  channel_data *chand = elem->channel_data;
+
+  grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
+
+  GPR_ASSERT(op->set_accept_stream == false);
+  if (op->bind_pollset != NULL) {
+    grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties,
+                                 op->bind_pollset);
+  }
+
+  gpr_mu_lock(&chand->mu_config);
+  if (op->on_connectivity_state_change != NULL) {
+    grpc_connectivity_state_notify_on_state_change(
+        exec_ctx, &chand->state_tracker, op->connectivity_state,
+        op->on_connectivity_state_change);
+    op->on_connectivity_state_change = NULL;
+    op->connectivity_state = NULL;
+  }
+
+  if (op->send_ping != NULL) {
+    if (chand->lb_policy == NULL) {
+      grpc_exec_ctx_enqueue(exec_ctx, op->send_ping, false, NULL);
+    } else {
+      grpc_lb_policy_ping_one(exec_ctx, chand->lb_policy, op->send_ping);
+      op->bind_pollset = NULL;
+    }
+    op->send_ping = NULL;
+  }
+
+  if (op->disconnect && chand->resolver != NULL) {
+    grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
+                                GRPC_CHANNEL_FATAL_FAILURE, "disconnect");
+    grpc_resolver_shutdown(exec_ctx, chand->resolver);
+    GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
+    chand->resolver = NULL;
+    if (chand->lb_policy != NULL) {
+      grpc_pollset_set_del_pollset_set(exec_ctx,
+                                       chand->lb_policy->interested_parties,
+                                       chand->interested_parties);
+      GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
+      chand->lb_policy = NULL;
+    }
+  }
+  gpr_mu_unlock(&chand->mu_config);
+}
+
+typedef struct {
+  grpc_metadata_batch *initial_metadata;
+  grpc_connected_subchannel **connected_subchannel;
+  grpc_closure *on_ready;
+  grpc_call_element *elem;
+  grpc_closure closure;
+} continue_picking_args;
+
+static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
+                              grpc_metadata_batch *initial_metadata,
+                              grpc_connected_subchannel **connected_subchannel,
+                              grpc_closure *on_ready);
+
+static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  continue_picking_args *cpa = arg;
+  if (!success) {
+    grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL);
+  } else if (cpa->connected_subchannel == NULL) {
+    /* cancelled, do nothing */
+  } else if (cc_pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata,
+                                cpa->connected_subchannel, cpa->on_ready)) {
+    grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, true, NULL);
+  }
+  gpr_free(cpa);
+}
+
+static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
+                              grpc_metadata_batch *initial_metadata,
+                              grpc_connected_subchannel **connected_subchannel,
+                              grpc_closure *on_ready) {
+  grpc_call_element *elem = elemp;
+  channel_data *chand = elem->channel_data;
+  call_data *calld = elem->call_data;
+  continue_picking_args *cpa;
+  grpc_closure *closure;
+
+  GPR_ASSERT(connected_subchannel);
+
+  gpr_mu_lock(&chand->mu_config);
+  if (initial_metadata == NULL) {
+    if (chand->lb_policy != NULL) {
+      grpc_lb_policy_cancel_pick(exec_ctx, chand->lb_policy,
+                                 connected_subchannel);
+    }
+    for (closure = chand->waiting_for_config_closures.head; closure != NULL;
+         closure = grpc_closure_next(closure)) {
+      cpa = closure->cb_arg;
+      if (cpa->connected_subchannel == connected_subchannel) {
+        cpa->connected_subchannel = NULL;
+        grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL);
+      }
+    }
+    gpr_mu_unlock(&chand->mu_config);
+    return 1;
+  }
+  if (chand->lb_policy != NULL) {
+    grpc_lb_policy *lb_policy = chand->lb_policy;
+    int r;
+    GRPC_LB_POLICY_REF(lb_policy, "cc_pick_subchannel");
+    gpr_mu_unlock(&chand->mu_config);
+    r = grpc_lb_policy_pick(exec_ctx, lb_policy, calld->pollset,
+                            initial_metadata, connected_subchannel, on_ready);
+    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "cc_pick_subchannel");
+    return r;
+  }
+  if (chand->resolver != NULL && !chand->started_resolving) {
+    chand->started_resolving = 1;
+    GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
+    grpc_resolver_next(exec_ctx, chand->resolver,
+                       &chand->incoming_configuration,
+                       &chand->on_config_changed);
+  }
+  cpa = gpr_malloc(sizeof(*cpa));
+  cpa->initial_metadata = initial_metadata;
+  cpa->connected_subchannel = connected_subchannel;
+  cpa->on_ready = on_ready;
+  cpa->elem = elem;
+  grpc_closure_init(&cpa->closure, continue_picking, cpa);
+  grpc_closure_list_add(&chand->waiting_for_config_closures, &cpa->closure, 1);
+  gpr_mu_unlock(&chand->mu_config);
+  return 0;
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                           grpc_call_element_args *args) {
+  grpc_subchannel_call_holder_init(elem->call_data, cc_pick_subchannel, elem,
+                                   args->call_stack);
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_call_element *elem) {
+  grpc_subchannel_call_holder_destroy(exec_ctx, elem->call_data);
+}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_channel_element *elem,
+                              grpc_channel_element_args *args) {
+  channel_data *chand = elem->channel_data;
+
+  memset(chand, 0, sizeof(*chand));
+
+  GPR_ASSERT(args->is_last);
+  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
+
+  gpr_mu_init(&chand->mu_config);
+  grpc_closure_init(&chand->on_config_changed, cc_on_config_changed, chand);
+  chand->owning_stack = args->channel_stack;
+
+  grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
+                               "client_channel");
+  chand->interested_parties = grpc_pollset_set_create();
+}
+
+/* Destructor for channel_data */
+static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem) {
+  channel_data *chand = elem->channel_data;
+
+  if (chand->resolver != NULL) {
+    grpc_resolver_shutdown(exec_ctx, chand->resolver);
+    GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
+  }
+  if (chand->lb_policy != NULL) {
+    grpc_pollset_set_del_pollset_set(exec_ctx,
+                                     chand->lb_policy->interested_parties,
+                                     chand->interested_parties);
+    GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
+  }
+  grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
+  grpc_pollset_set_destroy(chand->interested_parties);
+  gpr_mu_destroy(&chand->mu_config);
+}
+
+static void cc_set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                           grpc_pollset *pollset) {
+  call_data *calld = elem->call_data;
+  calld->pollset = pollset;
+}
+
+const grpc_channel_filter grpc_client_channel_filter = {
+    cc_start_transport_stream_op,
+    cc_start_transport_op,
+    sizeof(call_data),
+    init_call_elem,
+    cc_set_pollset,
+    destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    cc_get_peer,
+    "client-channel",
+};
+
+void grpc_client_channel_set_resolver(grpc_exec_ctx *exec_ctx,
+                                      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_mu_lock(&chand->mu_config);
+  GPR_ASSERT(!chand->resolver);
+  chand->resolver = resolver;
+  GRPC_RESOLVER_REF(resolver, "channel");
+  if (!grpc_closure_list_empty(chand->waiting_for_config_closures) ||
+      chand->exit_idle_when_lb_policy_arrives) {
+    chand->started_resolving = 1;
+    GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
+    grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration,
+                       &chand->on_config_changed);
+  }
+  gpr_mu_unlock(&chand->mu_config);
+}
+
+grpc_connectivity_state grpc_client_channel_check_connectivity_state(
+    grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) {
+  channel_data *chand = elem->channel_data;
+  grpc_connectivity_state out;
+  gpr_mu_lock(&chand->mu_config);
+  out = grpc_connectivity_state_check(&chand->state_tracker);
+  if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
+    if (chand->lb_policy != NULL) {
+      grpc_lb_policy_exit_idle(exec_ctx, chand->lb_policy);
+    } else {
+      chand->exit_idle_when_lb_policy_arrives = 1;
+      if (!chand->started_resolving && chand->resolver != NULL) {
+        GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
+        chand->started_resolving = 1;
+        grpc_resolver_next(exec_ctx, chand->resolver,
+                           &chand->incoming_configuration,
+                           &chand->on_config_changed);
+      }
+    }
+  }
+  gpr_mu_unlock(&chand->mu_config);
+  return out;
+}
+
+typedef struct {
+  channel_data *chand;
+  grpc_pollset *pollset;
+  grpc_closure *on_complete;
+  grpc_closure my_closure;
+} external_connectivity_watcher;
+
+static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
+                                       bool iomgr_success) {
+  external_connectivity_watcher *w = arg;
+  grpc_closure *follow_up = w->on_complete;
+  grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties,
+                               w->pollset);
+  GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
+                           "external_connectivity_watcher");
+  gpr_free(w);
+  follow_up->cb(exec_ctx, follow_up->cb_arg, iomgr_success);
+}
+
+void grpc_client_channel_watch_connectivity_state(
+    grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
+    grpc_connectivity_state *state, grpc_closure *on_complete) {
+  channel_data *chand = elem->channel_data;
+  external_connectivity_watcher *w = gpr_malloc(sizeof(*w));
+  w->chand = chand;
+  w->pollset = pollset;
+  w->on_complete = on_complete;
+  grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, pollset);
+  grpc_closure_init(&w->my_closure, on_external_watch_complete, w);
+  GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
+                         "external_connectivity_watcher");
+  gpr_mu_lock(&chand->mu_config);
+  grpc_connectivity_state_notify_on_state_change(
+      exec_ctx, &chand->state_tracker, state, &w->my_closure);
+  gpr_mu_unlock(&chand->mu_config);
+}
diff --git a/src/core/lib/channel/client_channel.h b/src/core/lib/channel/client_channel.h
new file mode 100644
index 0000000..8777796
--- /dev/null
+++ b/src/core/lib/channel/client_channel.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_CLIENT_CHANNEL_H
+#define GRPC_CORE_LIB_CHANNEL_CLIENT_CHANNEL_H
+
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/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
+   connected to again later.
+
+   Calls on a disconnected client channel are queued until a connection is
+   established. */
+
+extern const grpc_channel_filter grpc_client_channel_filter;
+
+/* 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_resolver(grpc_exec_ctx *exec_ctx,
+                                      grpc_channel_stack *channel_stack,
+                                      grpc_resolver *resolver);
+
+grpc_connectivity_state grpc_client_channel_check_connectivity_state(
+    grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect);
+
+void grpc_client_channel_watch_connectivity_state(
+    grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
+    grpc_connectivity_state *state, grpc_closure *on_complete);
+
+#endif /* GRPC_CORE_LIB_CHANNEL_CLIENT_CHANNEL_H */
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
new file mode 100644
index 0000000..04bb7cc
--- /dev/null
+++ b/src/core/lib/channel/compress_filter.c
@@ -0,0 +1,304 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <grpc/compression.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/compress_filter.h"
+#include "src/core/lib/compression/algorithm_metadata.h"
+#include "src/core/lib/compression/message_compress.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+typedef struct call_data {
+  gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */
+  grpc_linked_mdelem compression_algorithm_storage;
+  grpc_linked_mdelem accept_encoding_storage;
+  uint32_t remaining_slice_bytes;
+  /** 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;
+
+  grpc_transport_stream_op send_op;
+  uint32_t send_length;
+  uint32_t send_flags;
+  gpr_slice incoming_slice;
+  grpc_slice_buffer_stream replacement_stream;
+  grpc_closure *post_send;
+  grpc_closure send_done;
+  grpc_closure got_slice;
+} call_data;
+
+typedef struct channel_data {
+  /** The default, channel-level, compression algorithm */
+  grpc_compression_algorithm default_compression_algorithm;
+  /** Compression options for the channel */
+  grpc_compression_options compression_options;
+  /** Supported compression algorithms */
+  uint32_t supported_compression_algorithms;
+} channel_data;
+
+/** 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 == GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST) {
+    const char *md_c_str = grpc_mdstr_as_c_string(md->value);
+    if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
+                                          &calld->compression_algorithm)) {
+      gpr_log(GPR_ERROR,
+              "Invalid compression algorithm: '%s' (unknown). Ignoring.",
+              md_c_str);
+      calld->compression_algorithm = GRPC_COMPRESS_NONE;
+    }
+    if (grpc_compression_options_is_algorithm_enabled(
+            &channeld->compression_options, calld->compression_algorithm) ==
+        0) {
+      gpr_log(GPR_ERROR,
+              "Invalid compression algorithm: '%s' (previously disabled). "
+              "Ignoring.",
+              md_c_str);
+      calld->compression_algorithm = GRPC_COMPRESS_NONE;
+    }
+    calld->has_compression_algorithm = 1;
+    return NULL;
+  }
+
+  return md;
+}
+
+static int skip_compression(grpc_call_element *elem) {
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+  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;
+}
+
+/** Filter initial metadata */
+static void process_send_initial_metadata(
+    grpc_call_element *elem, grpc_metadata_batch *initial_metadata) {
+  call_data *calld = elem->call_data;
+  channel_data *channeld = elem->channel_data;
+  /* Parse incoming request for compression. If any, it'll be available
+   * at calld->compression_algorithm */
+  grpc_metadata_batch_filter(initial_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 */
+  }
+  /* hint compression algorithm */
+  grpc_metadata_batch_add_tail(
+      initial_metadata, &calld->compression_algorithm_storage,
+      grpc_compression_encoding_mdelem(calld->compression_algorithm));
+
+  /* convey supported compression algorithms */
+  grpc_metadata_batch_add_tail(initial_metadata,
+                               &calld->accept_encoding_storage,
+                               GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(
+                                   channeld->supported_compression_algorithms));
+}
+
+static void continue_send_message(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem);
+
+static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, bool success) {
+  grpc_call_element *elem = elemp;
+  call_data *calld = elem->call_data;
+  gpr_slice_buffer_reset_and_unref(&calld->slices);
+  calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, success);
+}
+
+static void finish_send_message(grpc_exec_ctx *exec_ctx,
+                                grpc_call_element *elem) {
+  call_data *calld = elem->call_data;
+  int did_compress;
+  gpr_slice_buffer tmp;
+  gpr_slice_buffer_init(&tmp);
+  did_compress =
+      grpc_msg_compress(calld->compression_algorithm, &calld->slices, &tmp);
+  if (did_compress) {
+    gpr_slice_buffer_swap(&calld->slices, &tmp);
+    calld->send_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
+  }
+  gpr_slice_buffer_destroy(&tmp);
+
+  grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
+                                calld->send_flags);
+  calld->send_op.send_message = &calld->replacement_stream.base;
+  calld->post_send = calld->send_op.on_complete;
+  calld->send_op.on_complete = &calld->send_done;
+
+  grpc_call_next_op(exec_ctx, elem, &calld->send_op);
+}
+
+static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, bool success) {
+  grpc_call_element *elem = elemp;
+  call_data *calld = elem->call_data;
+  gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
+  if (calld->send_length == calld->slices.length) {
+    finish_send_message(exec_ctx, elem);
+  } else {
+    continue_send_message(exec_ctx, elem);
+  }
+}
+
+static void continue_send_message(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem) {
+  call_data *calld = elem->call_data;
+  while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message,
+                               &calld->incoming_slice, ~(size_t)0,
+                               &calld->got_slice)) {
+    gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
+    if (calld->send_length == calld->slices.length) {
+      finish_send_message(exec_ctx, elem);
+      break;
+    }
+  }
+}
+
+static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
+                                               grpc_call_element *elem,
+                                               grpc_transport_stream_op *op) {
+  call_data *calld = elem->call_data;
+
+  GPR_TIMER_BEGIN("compress_start_transport_stream_op", 0);
+
+  if (op->send_initial_metadata) {
+    process_send_initial_metadata(elem, op->send_initial_metadata);
+  }
+  if (op->send_message != NULL && !skip_compression(elem) &&
+      0 == (op->send_message->flags & GRPC_WRITE_NO_COMPRESS)) {
+    calld->send_op = *op;
+    calld->send_length = op->send_message->length;
+    calld->send_flags = op->send_message->flags;
+    continue_send_message(exec_ctx, elem);
+  } else {
+    /* pass control down the stack */
+    grpc_call_next_op(exec_ctx, elem, op);
+  }
+
+  GPR_TIMER_END("compress_start_transport_stream_op", 0);
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                           grpc_call_element_args *args) {
+  /* 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;
+  grpc_closure_init(&calld->got_slice, got_slice, elem);
+  grpc_closure_init(&calld->send_done, send_done, elem);
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
+                              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_exec_ctx *exec_ctx,
+                              grpc_channel_element *elem,
+                              grpc_channel_element_args *args) {
+  channel_data *channeld = elem->channel_data;
+  grpc_compression_algorithm algo_idx;
+
+  grpc_compression_options_init(&channeld->compression_options);
+  channeld->compression_options.enabled_algorithms_bitset =
+      (uint32_t)grpc_channel_args_compression_algorithm_get_states(
+          args->channel_args);
+
+  channeld->default_compression_algorithm =
+      grpc_channel_args_get_compression_algorithm(args->channel_args);
+  /* Make sure the default isn't disabled. */
+  GPR_ASSERT(grpc_compression_options_is_algorithm_enabled(
+      &channeld->compression_options, channeld->default_compression_algorithm));
+  channeld->compression_options.default_compression_algorithm =
+      channeld->default_compression_algorithm;
+
+  channeld->supported_compression_algorithms = 0;
+  for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
+    /* skip disabled algorithms */
+    if (grpc_compression_options_is_algorithm_enabled(
+            &channeld->compression_options, algo_idx) == 0) {
+      continue;
+    }
+    channeld->supported_compression_algorithms |= 1u << algo_idx;
+  }
+
+  GPR_ASSERT(!args->is_last);
+}
+
+/* Destructor for channel data */
+static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem) {}
+
+const grpc_channel_filter grpc_compress_filter = {
+    compress_start_transport_stream_op,
+    grpc_channel_next_op,
+    sizeof(call_data),
+    init_call_elem,
+    grpc_call_stack_ignore_set_pollset,
+    destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    grpc_call_next_get_peer,
+    "compress"};
diff --git a/src/core/lib/channel/compress_filter.h b/src/core/lib/channel/compress_filter.h
new file mode 100644
index 0000000..9010074
--- /dev/null
+++ b/src/core/lib/channel/compress_filter.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_COMPRESS_FILTER_H
+#define GRPC_CORE_LIB_CHANNEL_COMPRESS_FILTER_H
+
+#include "src/core/lib/channel/channel_stack.h"
+
+#define GRPC_COMPRESS_REQUEST_ALGORITHM_KEY "grpc-internal-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_CORE_LIB_CHANNEL_COMPRESS_FILTER_H */
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
new file mode 100644
index 0000000..5e3a897
--- /dev/null
+++ b/src/core/lib/channel/connected_channel.c
@@ -0,0 +1,176 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/channel/connected_channel.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/transport.h"
+
+#define MAX_BUFFER_LENGTH 8192
+
+typedef struct connected_channel_channel_data {
+  grpc_transport *transport;
+} channel_data;
+
+typedef struct connected_channel_call_data { void *unused; } call_data;
+
+/* We perform a small hack to locate transport data alongside the connected
+   channel data in call allocations, to allow everything to be pulled in minimal
+   cache line requests */
+#define TRANSPORT_STREAM_FROM_CALL_DATA(calld) ((grpc_stream *)((calld) + 1))
+#define CALL_DATA_FROM_TRANSPORT_STREAM(transport_stream) \
+  (((call_data *)(transport_stream)) - 1)
+
+/* Intercept a call operation and either push it directly up or translate it
+   into transport stream operations */
+static void con_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
+                                          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);
+
+  grpc_transport_perform_stream_op(exec_ctx, chand->transport,
+                                   TRANSPORT_STREAM_FROM_CALL_DATA(calld), op);
+}
+
+static void con_start_transport_op(grpc_exec_ctx *exec_ctx,
+                                   grpc_channel_element *elem,
+                                   grpc_transport_op *op) {
+  channel_data *chand = elem->channel_data;
+  grpc_transport_perform_op(exec_ctx, chand->transport, op);
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                           grpc_call_element_args *args) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  int r;
+
+  r = grpc_transport_init_stream(
+      exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld),
+      &args->call_stack->refcount, args->server_transport_data);
+  GPR_ASSERT(r == 0);
+}
+
+static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                        grpc_pollset *pollset) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  grpc_transport_set_pollset(exec_ctx, chand->transport,
+                             TRANSPORT_STREAM_FROM_CALL_DATA(calld), pollset);
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_call_element *elem) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  grpc_transport_destroy_stream(exec_ctx, chand->transport,
+                                TRANSPORT_STREAM_FROM_CALL_DATA(calld));
+}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_channel_element *elem,
+                              grpc_channel_element_args *args) {
+  channel_data *cd = (channel_data *)elem->channel_data;
+  GPR_ASSERT(args->is_last);
+  cd->transport = NULL;
+}
+
+/* Destructor for channel_data */
+static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem) {
+  channel_data *cd = (channel_data *)elem->channel_data;
+  grpc_transport_destroy(exec_ctx, cd->transport);
+}
+
+static char *con_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
+  channel_data *chand = elem->channel_data;
+  return grpc_transport_get_peer(exec_ctx, chand->transport);
+}
+
+static const grpc_channel_filter connected_channel_filter = {
+    con_start_transport_stream_op,
+    con_start_transport_op,
+    sizeof(call_data),
+    init_call_elem,
+    set_pollset,
+    destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    con_get_peer,
+    "connected",
+};
+
+static void bind_transport(grpc_channel_stack *channel_stack,
+                           grpc_channel_element *elem, void *t) {
+  channel_data *cd = (channel_data *)elem->channel_data;
+  GPR_ASSERT(elem->filter == &connected_channel_filter);
+  GPR_ASSERT(cd->transport == NULL);
+  cd->transport = t;
+
+  /* HACK(ctiller): increase call stack size for the channel to make space
+     for channel data. We need a cleaner (but performant) way to do this,
+     and I'm not sure what that is yet.
+     This is only "safe" because call stacks place no additional data after
+     the last call element, and the last call element MUST be the connected
+     channel. */
+  channel_stack->call_stack_size += grpc_transport_stream_size(t);
+}
+
+bool grpc_add_connected_filter(grpc_channel_stack_builder *builder,
+                               void *arg_must_be_null) {
+  GPR_ASSERT(arg_must_be_null == NULL);
+  grpc_transport *t = grpc_channel_stack_builder_get_transport(builder);
+  GPR_ASSERT(t != NULL);
+  return grpc_channel_stack_builder_append_filter(
+      builder, &connected_channel_filter, bind_transport, t);
+}
+
+grpc_stream *grpc_connected_channel_get_stream(grpc_call_element *elem) {
+  call_data *calld = elem->call_data;
+  return TRANSPORT_STREAM_FROM_CALL_DATA(calld);
+}
diff --git a/src/core/lib/channel/connected_channel.h b/src/core/lib/channel/connected_channel.h
new file mode 100644
index 0000000..4f20b75
--- /dev/null
+++ b/src/core/lib/channel/connected_channel.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_CONNECTED_CHANNEL_H
+#define GRPC_CORE_LIB_CHANNEL_CONNECTED_CHANNEL_H
+
+#include "src/core/lib/channel/channel_stack_builder.h"
+
+bool grpc_add_connected_filter(grpc_channel_stack_builder *builder,
+                               void *arg_must_be_null);
+
+#endif /* GRPC_CORE_LIB_CHANNEL_CONNECTED_CHANNEL_H */
diff --git a/src/core/lib/channel/context.h b/src/core/lib/channel/context.h
new file mode 100644
index 0000000..bca102d
--- /dev/null
+++ b/src/core/lib/channel/context.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_CONTEXT_H
+#define GRPC_CORE_LIB_CHANNEL_CONTEXT_H
+
+/* Call object context pointers */
+typedef enum {
+  GRPC_CONTEXT_SECURITY = 0,
+  GRPC_CONTEXT_TRACING,
+  GRPC_CONTEXT_COUNT
+} grpc_context_index;
+
+typedef struct {
+  void *value;
+  void (*destroy)(void *);
+} grpc_call_context_element;
+
+#endif /* GRPC_CORE_LIB_CHANNEL_CONTEXT_H */
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
new file mode 100644
index 0000000..7dbac38
--- /dev/null
+++ b/src/core/lib/channel/http_client_filter.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/channel/http_client_filter.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <string.h>
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+typedef struct call_data {
+  grpc_linked_mdelem method;
+  grpc_linked_mdelem scheme;
+  grpc_linked_mdelem authority;
+  grpc_linked_mdelem te_trailers;
+  grpc_linked_mdelem content_type;
+  grpc_linked_mdelem user_agent;
+
+  grpc_metadata_batch *recv_initial_metadata;
+
+  /** Closure to call when finished with the hc_on_recv hook */
+  grpc_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_closure hc_on_recv;
+} call_data;
+
+typedef struct channel_data {
+  grpc_mdelem *static_scheme;
+  grpc_mdelem *user_agent;
+} channel_data;
+
+typedef struct {
+  grpc_call_element *elem;
+  grpc_exec_ctx *exec_ctx;
+} client_recv_filter_args;
+
+static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
+  client_recv_filter_args *a = user_data;
+  if (md == GRPC_MDELEM_STATUS_200) {
+    return NULL;
+  } else if (md->key == GRPC_MDSTR_STATUS) {
+    grpc_call_element_send_cancel(a->exec_ctx, a->elem);
+    return NULL;
+  } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
+    return NULL;
+  }
+  return md;
+}
+
+static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
+  grpc_call_element *elem = user_data;
+  call_data *calld = elem->call_data;
+  client_recv_filter_args a;
+  a.elem = elem;
+  a.exec_ctx = exec_ctx;
+  grpc_metadata_batch_filter(calld->recv_initial_metadata, client_recv_filter,
+                             &a);
+  calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success);
+}
+
+static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
+  /* eat the things we'd like to set ourselves */
+  if (md->key == GRPC_MDSTR_METHOD) return NULL;
+  if (md->key == GRPC_MDSTR_SCHEME) return NULL;
+  if (md->key == GRPC_MDSTR_TE) return NULL;
+  if (md->key == GRPC_MDSTR_CONTENT_TYPE) return NULL;
+  if (md->key == GRPC_MDSTR_USER_AGENT) return NULL;
+  return md;
+}
+
+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;
+  if (op->send_initial_metadata != NULL) {
+    grpc_metadata_batch_filter(op->send_initial_metadata, client_strip_filter,
+                               elem);
+    /* Send : prefixed headers, which have to be before any application
+       layer headers. */
+    grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method,
+                                 GRPC_MDELEM_METHOD_POST);
+    grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme,
+                                 channeld->static_scheme);
+    grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers,
+                                 GRPC_MDELEM_TE_TRAILERS);
+    grpc_metadata_batch_add_tail(
+        op->send_initial_metadata, &calld->content_type,
+        GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
+    grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->user_agent,
+                                 GRPC_MDELEM_REF(channeld->user_agent));
+  }
+
+  if (op->recv_initial_metadata != NULL) {
+    /* substitute our callback for the higher callback */
+    calld->recv_initial_metadata = op->recv_initial_metadata;
+    calld->on_done_recv = op->recv_initial_metadata_ready;
+    op->recv_initial_metadata_ready = &calld->hc_on_recv;
+  }
+}
+
+static void hc_start_transport_op(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_transport_stream_op *op) {
+  GPR_TIMER_BEGIN("hc_start_transport_op", 0);
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+  hc_mutate_op(elem, op);
+  GPR_TIMER_END("hc_start_transport_op", 0);
+  grpc_call_next_op(exec_ctx, elem, op);
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                           grpc_call_element_args *args) {
+  call_data *calld = elem->call_data;
+  calld->on_done_recv = NULL;
+  grpc_closure_init(&calld->hc_on_recv, hc_on_recv, elem);
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_call_element *elem) {}
+
+static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
+  unsigned i;
+  size_t j;
+  grpc_mdelem *valid_schemes[] = {GRPC_MDELEM_SCHEME_HTTP,
+                                  GRPC_MDELEM_SCHEME_HTTPS};
+  if (args != NULL) {
+    for (i = 0; i < args->num_args; ++i) {
+      if (args->args[i].type == GRPC_ARG_STRING &&
+          strcmp(args->args[i].key, GRPC_ARG_HTTP2_SCHEME) == 0) {
+        for (j = 0; j < GPR_ARRAY_SIZE(valid_schemes); j++) {
+          if (0 == strcmp(grpc_mdstr_as_c_string(valid_schemes[j]->value),
+                          args->args[i].value.string)) {
+            return valid_schemes[j];
+          }
+        }
+      }
+    }
+  }
+  return GRPC_MDELEM_SCHEME_HTTP;
+}
+
+static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args) {
+  gpr_strvec v;
+  size_t i;
+  int is_first = 1;
+  char *tmp;
+  grpc_mdstr *result;
+
+  gpr_strvec_init(&v);
+
+  for (i = 0; args && i < args->num_args; i++) {
+    if (0 == strcmp(args->args[i].key, GRPC_ARG_PRIMARY_USER_AGENT_STRING)) {
+      if (args->args[i].type != GRPC_ARG_STRING) {
+        gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
+                GRPC_ARG_PRIMARY_USER_AGENT_STRING);
+      } else {
+        if (!is_first) gpr_strvec_add(&v, gpr_strdup(" "));
+        is_first = 0;
+        gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string));
+      }
+    }
+  }
+
+  gpr_asprintf(&tmp, "%sgrpc-c/%s (%s)", is_first ? "" : " ",
+               grpc_version_string(), GPR_PLATFORM_STRING);
+  is_first = 0;
+  gpr_strvec_add(&v, tmp);
+
+  for (i = 0; args && i < args->num_args; i++) {
+    if (0 == strcmp(args->args[i].key, GRPC_ARG_SECONDARY_USER_AGENT_STRING)) {
+      if (args->args[i].type != GRPC_ARG_STRING) {
+        gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
+                GRPC_ARG_SECONDARY_USER_AGENT_STRING);
+      } else {
+        if (!is_first) gpr_strvec_add(&v, gpr_strdup(" "));
+        is_first = 0;
+        gpr_strvec_add(&v, gpr_strdup(args->args[i].value.string));
+      }
+    }
+  }
+
+  tmp = gpr_strvec_flatten(&v, NULL);
+  gpr_strvec_destroy(&v);
+  result = grpc_mdstr_from_string(tmp);
+  gpr_free(tmp);
+
+  return result;
+}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_channel_element *elem,
+                              grpc_channel_element_args *args) {
+  channel_data *chand = elem->channel_data;
+  GPR_ASSERT(!args->is_last);
+  chand->static_scheme = scheme_from_args(args->channel_args);
+  chand->user_agent = grpc_mdelem_from_metadata_strings(
+      GRPC_MDSTR_USER_AGENT, user_agent_from_args(args->channel_args));
+}
+
+/* Destructor for channel data */
+static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem) {
+  channel_data *chand = elem->channel_data;
+  GRPC_MDELEM_UNREF(chand->user_agent);
+}
+
+const grpc_channel_filter grpc_http_client_filter = {
+    hc_start_transport_op,
+    grpc_channel_next_op,
+    sizeof(call_data),
+    init_call_elem,
+    grpc_call_stack_ignore_set_pollset,
+    destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    grpc_call_next_get_peer,
+    "http-client"};
diff --git a/src/core/lib/channel/http_client_filter.h b/src/core/lib/channel/http_client_filter.h
new file mode 100644
index 0000000..418426e
--- /dev/null
+++ b/src/core/lib/channel/http_client_filter.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H
+#define GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H
+
+#include "src/core/lib/channel/channel_stack.h"
+
+/* Processes metadata on the client side for HTTP2 transports */
+extern const grpc_channel_filter grpc_http_client_filter;
+
+#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme"
+
+#endif /* GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H */
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
new file mode 100644
index 0000000..df99b77
--- /dev/null
+++ b/src/core/lib/channel/http_server_filter.c
@@ -0,0 +1,240 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/channel/http_server_filter.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <string.h>
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+typedef struct call_data {
+  uint8_t seen_path;
+  uint8_t seen_post;
+  uint8_t sent_status;
+  uint8_t seen_scheme;
+  uint8_t seen_te_trailers;
+  uint8_t seen_authority;
+  grpc_linked_mdelem status;
+  grpc_linked_mdelem content_type;
+
+  grpc_metadata_batch *recv_initial_metadata;
+  /** Closure to call when finished with the hs_on_recv hook */
+  grpc_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_closure hs_on_recv;
+} call_data;
+
+typedef struct channel_data { uint8_t unused; } channel_data;
+
+typedef struct {
+  grpc_call_element *elem;
+  grpc_exec_ctx *exec_ctx;
+} server_filter_args;
+
+static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
+  server_filter_args *a = user_data;
+  grpc_call_element *elem = a->elem;
+  call_data *calld = elem->call_data;
+
+  /* Check if it is one of the headers we care about. */
+  if (md == GRPC_MDELEM_TE_TRAILERS || md == GRPC_MDELEM_METHOD_POST ||
+      md == GRPC_MDELEM_SCHEME_HTTP || md == GRPC_MDELEM_SCHEME_HTTPS ||
+      md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
+    /* swallow it */
+    if (md == GRPC_MDELEM_METHOD_POST) {
+      calld->seen_post = 1;
+    } else if (md->key == GRPC_MDSTR_SCHEME) {
+      calld->seen_scheme = 1;
+    } else if (md == GRPC_MDELEM_TE_TRAILERS) {
+      calld->seen_te_trailers = 1;
+    }
+    /* TODO(klempner): Track that we've seen all the headers we should
+       require */
+    return NULL;
+  } else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
+    if (strncmp(grpc_mdstr_as_c_string(md->value), "application/grpc+", 17) ==
+        0) {
+      /* Although the C implementation doesn't (currently) generate them,
+         any custom +-suffix is explicitly valid. */
+      /* TODO(klempner): We should consider preallocating common values such
+         as +proto or +json, or at least stashing them if we see them. */
+      /* TODO(klempner): Should we be surfacing this to application code? */
+    } else {
+      /* TODO(klempner): We're currently allowing this, but we shouldn't
+         see it without a proxy so log for now. */
+      gpr_log(GPR_INFO, "Unexpected content-type %s",
+              grpc_mdstr_as_c_string(md->value));
+    }
+    return NULL;
+  } else if (md->key == GRPC_MDSTR_TE || md->key == GRPC_MDSTR_METHOD ||
+             md->key == GRPC_MDSTR_SCHEME) {
+    gpr_log(GPR_ERROR, "Invalid %s: header: '%s'",
+            grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value));
+    /* swallow it and error everything out. */
+    /* TODO(klempner): We ought to generate more descriptive error messages
+       on the wire here. */
+    grpc_call_element_send_cancel(a->exec_ctx, elem);
+    return NULL;
+  } else if (md->key == GRPC_MDSTR_PATH) {
+    if (calld->seen_path) {
+      gpr_log(GPR_ERROR, "Received :path twice");
+      return NULL;
+    }
+    calld->seen_path = 1;
+    return md;
+  } else if (md->key == GRPC_MDSTR_AUTHORITY) {
+    calld->seen_authority = 1;
+    return md;
+  } else if (md->key == GRPC_MDSTR_HOST) {
+    /* translate host to :authority since :authority may be
+       omitted */
+    grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
+        GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value));
+    calld->seen_authority = 1;
+    return authority;
+  } else {
+    return md;
+  }
+}
+
+static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
+  grpc_call_element *elem = user_data;
+  call_data *calld = elem->call_data;
+  if (success) {
+    server_filter_args a;
+    a.elem = elem;
+    a.exec_ctx = exec_ctx;
+    grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, &a);
+    /* Have we seen the required http2 transport headers?
+       (:method, :scheme, content-type, with :path and :authority covered
+       at the channel level right now) */
+    if (calld->seen_post && calld->seen_scheme && calld->seen_te_trailers &&
+        calld->seen_path && calld->seen_authority) {
+      /* do nothing */
+    } else {
+      if (!calld->seen_path) {
+        gpr_log(GPR_ERROR, "Missing :path header");
+      }
+      if (!calld->seen_authority) {
+        gpr_log(GPR_ERROR, "Missing :authority header");
+      }
+      if (!calld->seen_post) {
+        gpr_log(GPR_ERROR, "Missing :method header");
+      }
+      if (!calld->seen_scheme) {
+        gpr_log(GPR_ERROR, "Missing :scheme header");
+      }
+      if (!calld->seen_te_trailers) {
+        gpr_log(GPR_ERROR, "Missing te trailers header");
+      }
+      /* Error this call out */
+      success = 0;
+      grpc_call_element_send_cancel(exec_ctx, elem);
+    }
+  }
+  calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success);
+}
+
+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;
+
+  if (op->send_initial_metadata != NULL && !calld->sent_status) {
+    calld->sent_status = 1;
+    grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->status,
+                                 GRPC_MDELEM_STATUS_200);
+    grpc_metadata_batch_add_tail(
+        op->send_initial_metadata, &calld->content_type,
+        GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
+  }
+
+  if (op->recv_initial_metadata) {
+    /* substitute our callback for the higher callback */
+    calld->recv_initial_metadata = op->recv_initial_metadata;
+    calld->on_done_recv = op->recv_initial_metadata_ready;
+    op->recv_initial_metadata_ready = &calld->hs_on_recv;
+  }
+}
+
+static void hs_start_transport_op(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_transport_stream_op *op) {
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+  GPR_TIMER_BEGIN("hs_start_transport_op", 0);
+  hs_mutate_op(elem, op);
+  grpc_call_next_op(exec_ctx, elem, op);
+  GPR_TIMER_END("hs_start_transport_op", 0);
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                           grpc_call_element_args *args) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  /* initialize members */
+  memset(calld, 0, sizeof(*calld));
+  grpc_closure_init(&calld->hs_on_recv, hs_on_recv, elem);
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_call_element *elem) {}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_channel_element *elem,
+                              grpc_channel_element_args *args) {
+  GPR_ASSERT(!args->is_last);
+}
+
+/* Destructor for channel data */
+static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem) {}
+
+const grpc_channel_filter grpc_http_server_filter = {
+    hs_start_transport_op,
+    grpc_channel_next_op,
+    sizeof(call_data),
+    init_call_elem,
+    grpc_call_stack_ignore_set_pollset,
+    destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    grpc_call_next_get_peer,
+    "http-server"};
diff --git a/src/core/lib/channel/http_server_filter.h b/src/core/lib/channel/http_server_filter.h
new file mode 100644
index 0000000..c8cf920
--- /dev/null
+++ b/src/core/lib/channel/http_server_filter.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_HTTP_SERVER_FILTER_H
+#define GRPC_CORE_LIB_CHANNEL_HTTP_SERVER_FILTER_H
+
+#include "src/core/lib/channel/channel_stack.h"
+
+/* Processes metadata on the client side for HTTP2 transports */
+extern const grpc_channel_filter grpc_http_server_filter;
+
+#endif /* GRPC_CORE_LIB_CHANNEL_HTTP_SERVER_FILTER_H */
diff --git a/src/core/lib/channel/subchannel_call_holder.c b/src/core/lib/channel/subchannel_call_holder.c
new file mode 100644
index 0000000..6c6d42d
--- /dev/null
+++ b/src/core/lib/channel/subchannel_call_holder.c
@@ -0,0 +1,259 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/channel/subchannel_call_holder.h"
+
+#include <grpc/support/alloc.h>
+
+#include "src/core/lib/profiling/timers.h"
+
+#define GET_CALL(holder) \
+  ((grpc_subchannel_call *)(gpr_atm_acq_load(&(holder)->subchannel_call)))
+
+#define CANCELLED_CALL ((grpc_subchannel_call *)1)
+
+static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder,
+                             bool success);
+static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args,
+                      bool success);
+
+static void add_waiting_locked(grpc_subchannel_call_holder *holder,
+                               grpc_transport_stream_op *op);
+static void fail_locked(grpc_exec_ctx *exec_ctx,
+                        grpc_subchannel_call_holder *holder);
+static void retry_waiting_locked(grpc_exec_ctx *exec_ctx,
+                                 grpc_subchannel_call_holder *holder);
+
+void grpc_subchannel_call_holder_init(
+    grpc_subchannel_call_holder *holder,
+    grpc_subchannel_call_holder_pick_subchannel pick_subchannel,
+    void *pick_subchannel_arg, grpc_call_stack *owning_call) {
+  gpr_atm_rel_store(&holder->subchannel_call, 0);
+  holder->pick_subchannel = pick_subchannel;
+  holder->pick_subchannel_arg = pick_subchannel_arg;
+  gpr_mu_init(&holder->mu);
+  holder->connected_subchannel = NULL;
+  holder->waiting_ops = NULL;
+  holder->waiting_ops_count = 0;
+  holder->waiting_ops_capacity = 0;
+  holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
+  holder->owning_call = owning_call;
+}
+
+void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx,
+                                         grpc_subchannel_call_holder *holder) {
+  grpc_subchannel_call *call = GET_CALL(holder);
+  if (call != NULL && call != CANCELLED_CALL) {
+    GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "holder");
+  }
+  GPR_ASSERT(holder->creation_phase ==
+             GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING);
+  gpr_mu_destroy(&holder->mu);
+  GPR_ASSERT(holder->waiting_ops_count == 0);
+  gpr_free(holder->waiting_ops);
+}
+
+void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx,
+                                            grpc_subchannel_call_holder *holder,
+                                            grpc_transport_stream_op *op) {
+  /* try to (atomically) get the call */
+  grpc_subchannel_call *call = GET_CALL(holder);
+  GPR_TIMER_BEGIN("grpc_subchannel_call_holder_perform_op", 0);
+  if (call == CANCELLED_CALL) {
+    grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
+    GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
+    return;
+  }
+  if (call != NULL) {
+    grpc_subchannel_call_process_op(exec_ctx, call, op);
+    GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
+    return;
+  }
+  /* we failed; lock and figure out what to do */
+  gpr_mu_lock(&holder->mu);
+retry:
+  /* need to recheck that another thread hasn't set the call */
+  call = GET_CALL(holder);
+  if (call == CANCELLED_CALL) {
+    gpr_mu_unlock(&holder->mu);
+    grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
+    GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
+    return;
+  }
+  if (call != NULL) {
+    gpr_mu_unlock(&holder->mu);
+    grpc_subchannel_call_process_op(exec_ctx, call, op);
+    GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
+    return;
+  }
+  /* if this is a cancellation, then we can raise our cancelled flag */
+  if (op->cancel_with_status != GRPC_STATUS_OK) {
+    if (!gpr_atm_rel_cas(&holder->subchannel_call, 0, 1)) {
+      goto retry;
+    } else {
+      switch (holder->creation_phase) {
+        case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING:
+          fail_locked(exec_ctx, holder);
+          break;
+        case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL:
+          holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL,
+                                  &holder->connected_subchannel, NULL);
+          break;
+      }
+      gpr_mu_unlock(&holder->mu);
+      grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
+      GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
+      return;
+    }
+  }
+  /* if we don't have a subchannel, try to get one */
+  if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
+      holder->connected_subchannel == NULL &&
+      op->send_initial_metadata != NULL) {
+    holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL;
+    grpc_closure_init(&holder->next_step, subchannel_ready, holder);
+    GRPC_CALL_STACK_REF(holder->owning_call, "pick_subchannel");
+    if (holder->pick_subchannel(
+            exec_ctx, holder->pick_subchannel_arg, op->send_initial_metadata,
+            &holder->connected_subchannel, &holder->next_step)) {
+      holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
+      GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel");
+    }
+  }
+  /* if we've got a subchannel, then let's ask it to create a call */
+  if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
+      holder->connected_subchannel != NULL) {
+    gpr_atm_rel_store(
+        &holder->subchannel_call,
+        (gpr_atm)(uintptr_t)grpc_connected_subchannel_create_call(
+            exec_ctx, holder->connected_subchannel, holder->pollset));
+    retry_waiting_locked(exec_ctx, holder);
+    goto retry;
+  }
+  /* nothing to be done but wait */
+  add_waiting_locked(holder, op);
+  gpr_mu_unlock(&holder->mu);
+  GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
+}
+
+static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  grpc_subchannel_call_holder *holder = arg;
+  gpr_mu_lock(&holder->mu);
+  GPR_ASSERT(holder->creation_phase ==
+             GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL);
+  holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
+  if (holder->connected_subchannel == NULL) {
+    fail_locked(exec_ctx, holder);
+  } else if (1 == gpr_atm_acq_load(&holder->subchannel_call)) {
+    /* already cancelled before subchannel became ready */
+    fail_locked(exec_ctx, holder);
+  } else {
+    gpr_atm_rel_store(
+        &holder->subchannel_call,
+        (gpr_atm)(uintptr_t)grpc_connected_subchannel_create_call(
+            exec_ctx, holder->connected_subchannel, holder->pollset));
+    retry_waiting_locked(exec_ctx, holder);
+  }
+  gpr_mu_unlock(&holder->mu);
+  GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel");
+}
+
+typedef struct {
+  grpc_transport_stream_op *ops;
+  size_t nops;
+  grpc_subchannel_call *call;
+} retry_ops_args;
+
+static void retry_waiting_locked(grpc_exec_ctx *exec_ctx,
+                                 grpc_subchannel_call_holder *holder) {
+  retry_ops_args *a = gpr_malloc(sizeof(*a));
+  a->ops = holder->waiting_ops;
+  a->nops = holder->waiting_ops_count;
+  a->call = GET_CALL(holder);
+  if (a->call == CANCELLED_CALL) {
+    gpr_free(a);
+    fail_locked(exec_ctx, holder);
+    return;
+  }
+  holder->waiting_ops = NULL;
+  holder->waiting_ops_count = 0;
+  holder->waiting_ops_capacity = 0;
+  GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops");
+  grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(retry_ops, a), true,
+                        NULL);
+}
+
+static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, bool success) {
+  retry_ops_args *a = args;
+  size_t i;
+  for (i = 0; i < a->nops; i++) {
+    grpc_subchannel_call_process_op(exec_ctx, a->call, &a->ops[i]);
+  }
+  GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, a->call, "retry_ops");
+  gpr_free(a->ops);
+  gpr_free(a);
+}
+
+static void add_waiting_locked(grpc_subchannel_call_holder *holder,
+                               grpc_transport_stream_op *op) {
+  GPR_TIMER_BEGIN("add_waiting_locked", 0);
+  if (holder->waiting_ops_count == holder->waiting_ops_capacity) {
+    holder->waiting_ops_capacity = GPR_MAX(3, 2 * holder->waiting_ops_capacity);
+    holder->waiting_ops =
+        gpr_realloc(holder->waiting_ops, holder->waiting_ops_capacity *
+                                             sizeof(*holder->waiting_ops));
+  }
+  holder->waiting_ops[holder->waiting_ops_count++] = *op;
+  GPR_TIMER_END("add_waiting_locked", 0);
+}
+
+static void fail_locked(grpc_exec_ctx *exec_ctx,
+                        grpc_subchannel_call_holder *holder) {
+  size_t i;
+  for (i = 0; i < holder->waiting_ops_count; i++) {
+    grpc_transport_stream_op_finish_with_failure(exec_ctx,
+                                                 &holder->waiting_ops[i]);
+  }
+  holder->waiting_ops_count = 0;
+}
+
+char *grpc_subchannel_call_holder_get_peer(
+    grpc_exec_ctx *exec_ctx, grpc_subchannel_call_holder *holder) {
+  grpc_subchannel_call *subchannel_call = GET_CALL(holder);
+
+  if (subchannel_call) {
+    return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call);
+  } else {
+    return NULL;
+  }
+}
diff --git a/src/core/lib/channel/subchannel_call_holder.h b/src/core/lib/channel/subchannel_call_holder.h
new file mode 100644
index 0000000..882f366
--- /dev/null
+++ b/src/core/lib/channel/subchannel_call_holder.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_SUBCHANNEL_CALL_HOLDER_H
+#define GRPC_CORE_LIB_CHANNEL_SUBCHANNEL_CALL_HOLDER_H
+
+#include "src/core/lib/client_config/subchannel.h"
+
+/** Pick a subchannel for grpc_subchannel_call_holder;
+    Return 1 if subchannel is available immediately (in which case on_ready
+    should not be called), or 0 otherwise (in which case on_ready should be
+    called when the subchannel is available) */
+typedef int (*grpc_subchannel_call_holder_pick_subchannel)(
+    grpc_exec_ctx *exec_ctx, void *arg, grpc_metadata_batch *initial_metadata,
+    grpc_connected_subchannel **connected_subchannel, grpc_closure *on_ready);
+
+typedef enum {
+  GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING,
+  GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL
+} grpc_subchannel_call_holder_creation_phase;
+
+/** Wrapper for holding a pointer to grpc_subchannel_call, and the
+    associated machinery to create such a pointer.
+    Handles queueing of stream ops until a call object is ready, waiting
+    for initial metadata before trying to create a call object,
+    and handling cancellation gracefully.
+
+    The channel filter uses this as their call_data. */
+typedef struct grpc_subchannel_call_holder {
+  /** either 0 for no call, 1 for cancelled, or a pointer to a
+      grpc_subchannel_call */
+  gpr_atm subchannel_call;
+  /** Helper function to choose the subchannel on which to create
+      the call object. Channel filter delegates to the load
+      balancing policy (once it's ready). */
+  grpc_subchannel_call_holder_pick_subchannel pick_subchannel;
+  void *pick_subchannel_arg;
+
+  gpr_mu mu;
+
+  grpc_subchannel_call_holder_creation_phase creation_phase;
+  grpc_connected_subchannel *connected_subchannel;
+  grpc_pollset *pollset;
+
+  grpc_transport_stream_op *waiting_ops;
+  size_t waiting_ops_count;
+  size_t waiting_ops_capacity;
+
+  grpc_closure next_step;
+
+  grpc_call_stack *owning_call;
+} grpc_subchannel_call_holder;
+
+void grpc_subchannel_call_holder_init(
+    grpc_subchannel_call_holder *holder,
+    grpc_subchannel_call_holder_pick_subchannel pick_subchannel,
+    void *pick_subchannel_arg, grpc_call_stack *owning_call);
+void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx,
+                                         grpc_subchannel_call_holder *holder);
+
+void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx,
+                                            grpc_subchannel_call_holder *holder,
+                                            grpc_transport_stream_op *op);
+char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx,
+                                           grpc_subchannel_call_holder *holder);
+
+#endif /* GRPC_CORE_LIB_CHANNEL_SUBCHANNEL_CALL_HOLDER_H */
diff --git a/src/core/client_config/README.md b/src/core/lib/client_config/README.md
similarity index 100%
rename from src/core/client_config/README.md
rename to src/core/lib/client_config/README.md
diff --git a/src/core/lib/client_config/client_config.c b/src/core/lib/client_config/client_config.c
new file mode 100644
index 0000000..82c8d68
--- /dev/null
+++ b/src/core/lib/client_config/client_config.c
@@ -0,0 +1,74 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/client_config.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.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_exec_ctx *exec_ctx, grpc_client_config *c) {
+  if (gpr_unref(&c->refs)) {
+    if (c->lb_policy != NULL) {
+      GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "client_config");
+    }
+    gpr_free(c);
+  }
+}
+
+void grpc_client_config_set_lb_policy(grpc_client_config *c,
+                                      grpc_lb_policy *lb_policy) {
+  GPR_ASSERT(c->lb_policy == NULL);
+  if (lb_policy) {
+    GRPC_LB_POLICY_REF(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/lib/client_config/client_config.h b/src/core/lib/client_config/client_config.h
new file mode 100644
index 0000000..404ec0d
--- /dev/null
+++ b/src/core/lib/client_config/client_config.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_CLIENT_CONFIG_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_CLIENT_CONFIG_H
+
+#include "src/core/lib/client_config/lb_policy.h"
+
+/** Total configuration for a client. Provided, and updated, by
+    grpc_resolver */
+typedef struct grpc_client_config grpc_client_config;
+
+grpc_client_config *grpc_client_config_create();
+void grpc_client_config_ref(grpc_client_config *client_config);
+void grpc_client_config_unref(grpc_exec_ctx *exec_ctx,
+                              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_CORE_LIB_CLIENT_CONFIG_CLIENT_CONFIG_H */
diff --git a/src/core/lib/client_config/connector.c b/src/core/lib/client_config/connector.c
new file mode 100644
index 0000000..f51d862
--- /dev/null
+++ b/src/core/lib/client_config/connector.c
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/connector.h"
+
+grpc_connector* grpc_connector_ref(grpc_connector* connector) {
+  connector->vtable->ref(connector);
+  return connector;
+}
+
+void grpc_connector_unref(grpc_exec_ctx* exec_ctx, grpc_connector* connector) {
+  connector->vtable->unref(exec_ctx, connector);
+}
+
+void grpc_connector_connect(grpc_exec_ctx* exec_ctx, grpc_connector* connector,
+                            const grpc_connect_in_args* in_args,
+                            grpc_connect_out_args* out_args,
+                            grpc_closure* notify) {
+  connector->vtable->connect(exec_ctx, connector, in_args, out_args, notify);
+}
+
+void grpc_connector_shutdown(grpc_exec_ctx* exec_ctx,
+                             grpc_connector* connector) {
+  connector->vtable->shutdown(exec_ctx, connector);
+}
diff --git a/src/core/lib/client_config/connector.h b/src/core/lib/client_config/connector.h
new file mode 100644
index 0000000..21b925a
--- /dev/null
+++ b/src/core/lib/client_config/connector.h
@@ -0,0 +1,92 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_CONNECTOR_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_CONNECTOR_H
+
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/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;
+  size_t addr_len;
+  /** initial connect string to send */
+  gpr_slice initial_connect_string;
+  /** deadline for connection */
+  gpr_timespec deadline;
+  /** channel arguments (to be passed to transport) */
+  const grpc_channel_args *channel_args;
+} grpc_connect_in_args;
+
+typedef struct {
+  /** the connected transport */
+  grpc_transport *transport;
+
+  /** channel arguments (to be passed to the filters) */
+  const grpc_channel_args *channel_args;
+} grpc_connect_out_args;
+
+struct grpc_connector_vtable {
+  void (*ref)(grpc_connector *connector);
+  void (*unref)(grpc_exec_ctx *exec_ctx, grpc_connector *connector);
+  /** Implementation of grpc_connector_shutdown */
+  void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_connector *connector);
+  /** Implementation of grpc_connector_connect */
+  void (*connect)(grpc_exec_ctx *exec_ctx, grpc_connector *connector,
+                  const grpc_connect_in_args *in_args,
+                  grpc_connect_out_args *out_args, grpc_closure *notify);
+};
+
+grpc_connector *grpc_connector_ref(grpc_connector *connector);
+void grpc_connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *connector);
+/** Connect using the connector: max one outstanding call at a time */
+void grpc_connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *connector,
+                            const grpc_connect_in_args *in_args,
+                            grpc_connect_out_args *out_args,
+                            grpc_closure *notify);
+/** Cancel any pending connection */
+void grpc_connector_shutdown(grpc_exec_ctx *exec_ctx,
+                             grpc_connector *connector);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_CONNECTOR_H */
diff --git a/src/core/lib/client_config/default_initial_connect_string.c b/src/core/lib/client_config/default_initial_connect_string.c
new file mode 100644
index 0000000..86eb37d
--- /dev/null
+++ b/src/core/lib/client_config/default_initial_connect_string.c
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/slice.h>
+#include "src/core/lib/iomgr/sockaddr.h"
+
+void grpc_set_default_initial_connect_string(struct sockaddr **addr,
+                                             size_t *addr_len,
+                                             gpr_slice *initial_str) {}
diff --git a/src/core/lib/client_config/initial_connect_string.c b/src/core/lib/client_config/initial_connect_string.c
new file mode 100644
index 0000000..95ae728
--- /dev/null
+++ b/src/core/lib/client_config/initial_connect_string.c
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/initial_connect_string.h"
+
+#include <stddef.h>
+
+extern void grpc_set_default_initial_connect_string(struct sockaddr **addr,
+                                                    size_t *addr_len,
+                                                    gpr_slice *initial_str);
+
+static grpc_set_initial_connect_string_func g_set_initial_connect_string_func =
+    grpc_set_default_initial_connect_string;
+
+void grpc_test_set_initial_connect_string_function(
+    grpc_set_initial_connect_string_func func) {
+  g_set_initial_connect_string_func = func;
+}
+
+void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len,
+                                     gpr_slice *initial_str) {
+  g_set_initial_connect_string_func(addr, addr_len, initial_str);
+}
diff --git a/src/core/lib/client_config/initial_connect_string.h b/src/core/lib/client_config/initial_connect_string.h
new file mode 100644
index 0000000..eec42fa
--- /dev/null
+++ b/src/core/lib/client_config/initial_connect_string.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H
+
+#include <grpc/support/slice.h>
+#include "src/core/lib/iomgr/sockaddr.h"
+
+typedef void (*grpc_set_initial_connect_string_func)(struct sockaddr **addr,
+                                                     size_t *addr_len,
+                                                     gpr_slice *initial_str);
+void grpc_test_set_initial_connect_string_function(
+    grpc_set_initial_connect_string_func func);
+
+/** Set a string to be sent once connected. Optionally reset addr. */
+void grpc_set_initial_connect_string(struct sockaddr **addr, size_t *addr_len,
+                                     gpr_slice *connect_string);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_INITIAL_CONNECT_STRING_H */
diff --git a/src/core/lib/client_config/lb_policies/load_balancer_api.c b/src/core/lib/client_config/lb_policies/load_balancer_api.c
new file mode 100644
index 0000000..4cbed20
--- /dev/null
+++ b/src/core/lib/client_config/lb_policies/load_balancer_api.c
@@ -0,0 +1,163 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/lb_policies/load_balancer_api.h"
+#include "third_party/nanopb/pb_decode.h"
+#include "third_party/nanopb/pb_encode.h"
+
+#include <grpc/support/alloc.h>
+
+typedef struct decode_serverlist_arg {
+  int first_pass;
+  int i;
+  size_t num_servers;
+  grpc_grpclb_server **servers;
+} decode_serverlist_arg;
+
+/* invoked once for every Server in ServerList */
+static bool decode_serverlist(pb_istream_t *stream, const pb_field_t *field,
+                              void **arg) {
+  decode_serverlist_arg *dec_arg = *arg;
+  if (dec_arg->first_pass != 0) { /* first pass */
+    grpc_grpclb_server server;
+    if (!pb_decode(stream, grpc_lb_v0_Server_fields, &server)) {
+      return false;
+    }
+    dec_arg->num_servers++;
+  } else { /* second pass */
+    grpc_grpclb_server *server = gpr_malloc(sizeof(grpc_grpclb_server));
+    GPR_ASSERT(dec_arg->num_servers > 0);
+    if (dec_arg->i == 0) { /* first iteration of second pass */
+      dec_arg->servers =
+          gpr_malloc(sizeof(grpc_grpclb_server *) * dec_arg->num_servers);
+    }
+    if (!pb_decode(stream, grpc_lb_v0_Server_fields, server)) {
+      return false;
+    }
+    dec_arg->servers[dec_arg->i++] = server;
+  }
+
+  return true;
+}
+
+grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name) {
+  grpc_grpclb_request *req = gpr_malloc(sizeof(grpc_grpclb_request));
+
+  req->has_client_stats = 0; /* TODO(dgq): add support for stats once defined */
+  req->has_initial_request = 1;
+  req->initial_request.has_name = 1;
+  strncpy(req->initial_request.name, lb_service_name,
+          GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH);
+  return req;
+}
+
+gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request) {
+  size_t encoded_length;
+  pb_ostream_t sizestream;
+  pb_ostream_t outputstream;
+  gpr_slice slice;
+  memset(&sizestream, 0, sizeof(pb_ostream_t));
+  pb_encode(&sizestream, grpc_lb_v0_LoadBalanceRequest_fields, request);
+  encoded_length = sizestream.bytes_written;
+
+  slice = gpr_slice_malloc(encoded_length);
+  outputstream =
+      pb_ostream_from_buffer(GPR_SLICE_START_PTR(slice), encoded_length);
+  GPR_ASSERT(pb_encode(&outputstream, grpc_lb_v0_LoadBalanceRequest_fields,
+                       request) != 0);
+  return slice;
+}
+
+void grpc_grpclb_request_destroy(grpc_grpclb_request *request) {
+  gpr_free(request);
+}
+
+grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response) {
+  bool status;
+  pb_istream_t stream =
+      pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response),
+                             GPR_SLICE_LENGTH(encoded_response));
+  grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response));
+  memset(res, 0, sizeof(*res));
+  status = pb_decode(&stream, grpc_lb_v0_LoadBalanceResponse_fields, res);
+  GPR_ASSERT(status == true);
+  return res;
+}
+
+grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
+    gpr_slice encoded_response) {
+  grpc_grpclb_serverlist *sl = gpr_malloc(sizeof(grpc_grpclb_serverlist));
+  bool status;
+  decode_serverlist_arg arg;
+  pb_istream_t stream =
+      pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response),
+                             GPR_SLICE_LENGTH(encoded_response));
+  pb_istream_t stream_at_start = stream;
+  grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response));
+  memset(res, 0, sizeof(*res));
+  memset(&arg, 0, sizeof(decode_serverlist_arg));
+
+  res->server_list.servers.funcs.decode = decode_serverlist;
+  res->server_list.servers.arg = &arg;
+  arg.first_pass = 1;
+  status = pb_decode(&stream, grpc_lb_v0_LoadBalanceResponse_fields, res);
+  GPR_ASSERT(status == true);
+  GPR_ASSERT(arg.num_servers > 0);
+
+  arg.first_pass = 0;
+  status =
+      pb_decode(&stream_at_start, grpc_lb_v0_LoadBalanceResponse_fields, res);
+  GPR_ASSERT(status == true);
+  GPR_ASSERT(arg.servers != NULL);
+
+  sl->num_servers = arg.num_servers;
+  sl->servers = arg.servers;
+  if (res->server_list.has_expiration_interval) {
+    sl->expiration_interval = res->server_list.expiration_interval;
+  }
+  grpc_grpclb_response_destroy(res);
+  return sl;
+}
+
+void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist) {
+  size_t i;
+  for (i = 0; i < serverlist->num_servers; i++) {
+    gpr_free(serverlist->servers[i]);
+  }
+  gpr_free(serverlist->servers);
+  gpr_free(serverlist);
+}
+
+void grpc_grpclb_response_destroy(grpc_grpclb_response *response) {
+  gpr_free(response);
+}
diff --git a/src/core/lib/client_config/lb_policies/load_balancer_api.h b/src/core/lib/client_config/lb_policies/load_balancer_api.h
new file mode 100644
index 0000000..83299ad
--- /dev/null
+++ b/src/core/lib/client_config/lb_policies/load_balancer_api.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H
+
+#include <grpc/support/slice_buffer.h>
+
+#include "src/core/lib/client_config/lb_policy_factory.h"
+#include "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128
+
+typedef grpc_lb_v0_LoadBalanceRequest grpc_grpclb_request;
+typedef grpc_lb_v0_LoadBalanceResponse grpc_grpclb_response;
+typedef grpc_lb_v0_Server grpc_grpclb_server;
+typedef grpc_lb_v0_Duration grpc_grpclb_duration;
+typedef struct grpc_grpclb_serverlist {
+  grpc_grpclb_server **servers;
+  size_t num_servers;
+  grpc_grpclb_duration expiration_interval;
+} grpc_grpclb_serverlist;
+
+/** Create a request for a gRPC LB service under \a lb_service_name */
+grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name);
+
+/** Protocol Buffers v3-encode \a request */
+gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request);
+
+/** Destroy \a request */
+void grpc_grpclb_request_destroy(grpc_grpclb_request *request);
+
+/** Parse (ie, decode) the bytes in \a encoded_response as a \a
+ * grpc_grpclb_response */
+grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response);
+
+/** Destroy \a serverlist */
+void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist);
+
+/** Parse the list of servers from an encoded \a grpc_grpclb_response */
+grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
+    gpr_slice encoded_response);
+
+/** Destroy \a response */
+void grpc_grpclb_response_destroy(grpc_grpclb_response *response);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICIES_LOAD_BALANCER_API_H */
diff --git a/src/core/lib/client_config/lb_policies/pick_first.c b/src/core/lib/client_config/lb_policies/pick_first.c
new file mode 100644
index 0000000..9ac550d9
--- /dev/null
+++ b/src/core/lib/client_config/lb_policies/pick_first.c
@@ -0,0 +1,444 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/lb_policies/pick_first.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include "src/core/lib/client_config/lb_policy_factory.h"
+#include "src/core/lib/transport/connectivity_state.h"
+
+typedef struct pending_pick {
+  struct pending_pick *next;
+  grpc_pollset *pollset;
+  grpc_connected_subchannel **target;
+  grpc_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_closure connectivity_changed;
+
+  /** the selected channel (a grpc_connected_subchannel) */
+  gpr_atm selected;
+
+  /** mutex protecting remaining members */
+  gpr_mu mu;
+  /** have we started picking? */
+  int started_picking;
+  /** are we shut down? */
+  int shutdown;
+  /** 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;
+
+#define GET_SELECTED(p) \
+  ((grpc_connected_subchannel *)gpr_atm_acq_load(&(p)->selected))
+
+void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  grpc_connected_subchannel *selected = GET_SELECTED(p);
+  size_t i;
+  GPR_ASSERT(p->pending_picks == NULL);
+  for (i = 0; i < p->num_subchannels; i++) {
+    GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first");
+  }
+  if (selected != NULL) {
+    GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, selected, "picked_first");
+  }
+  grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
+  gpr_free(p->subchannels);
+  gpr_mu_destroy(&p->mu);
+  gpr_free(p);
+}
+
+void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  pending_pick *pp;
+  grpc_connected_subchannel *selected;
+  gpr_mu_lock(&p->mu);
+  selected = GET_SELECTED(p);
+  p->shutdown = 1;
+  pp = p->pending_picks;
+  p->pending_picks = NULL;
+  grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                              GRPC_CHANNEL_FATAL_FAILURE, "shutdown");
+  /* cancel subscription */
+  if (selected != NULL) {
+    grpc_connected_subchannel_notify_on_state_change(
+        exec_ctx, selected, NULL, NULL, &p->connectivity_changed);
+  } else {
+    grpc_subchannel_notify_on_state_change(
+        exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL,
+        &p->connectivity_changed);
+  }
+  gpr_mu_unlock(&p->mu);
+  while (pp != NULL) {
+    pending_pick *next = pp->next;
+    *pp->target = NULL;
+    grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
+                                 pp->pollset);
+    grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
+    gpr_free(pp);
+    pp = next;
+  }
+}
+
+static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+                           grpc_connected_subchannel **target) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  pending_pick *pp;
+  gpr_mu_lock(&p->mu);
+  pp = p->pending_picks;
+  p->pending_picks = NULL;
+  while (pp != NULL) {
+    pending_pick *next = pp->next;
+    if (pp->target == target) {
+      grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
+                                   pp->pollset);
+      *target = NULL;
+      grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
+      gpr_free(pp);
+    } else {
+      pp->next = p->pending_picks;
+      p->pending_picks = pp;
+    }
+    pp = next;
+  }
+  gpr_mu_unlock(&p->mu);
+}
+
+static void start_picking(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p) {
+  p->started_picking = 1;
+  p->checking_subchannel = 0;
+  p->checking_connectivity = GRPC_CHANNEL_IDLE;
+  GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity");
+  grpc_subchannel_notify_on_state_change(
+      exec_ctx, p->subchannels[p->checking_subchannel],
+      p->base.interested_parties, &p->checking_connectivity,
+      &p->connectivity_changed);
+}
+
+void pf_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  gpr_mu_lock(&p->mu);
+  if (!p->started_picking) {
+    start_picking(exec_ctx, p);
+  }
+  gpr_mu_unlock(&p->mu);
+}
+
+int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
+            grpc_metadata_batch *initial_metadata,
+            grpc_connected_subchannel **target, grpc_closure *on_complete) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  pending_pick *pp;
+
+  /* Check atomically for a selected channel */
+  grpc_connected_subchannel *selected = GET_SELECTED(p);
+  if (selected != NULL) {
+    *target = selected;
+    return 1;
+  }
+
+  /* No subchannel selected yet, so acquire lock and then attempt again */
+  gpr_mu_lock(&p->mu);
+  selected = GET_SELECTED(p);
+  if (selected) {
+    gpr_mu_unlock(&p->mu);
+    *target = selected;
+    return 1;
+  } else {
+    if (!p->started_picking) {
+      start_picking(exec_ctx, p);
+    }
+    grpc_pollset_set_add_pollset(exec_ctx, p->base.interested_parties, 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);
+    return 0;
+  }
+}
+
+static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
+                                bool iomgr_success) {
+  pick_first_lb_policy *p = arg;
+  size_t i;
+  size_t num_subchannels = p->num_subchannels;
+  grpc_subchannel **subchannels;
+
+  gpr_mu_lock(&p->mu);
+  subchannels = p->subchannels;
+  p->num_subchannels = 0;
+  p->subchannels = NULL;
+  gpr_mu_unlock(&p->mu);
+  GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels");
+
+  for (i = 0; i < num_subchannels; i++) {
+    GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first");
+  }
+
+  gpr_free(subchannels);
+}
+
+static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
+                                    bool iomgr_success) {
+  pick_first_lb_policy *p = arg;
+  grpc_subchannel *selected_subchannel;
+  pending_pick *pp;
+  grpc_connected_subchannel *selected;
+
+  gpr_mu_lock(&p->mu);
+
+  selected = GET_SELECTED(p);
+
+  if (p->shutdown) {
+    gpr_mu_unlock(&p->mu);
+    GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
+    return;
+  } else if (selected != NULL) {
+    if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
+      /* if the selected channel goes bad, we're done */
+      p->checking_connectivity = GRPC_CHANNEL_FATAL_FAILURE;
+    }
+    grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                                p->checking_connectivity, "selected_changed");
+    if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) {
+      grpc_connected_subchannel_notify_on_state_change(
+          exec_ctx, selected, p->base.interested_parties,
+          &p->checking_connectivity, &p->connectivity_changed);
+    } else {
+      GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
+    }
+  } else {
+  loop:
+    switch (p->checking_connectivity) {
+      case GRPC_CHANNEL_READY:
+        grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                                    GRPC_CHANNEL_READY, "connecting_ready");
+        selected_subchannel = p->subchannels[p->checking_subchannel];
+        selected =
+            grpc_subchannel_get_connected_subchannel(selected_subchannel);
+        GPR_ASSERT(selected != NULL);
+        GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked_first");
+        /* drop the pick list: we are connected now */
+        GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
+        gpr_atm_rel_store(&p->selected, (gpr_atm)selected);
+        grpc_exec_ctx_enqueue(
+            exec_ctx, grpc_closure_create(destroy_subchannels, p), true, NULL);
+        /* update any calls that were waiting for a pick */
+        while ((pp = p->pending_picks)) {
+          p->pending_picks = pp->next;
+          *pp->target = selected;
+          grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
+                                       pp->pollset);
+          grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
+          gpr_free(pp);
+        }
+        grpc_connected_subchannel_notify_on_state_change(
+            exec_ctx, selected, p->base.interested_parties,
+            &p->checking_connectivity, &p->connectivity_changed);
+        break;
+      case GRPC_CHANNEL_TRANSIENT_FAILURE:
+        grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                                    GRPC_CHANNEL_TRANSIENT_FAILURE,
+                                    "connecting_transient_failure");
+        p->checking_subchannel =
+            (p->checking_subchannel + 1) % p->num_subchannels;
+        p->checking_connectivity = grpc_subchannel_check_connectivity(
+            p->subchannels[p->checking_subchannel]);
+        if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
+          grpc_subchannel_notify_on_state_change(
+              exec_ctx, p->subchannels[p->checking_subchannel],
+              p->base.interested_parties, &p->checking_connectivity,
+              &p->connectivity_changed);
+        } else {
+          goto loop;
+        }
+        break;
+      case GRPC_CHANNEL_CONNECTING:
+      case GRPC_CHANNEL_IDLE:
+        grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                                    GRPC_CHANNEL_CONNECTING,
+                                    "connecting_changed");
+        grpc_subchannel_notify_on_state_change(
+            exec_ctx, p->subchannels[p->checking_subchannel],
+            p->base.interested_parties, &p->checking_connectivity,
+            &p->connectivity_changed);
+        break;
+      case GRPC_CHANNEL_FATAL_FAILURE:
+        p->num_subchannels--;
+        GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
+                 p->subchannels[p->num_subchannels]);
+        GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels],
+                              "pick_first");
+        if (p->num_subchannels == 0) {
+          grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                                      GRPC_CHANNEL_FATAL_FAILURE,
+                                      "no_more_channels");
+          while ((pp = p->pending_picks)) {
+            p->pending_picks = pp->next;
+            *pp->target = NULL;
+            grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
+            gpr_free(pp);
+          }
+          GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base,
+                                    "pick_first_connectivity");
+        } else {
+          grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                                      GRPC_CHANNEL_TRANSIENT_FAILURE,
+                                      "subchannel_failed");
+          p->checking_subchannel %= p->num_subchannels;
+          p->checking_connectivity = grpc_subchannel_check_connectivity(
+              p->subchannels[p->checking_subchannel]);
+          goto loop;
+        }
+    }
+  }
+
+  gpr_mu_unlock(&p->mu);
+}
+
+static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx,
+                                                     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;
+}
+
+void pf_notify_on_state_change(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+                               grpc_connectivity_state *current,
+                               grpc_closure *notify) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  gpr_mu_lock(&p->mu);
+  grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker,
+                                                 current, notify);
+  gpr_mu_unlock(&p->mu);
+}
+
+void pf_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+                 grpc_closure *closure) {
+  pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+  grpc_connected_subchannel *selected = GET_SELECTED(p);
+  if (selected) {
+    grpc_connected_subchannel_ping(exec_ctx, selected, closure);
+  } else {
+    grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
+  }
+}
+
+static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
+    pf_destroy,
+    pf_shutdown,
+    pf_pick,
+    pf_cancel_pick,
+    pf_ping_one,
+    pf_exit_idle,
+    pf_check_connectivity,
+    pf_notify_on_state_change};
+
+static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {}
+
+static void pick_first_factory_unref(grpc_lb_policy_factory *factory) {}
+
+static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx,
+                                         grpc_lb_policy_factory *factory,
+                                         grpc_lb_policy_args *args) {
+  GPR_ASSERT(args->addresses != NULL);
+  GPR_ASSERT(args->subchannel_factory != NULL);
+
+  if (args->addresses->naddrs == 0) return NULL;
+
+  pick_first_lb_policy *p = gpr_malloc(sizeof(*p));
+  memset(p, 0, sizeof(*p));
+
+  p->subchannels =
+      gpr_malloc(sizeof(grpc_subchannel *) * args->addresses->naddrs);
+  memset(p->subchannels, 0, sizeof(*p->subchannels) * args->addresses->naddrs);
+  grpc_subchannel_args sc_args;
+  size_t subchannel_idx = 0;
+  for (size_t i = 0; i < args->addresses->naddrs; i++) {
+    memset(&sc_args, 0, sizeof(grpc_subchannel_args));
+    sc_args.addr = (struct sockaddr *)(args->addresses->addrs[i].addr);
+    sc_args.addr_len = (size_t)args->addresses->addrs[i].len;
+
+    grpc_subchannel *subchannel = grpc_subchannel_factory_create_subchannel(
+        exec_ctx, args->subchannel_factory, &sc_args);
+
+    if (subchannel != NULL) {
+      p->subchannels[subchannel_idx++] = subchannel;
+    }
+  }
+  if (subchannel_idx == 0) {
+    gpr_free(p->subchannels);
+    gpr_free(p);
+    return NULL;
+  }
+  p->num_subchannels = subchannel_idx;
+
+  grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable);
+  grpc_closure_init(&p->connectivity_changed, pf_connectivity_changed, p);
+  gpr_mu_init(&p->mu);
+  return &p->base;
+}
+
+static const grpc_lb_policy_factory_vtable pick_first_factory_vtable = {
+    pick_first_factory_ref, pick_first_factory_unref, create_pick_first,
+    "pick_first"};
+
+static grpc_lb_policy_factory pick_first_lb_policy_factory = {
+    &pick_first_factory_vtable};
+
+grpc_lb_policy_factory *grpc_pick_first_lb_factory_create() {
+  return &pick_first_lb_policy_factory;
+}
diff --git a/src/core/lib/client_config/lb_policies/pick_first.h b/src/core/lib/client_config/lb_policies/pick_first.h
new file mode 100644
index 0000000..dba86ea
--- /dev/null
+++ b/src/core/lib/client_config/lb_policies/pick_first.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICIES_PICK_FIRST_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICIES_PICK_FIRST_H
+
+#include "src/core/lib/client_config/lb_policy_factory.h"
+
+/** Returns a load balancing factory for the pick first policy, which picks up
+ * the first subchannel from \a subchannels to succesfully connect */
+grpc_lb_policy_factory *grpc_pick_first_lb_factory_create();
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICIES_PICK_FIRST_H */
diff --git a/src/core/lib/client_config/lb_policies/round_robin.c b/src/core/lib/client_config/lb_policies/round_robin.c
new file mode 100644
index 0000000..a4bc2c4
--- /dev/null
+++ b/src/core/lib/client_config/lb_policies/round_robin.c
@@ -0,0 +1,563 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/lb_policies/round_robin.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include "src/core/lib/transport/connectivity_state.h"
+
+typedef struct round_robin_lb_policy round_robin_lb_policy;
+
+int grpc_lb_round_robin_trace = 0;
+
+/** List of entities waiting for a pick.
+ *
+ * Once a pick is available, \a target is updated and \a on_complete called. */
+typedef struct pending_pick {
+  struct pending_pick *next;
+  grpc_pollset *pollset;
+  grpc_connected_subchannel **target;
+  grpc_closure *on_complete;
+} pending_pick;
+
+/** List of subchannels in a connectivity READY state */
+typedef struct ready_list {
+  grpc_subchannel *subchannel;
+  struct ready_list *next;
+  struct ready_list *prev;
+} ready_list;
+
+typedef struct {
+  /** index within policy->subchannels */
+  size_t index;
+  /** backpointer to owning policy */
+  round_robin_lb_policy *policy;
+  /** subchannel itself */
+  grpc_subchannel *subchannel;
+  /** notification that connectivity has changed on subchannel */
+  grpc_closure connectivity_changed_closure;
+  /** this subchannels current position in subchannel->ready_list */
+  ready_list *ready_list_node;
+  /** last observed connectivity */
+  grpc_connectivity_state connectivity_state;
+} subchannel_data;
+
+struct round_robin_lb_policy {
+  /** base policy: must be first */
+  grpc_lb_policy base;
+
+  /** all our subchannels */
+  size_t num_subchannels;
+  subchannel_data **subchannels;
+
+  /** mutex protecting remaining members */
+  gpr_mu mu;
+  /** have we started picking? */
+  int started_picking;
+  /** are we shutting down? */
+  int shutdown;
+  /** List of picks that are waiting on connectivity */
+  pending_pick *pending_picks;
+
+  /** our connectivity state tracker */
+  grpc_connectivity_state_tracker state_tracker;
+
+  /** (Dummy) root of the doubly linked list containing READY subchannels */
+  ready_list ready_list;
+  /** Last pick from the ready list. */
+  ready_list *ready_list_last_pick;
+};
+
+/** Returns the next subchannel from the connected list or NULL if the list is
+ * empty.
+ *
+ * Note that this function does *not* advance p->ready_list_last_pick. Use \a
+ * advance_last_picked_locked() for that. */
+static ready_list *peek_next_connected_locked(const round_robin_lb_policy *p) {
+  ready_list *selected;
+  selected = p->ready_list_last_pick->next;
+
+  while (selected != NULL) {
+    if (selected == &p->ready_list) {
+      GPR_ASSERT(selected->subchannel == NULL);
+      /* skip dummy root */
+      selected = selected->next;
+    } else {
+      GPR_ASSERT(selected->subchannel != NULL);
+      return selected;
+    }
+  }
+  return NULL;
+}
+
+/** Advance the \a ready_list picking head. */
+static void advance_last_picked_locked(round_robin_lb_policy *p) {
+  if (p->ready_list_last_pick->next != NULL) { /* non-empty list */
+    p->ready_list_last_pick = p->ready_list_last_pick->next;
+    if (p->ready_list_last_pick == &p->ready_list) {
+      /* skip dummy root */
+      p->ready_list_last_pick = p->ready_list_last_pick->next;
+    }
+  } else { /* should be an empty list */
+    GPR_ASSERT(p->ready_list_last_pick == &p->ready_list);
+  }
+
+  if (grpc_lb_round_robin_trace) {
+    gpr_log(GPR_DEBUG, "[READYLIST] ADVANCED LAST PICK. NOW AT NODE %p (SC %p)",
+            p->ready_list_last_pick, p->ready_list_last_pick->subchannel);
+  }
+}
+
+/** Prepends (relative to the root at p->ready_list) the connected subchannel \a
+ * csc to the list of ready subchannels. */
+static ready_list *add_connected_sc_locked(round_robin_lb_policy *p,
+                                           grpc_subchannel *sc) {
+  ready_list *new_elem = gpr_malloc(sizeof(ready_list));
+  new_elem->subchannel = sc;
+  if (p->ready_list.prev == NULL) {
+    /* first element */
+    new_elem->next = &p->ready_list;
+    new_elem->prev = &p->ready_list;
+    p->ready_list.next = new_elem;
+    p->ready_list.prev = new_elem;
+  } else {
+    new_elem->next = &p->ready_list;
+    new_elem->prev = p->ready_list.prev;
+    p->ready_list.prev->next = new_elem;
+    p->ready_list.prev = new_elem;
+  }
+  if (grpc_lb_round_robin_trace) {
+    gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (SC %p)", new_elem, sc);
+  }
+  return new_elem;
+}
+
+/** Removes \a node from the list of connected subchannels */
+static void remove_disconnected_sc_locked(round_robin_lb_policy *p,
+                                          ready_list *node) {
+  if (node == NULL) {
+    return;
+  }
+  if (node == p->ready_list_last_pick) {
+    /* If removing the lastly picked node, reset the last pick pointer to the
+     * dummy root of the list */
+    p->ready_list_last_pick = &p->ready_list;
+  }
+
+  /* removing last item */
+  if (node->next == &p->ready_list && node->prev == &p->ready_list) {
+    GPR_ASSERT(p->ready_list.next == node);
+    GPR_ASSERT(p->ready_list.prev == node);
+    p->ready_list.next = NULL;
+    p->ready_list.prev = NULL;
+  } else {
+    node->prev->next = node->next;
+    node->next->prev = node->prev;
+  }
+
+  if (grpc_lb_round_robin_trace) {
+    gpr_log(GPR_DEBUG, "[READYLIST] REMOVED NODE %p (SC %p)", node,
+            node->subchannel);
+  }
+
+  node->next = NULL;
+  node->prev = NULL;
+  node->subchannel = NULL;
+
+  gpr_free(node);
+}
+
+void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
+  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
+  size_t i;
+  ready_list *elem;
+  for (i = 0; i < p->num_subchannels; i++) {
+    subchannel_data *sd = p->subchannels[i];
+    GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin");
+    gpr_free(sd);
+  }
+
+  grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
+  gpr_free(p->subchannels);
+  gpr_mu_destroy(&p->mu);
+
+  elem = p->ready_list.next;
+  while (elem != NULL && elem != &p->ready_list) {
+    ready_list *tmp;
+    tmp = elem->next;
+    elem->next = NULL;
+    elem->prev = NULL;
+    elem->subchannel = NULL;
+    gpr_free(elem);
+    elem = tmp;
+  }
+  gpr_free(p);
+}
+
+void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
+  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
+  pending_pick *pp;
+  size_t i;
+
+  gpr_mu_lock(&p->mu);
+
+  p->shutdown = 1;
+  while ((pp = p->pending_picks)) {
+    p->pending_picks = pp->next;
+    *pp->target = NULL;
+    grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
+    gpr_free(pp);
+  }
+  grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                              GRPC_CHANNEL_FATAL_FAILURE, "shutdown");
+  for (i = 0; i < p->num_subchannels; i++) {
+    subchannel_data *sd = p->subchannels[i];
+    grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL,
+                                           &sd->connectivity_changed_closure);
+  }
+  gpr_mu_unlock(&p->mu);
+}
+
+static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+                           grpc_connected_subchannel **target) {
+  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
+  pending_pick *pp;
+  gpr_mu_lock(&p->mu);
+  pp = p->pending_picks;
+  p->pending_picks = NULL;
+  while (pp != NULL) {
+    pending_pick *next = pp->next;
+    if (pp->target == target) {
+      grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
+                                   pp->pollset);
+      *target = NULL;
+      grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
+      gpr_free(pp);
+    } else {
+      pp->next = p->pending_picks;
+      p->pending_picks = pp;
+    }
+    pp = next;
+  }
+  gpr_mu_unlock(&p->mu);
+}
+
+static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) {
+  size_t i;
+  p->started_picking = 1;
+
+  gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%d", p,
+          p->num_subchannels);
+
+  for (i = 0; i < p->num_subchannels; i++) {
+    subchannel_data *sd = p->subchannels[i];
+    sd->connectivity_state = GRPC_CHANNEL_IDLE;
+    grpc_subchannel_notify_on_state_change(
+        exec_ctx, sd->subchannel, p->base.interested_parties,
+        &sd->connectivity_state, &sd->connectivity_changed_closure);
+    GRPC_LB_POLICY_WEAK_REF(&p->base, "round_robin_connectivity");
+  }
+}
+
+void rr_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
+  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
+  gpr_mu_lock(&p->mu);
+  if (!p->started_picking) {
+    start_picking(exec_ctx, p);
+  }
+  gpr_mu_unlock(&p->mu);
+}
+
+int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
+            grpc_metadata_batch *initial_metadata,
+            grpc_connected_subchannel **target, grpc_closure *on_complete) {
+  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
+  pending_pick *pp;
+  ready_list *selected;
+  gpr_mu_lock(&p->mu);
+  if ((selected = peek_next_connected_locked(p))) {
+    gpr_mu_unlock(&p->mu);
+    *target = grpc_subchannel_get_connected_subchannel(selected->subchannel);
+    if (grpc_lb_round_robin_trace) {
+      gpr_log(GPR_DEBUG,
+              "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)",
+              selected->subchannel, selected);
+    }
+    /* only advance the last picked pointer if the selection was used */
+    advance_last_picked_locked(p);
+    return 1;
+  } else {
+    if (!p->started_picking) {
+      start_picking(exec_ctx, p);
+    }
+    grpc_pollset_set_add_pollset(exec_ctx, p->base.interested_parties, 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);
+    return 0;
+  }
+}
+
+static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
+                                    bool iomgr_success) {
+  subchannel_data *sd = arg;
+  round_robin_lb_policy *p = sd->policy;
+  pending_pick *pp;
+  ready_list *selected;
+
+  int unref = 0;
+
+  gpr_mu_lock(&p->mu);
+
+  if (p->shutdown) {
+    unref = 1;
+  } else {
+    switch (sd->connectivity_state) {
+      case GRPC_CHANNEL_READY:
+        grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                                    GRPC_CHANNEL_READY, "connecting_ready");
+        /* add the newly connected subchannel to the list of connected ones.
+         * Note that it goes to the "end of the line". */
+        sd->ready_list_node = add_connected_sc_locked(p, sd->subchannel);
+        /* at this point we know there's at least one suitable subchannel. Go
+         * ahead and pick one and notify the pending suitors in
+         * p->pending_picks. This preemtively replicates rr_pick()'s actions. */
+        selected = peek_next_connected_locked(p);
+        if (p->pending_picks != NULL) {
+          /* if the selected subchannel is going to be used for the pending
+           * picks, update the last picked pointer */
+          advance_last_picked_locked(p);
+        }
+        while ((pp = p->pending_picks)) {
+          p->pending_picks = pp->next;
+          *pp->target =
+              grpc_subchannel_get_connected_subchannel(selected->subchannel);
+          if (grpc_lb_round_robin_trace) {
+            gpr_log(GPR_DEBUG,
+                    "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
+                    selected->subchannel, selected);
+          }
+          grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
+                                       pp->pollset);
+          grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
+          gpr_free(pp);
+        }
+        grpc_subchannel_notify_on_state_change(
+            exec_ctx, sd->subchannel, p->base.interested_parties,
+            &sd->connectivity_state, &sd->connectivity_changed_closure);
+        break;
+      case GRPC_CHANNEL_CONNECTING:
+      case GRPC_CHANNEL_IDLE:
+        grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                                    sd->connectivity_state,
+                                    "connecting_changed");
+        grpc_subchannel_notify_on_state_change(
+            exec_ctx, sd->subchannel, p->base.interested_parties,
+            &sd->connectivity_state, &sd->connectivity_changed_closure);
+        break;
+      case GRPC_CHANNEL_TRANSIENT_FAILURE:
+        /* renew state notification */
+        grpc_subchannel_notify_on_state_change(
+            exec_ctx, sd->subchannel, p->base.interested_parties,
+            &sd->connectivity_state, &sd->connectivity_changed_closure);
+
+        /* remove from ready list if still present */
+        if (sd->ready_list_node != NULL) {
+          remove_disconnected_sc_locked(p, sd->ready_list_node);
+          sd->ready_list_node = NULL;
+        }
+        grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                                    GRPC_CHANNEL_TRANSIENT_FAILURE,
+                                    "connecting_transient_failure");
+        break;
+      case GRPC_CHANNEL_FATAL_FAILURE:
+        if (sd->ready_list_node != NULL) {
+          remove_disconnected_sc_locked(p, sd->ready_list_node);
+          sd->ready_list_node = NULL;
+        }
+
+        p->num_subchannels--;
+        GPR_SWAP(subchannel_data *, p->subchannels[sd->index],
+                 p->subchannels[p->num_subchannels]);
+        GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin");
+        p->subchannels[sd->index]->index = sd->index;
+        gpr_free(sd);
+
+        unref = 1;
+        if (p->num_subchannels == 0) {
+          grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                                      GRPC_CHANNEL_FATAL_FAILURE,
+                                      "no_more_channels");
+          while ((pp = p->pending_picks)) {
+            p->pending_picks = pp->next;
+            *pp->target = NULL;
+            grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
+            gpr_free(pp);
+          }
+        } else {
+          grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+                                      GRPC_CHANNEL_TRANSIENT_FAILURE,
+                                      "subchannel_failed");
+        }
+    } /* switch */
+  }   /* !unref */
+
+  gpr_mu_unlock(&p->mu);
+
+  if (unref) {
+    GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "round_robin_connectivity");
+  }
+}
+
+static grpc_connectivity_state rr_check_connectivity(grpc_exec_ctx *exec_ctx,
+                                                     grpc_lb_policy *pol) {
+  round_robin_lb_policy *p = (round_robin_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 rr_notify_on_state_change(grpc_exec_ctx *exec_ctx,
+                                      grpc_lb_policy *pol,
+                                      grpc_connectivity_state *current,
+                                      grpc_closure *notify) {
+  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
+  gpr_mu_lock(&p->mu);
+  grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker,
+                                                 current, notify);
+  gpr_mu_unlock(&p->mu);
+}
+
+static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+                        grpc_closure *closure) {
+  round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
+  ready_list *selected;
+  grpc_connected_subchannel *target;
+  gpr_mu_lock(&p->mu);
+  if ((selected = peek_next_connected_locked(p))) {
+    gpr_mu_unlock(&p->mu);
+    target = grpc_subchannel_get_connected_subchannel(selected->subchannel);
+    grpc_connected_subchannel_ping(exec_ctx, target, closure);
+  } else {
+    gpr_mu_unlock(&p->mu);
+    grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
+  }
+}
+
+static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = {
+    rr_destroy,
+    rr_shutdown,
+    rr_pick,
+    rr_cancel_pick,
+    rr_ping_one,
+    rr_exit_idle,
+    rr_check_connectivity,
+    rr_notify_on_state_change};
+
+static void round_robin_factory_ref(grpc_lb_policy_factory *factory) {}
+
+static void round_robin_factory_unref(grpc_lb_policy_factory *factory) {}
+
+static grpc_lb_policy *create_round_robin(grpc_exec_ctx *exec_ctx,
+                                          grpc_lb_policy_factory *factory,
+                                          grpc_lb_policy_args *args) {
+  GPR_ASSERT(args->addresses != NULL);
+  GPR_ASSERT(args->subchannel_factory != NULL);
+
+  round_robin_lb_policy *p = gpr_malloc(sizeof(*p));
+  memset(p, 0, sizeof(*p));
+
+  p->subchannels =
+      gpr_malloc(sizeof(*p->subchannels) * args->addresses->naddrs);
+  memset(p->subchannels, 0, sizeof(*p->subchannels) * args->addresses->naddrs);
+
+  grpc_subchannel_args sc_args;
+  size_t subchannel_idx = 0;
+  for (size_t i = 0; i < args->addresses->naddrs; i++) {
+    memset(&sc_args, 0, sizeof(grpc_subchannel_args));
+    sc_args.addr = (struct sockaddr *)(args->addresses->addrs[i].addr);
+    sc_args.addr_len = (size_t)args->addresses->addrs[i].len;
+
+    grpc_subchannel *subchannel = grpc_subchannel_factory_create_subchannel(
+        exec_ctx, args->subchannel_factory, &sc_args);
+
+    if (subchannel != NULL) {
+      subchannel_data *sd = gpr_malloc(sizeof(*sd));
+      memset(sd, 0, sizeof(*sd));
+      p->subchannels[subchannel_idx] = sd;
+      sd->policy = p;
+      sd->index = subchannel_idx;
+      sd->subchannel = subchannel;
+      ++subchannel_idx;
+      grpc_closure_init(&sd->connectivity_changed_closure,
+                        rr_connectivity_changed, sd);
+    }
+  }
+  if (subchannel_idx == 0) {
+    gpr_free(p->subchannels);
+    gpr_free(p);
+    return NULL;
+  }
+  p->num_subchannels = subchannel_idx;
+
+  /* The (dummy node) root of the ready list */
+  p->ready_list.subchannel = NULL;
+  p->ready_list.prev = NULL;
+  p->ready_list.next = NULL;
+  p->ready_list_last_pick = &p->ready_list;
+
+  grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable);
+  grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
+                               "round_robin");
+  gpr_mu_init(&p->mu);
+  return &p->base;
+}
+
+static const grpc_lb_policy_factory_vtable round_robin_factory_vtable = {
+    round_robin_factory_ref, round_robin_factory_unref, create_round_robin,
+    "round_robin"};
+
+static grpc_lb_policy_factory round_robin_lb_policy_factory = {
+    &round_robin_factory_vtable};
+
+grpc_lb_policy_factory *grpc_round_robin_lb_factory_create() {
+  return &round_robin_lb_policy_factory;
+}
diff --git a/src/core/lib/client_config/lb_policies/round_robin.h b/src/core/lib/client_config/lb_policies/round_robin.h
new file mode 100644
index 0000000..52db1ca
--- /dev/null
+++ b/src/core/lib/client_config/lb_policies/round_robin.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICIES_ROUND_ROBIN_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICIES_ROUND_ROBIN_H
+
+#include "src/core/lib/client_config/lb_policy.h"
+
+extern int grpc_lb_round_robin_trace;
+
+#include "src/core/lib/client_config/lb_policy_factory.h"
+
+/** Returns a load balancing factory for the round robin policy */
+grpc_lb_policy_factory *grpc_round_robin_lb_factory_create();
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICIES_ROUND_ROBIN_H */
diff --git a/src/core/lib/client_config/lb_policy.c b/src/core/lib/client_config/lb_policy.c
new file mode 100644
index 0000000..ee20ccd
--- /dev/null
+++ b/src/core/lib/client_config/lb_policy.c
@@ -0,0 +1,134 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/lb_policy.h"
+
+#define WEAK_REF_BITS 16
+
+void grpc_lb_policy_init(grpc_lb_policy *policy,
+                         const grpc_lb_policy_vtable *vtable) {
+  policy->vtable = vtable;
+  gpr_atm_no_barrier_store(&policy->ref_pair, 1 << WEAK_REF_BITS);
+  policy->interested_parties = grpc_pollset_set_create();
+}
+
+#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
+#define REF_FUNC_EXTRA_ARGS , const char *file, int line, const char *reason
+#define REF_MUTATE_EXTRA_ARGS REF_FUNC_EXTRA_ARGS, const char *purpose
+#define REF_FUNC_PASS_ARGS(new_reason) , file, line, new_reason
+#define REF_MUTATE_PASS_ARGS(purpose) , file, line, reason, purpose
+#else
+#define REF_FUNC_EXTRA_ARGS
+#define REF_MUTATE_EXTRA_ARGS
+#define REF_FUNC_PASS_ARGS(new_reason)
+#define REF_MUTATE_PASS_ARGS(x)
+#endif
+
+static gpr_atm ref_mutate(grpc_lb_policy *c, gpr_atm delta,
+                          int barrier REF_MUTATE_EXTRA_ARGS) {
+  gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta)
+                            : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
+#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+          "LB_POLICY: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val,
+          old_val + delta, reason);
+#endif
+  return old_val;
+}
+
+void grpc_lb_policy_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
+  ref_mutate(policy, 1 << WEAK_REF_BITS, 0 REF_MUTATE_PASS_ARGS("STRONG_REF"));
+}
+
+void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx,
+                          grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
+  gpr_atm old_val =
+      ref_mutate(policy, (gpr_atm)1 - (gpr_atm)(1 << WEAK_REF_BITS),
+                 1 REF_MUTATE_PASS_ARGS("STRONG_UNREF"));
+  gpr_atm mask = ~(gpr_atm)((1 << WEAK_REF_BITS) - 1);
+  gpr_atm check = 1 << WEAK_REF_BITS;
+  if ((old_val & mask) == check) {
+    policy->vtable->shutdown(exec_ctx, policy);
+  }
+  grpc_lb_policy_weak_unref(exec_ctx,
+                            policy REF_FUNC_PASS_ARGS("strong-unref"));
+}
+
+void grpc_lb_policy_weak_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
+  ref_mutate(policy, 1, 0 REF_MUTATE_PASS_ARGS("WEAK_REF"));
+}
+
+void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx,
+                               grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
+  gpr_atm old_val =
+      ref_mutate(policy, -(gpr_atm)1, 1 REF_MUTATE_PASS_ARGS("WEAK_UNREF"));
+  if (old_val == 1) {
+    grpc_pollset_set_destroy(policy->interested_parties);
+    policy->vtable->destroy(exec_ctx, policy);
+  }
+}
+
+int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+                        grpc_pollset *pollset,
+                        grpc_metadata_batch *initial_metadata,
+                        grpc_connected_subchannel **target,
+                        grpc_closure *on_complete) {
+  return policy->vtable->pick(exec_ctx, policy, pollset, initial_metadata,
+                              target, on_complete);
+}
+
+void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+                                grpc_connected_subchannel **target) {
+  policy->vtable->cancel_pick(exec_ctx, policy, target);
+}
+
+void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) {
+  policy->vtable->exit_idle(exec_ctx, policy);
+}
+
+void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+                             grpc_closure *closure) {
+  policy->vtable->ping_one(exec_ctx, policy, closure);
+}
+
+void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx,
+                                           grpc_lb_policy *policy,
+                                           grpc_connectivity_state *state,
+                                           grpc_closure *closure) {
+  policy->vtable->notify_on_state_change(exec_ctx, policy, state, closure);
+}
+
+grpc_connectivity_state grpc_lb_policy_check_connectivity(
+    grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) {
+  return policy->vtable->check_connectivity(exec_ctx, policy);
+}
diff --git a/src/core/lib/client_config/lb_policy.h b/src/core/lib/client_config/lb_policy.h
new file mode 100644
index 0000000..58a0a04
--- /dev/null
+++ b/src/core/lib/client_config/lb_policy.h
@@ -0,0 +1,144 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICY_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICY_H
+
+#include "src/core/lib/client_config/subchannel.h"
+#include "src/core/lib/transport/connectivity_state.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_atm ref_pair;
+  /* owned pointer to interested parties in load balancing decisions */
+  grpc_pollset_set *interested_parties;
+};
+
+struct grpc_lb_policy_vtable {
+  void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
+
+  void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
+
+  /** implement grpc_lb_policy_pick */
+  int (*pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+              grpc_pollset *pollset, grpc_metadata_batch *initial_metadata,
+              grpc_connected_subchannel **target, grpc_closure *on_complete);
+  void (*cancel_pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+                      grpc_connected_subchannel **target);
+
+  void (*ping_one)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+                   grpc_closure *closure);
+
+  /** try to enter a READY connectivity state */
+  void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
+
+  /** check the current connectivity of the lb_policy */
+  grpc_connectivity_state (*check_connectivity)(grpc_exec_ctx *exec_ctx,
+                                                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_exec_ctx *exec_ctx,
+                                 grpc_lb_policy *policy,
+                                 grpc_connectivity_state *state,
+                                 grpc_closure *closure);
+};
+
+/*#define GRPC_LB_POLICY_REFCOUNT_DEBUG*/
+#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(exec_ctx, p, r) \
+  grpc_lb_policy_unref((exec_ctx), (p), __FILE__, __LINE__, (r))
+#define GRPC_LB_POLICY_WEAK_REF(p, r) \
+  grpc_lb_policy_weak_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, p, r) \
+  grpc_lb_policy_weak_unref((exec_ctx), (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_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+                          const char *file, int line, const char *reason);
+void grpc_lb_policy_weak_ref(grpc_lb_policy *policy, const char *file, int line,
+                             const char *reason);
+void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, 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(cl, p, r) grpc_lb_policy_unref((cl), (p))
+#define GRPC_LB_POLICY_WEAK_REF(p, r) grpc_lb_policy_weak_ref((p))
+#define GRPC_LB_POLICY_WEAK_UNREF(cl, p, r) grpc_lb_policy_weak_unref((cl), (p))
+void grpc_lb_policy_ref(grpc_lb_policy *policy);
+void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
+void grpc_lb_policy_weak_ref(grpc_lb_policy *policy);
+void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, 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);
+
+/** 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. */
+int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+                        grpc_pollset *pollset,
+                        grpc_metadata_batch *initial_metadata,
+                        grpc_connected_subchannel **target,
+                        grpc_closure *on_complete);
+
+void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+                             grpc_closure *closure);
+
+void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+                                grpc_connected_subchannel **target);
+
+void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
+
+void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx,
+                                           grpc_lb_policy *policy,
+                                           grpc_connectivity_state *state,
+                                           grpc_closure *closure);
+
+grpc_connectivity_state grpc_lb_policy_check_connectivity(
+    grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICY_H */
diff --git a/src/core/lib/client_config/lb_policy_factory.c b/src/core/lib/client_config/lb_policy_factory.c
new file mode 100644
index 0000000..ede1d62
--- /dev/null
+++ b/src/core/lib/client_config/lb_policy_factory.c
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/lb_policy_factory.h"
+
+void grpc_lb_policy_factory_ref(grpc_lb_policy_factory* factory) {
+  factory->vtable->ref(factory);
+}
+
+void grpc_lb_policy_factory_unref(grpc_lb_policy_factory* factory) {
+  factory->vtable->unref(factory);
+}
+
+grpc_lb_policy* grpc_lb_policy_factory_create_lb_policy(
+    grpc_exec_ctx* exec_ctx, grpc_lb_policy_factory* factory,
+    grpc_lb_policy_args* args) {
+  if (factory == NULL) return NULL;
+  return factory->vtable->create_lb_policy(exec_ctx, factory, args);
+}
diff --git a/src/core/lib/client_config/lb_policy_factory.h b/src/core/lib/client_config/lb_policy_factory.h
new file mode 100644
index 0000000..9a93a8c
--- /dev/null
+++ b/src/core/lib/client_config/lb_policy_factory.h
@@ -0,0 +1,78 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICY_FACTORY_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICY_FACTORY_H
+
+#include "src/core/lib/client_config/lb_policy.h"
+#include "src/core/lib/client_config/subchannel_factory.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+typedef struct grpc_lb_policy_factory grpc_lb_policy_factory;
+typedef struct grpc_lb_policy_factory_vtable grpc_lb_policy_factory_vtable;
+
+/** grpc_lb_policy provides grpc_client_config objects to grpc_channel
+    objects */
+struct grpc_lb_policy_factory {
+  const grpc_lb_policy_factory_vtable *vtable;
+};
+
+typedef struct grpc_lb_policy_args {
+  grpc_resolved_addresses *addresses;
+  grpc_subchannel_factory *subchannel_factory;
+} grpc_lb_policy_args;
+
+struct grpc_lb_policy_factory_vtable {
+  void (*ref)(grpc_lb_policy_factory *factory);
+  void (*unref)(grpc_lb_policy_factory *factory);
+
+  /** Implementation of grpc_lb_policy_factory_create_lb_policy */
+  grpc_lb_policy *(*create_lb_policy)(grpc_exec_ctx *exec_ctx,
+                                      grpc_lb_policy_factory *factory,
+                                      grpc_lb_policy_args *args);
+
+  /** Name for the LB policy this factory implements */
+  const char *name;
+};
+
+void grpc_lb_policy_factory_ref(grpc_lb_policy_factory *factory);
+void grpc_lb_policy_factory_unref(grpc_lb_policy_factory *factory);
+
+/** Create a lb_policy instance. */
+grpc_lb_policy *grpc_lb_policy_factory_create_lb_policy(
+    grpc_exec_ctx *exec_ctx, grpc_lb_policy_factory *factory,
+    grpc_lb_policy_args *args);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICY_FACTORY_H */
diff --git a/src/core/lib/client_config/lb_policy_registry.c b/src/core/lib/client_config/lb_policy_registry.c
new file mode 100644
index 0000000..f703e63
--- /dev/null
+++ b/src/core/lib/client_config/lb_policy_registry.c
@@ -0,0 +1,88 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/lb_policy_registry.h"
+
+#include <string.h>
+
+#define MAX_POLICIES 10
+
+static grpc_lb_policy_factory *g_all_of_the_lb_policies[MAX_POLICIES];
+static int g_number_of_lb_policies = 0;
+
+static grpc_lb_policy_factory *g_default_lb_policy_factory;
+
+void grpc_lb_policy_registry_init(grpc_lb_policy_factory *default_factory) {
+  g_number_of_lb_policies = 0;
+  g_default_lb_policy_factory = default_factory;
+}
+
+void grpc_lb_policy_registry_shutdown(void) {
+  int i;
+  for (i = 0; i < g_number_of_lb_policies; i++) {
+    grpc_lb_policy_factory_unref(g_all_of_the_lb_policies[i]);
+  }
+}
+
+void grpc_register_lb_policy(grpc_lb_policy_factory *factory) {
+  int i;
+  for (i = 0; i < g_number_of_lb_policies; i++) {
+    GPR_ASSERT(0 != strcmp(factory->vtable->name,
+                           g_all_of_the_lb_policies[i]->vtable->name));
+  }
+  GPR_ASSERT(g_number_of_lb_policies != MAX_POLICIES);
+  grpc_lb_policy_factory_ref(factory);
+  g_all_of_the_lb_policies[g_number_of_lb_policies++] = factory;
+}
+
+static grpc_lb_policy_factory *lookup_factory(const char *name) {
+  int i;
+
+  if (name == NULL) return NULL;
+
+  for (i = 0; i < g_number_of_lb_policies; i++) {
+    if (0 == strcmp(name, g_all_of_the_lb_policies[i]->vtable->name)) {
+      return g_all_of_the_lb_policies[i];
+    }
+  }
+
+  return NULL;
+}
+
+grpc_lb_policy *grpc_lb_policy_create(grpc_exec_ctx *exec_ctx, const char *name,
+                                      grpc_lb_policy_args *args) {
+  grpc_lb_policy_factory *factory = lookup_factory(name);
+  grpc_lb_policy *lb_policy =
+      grpc_lb_policy_factory_create_lb_policy(exec_ctx, factory, args);
+  return lb_policy;
+}
diff --git a/src/core/lib/client_config/lb_policy_registry.h b/src/core/lib/client_config/lb_policy_registry.h
new file mode 100644
index 0000000..789854b
--- /dev/null
+++ b/src/core/lib/client_config/lb_policy_registry.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICY_REGISTRY_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICY_REGISTRY_H
+
+#include "src/core/lib/client_config/lb_policy_factory.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+/** Initialize the registry and set \a default_factory as the factory to be
+ * returned when no name is provided in a lookup */
+void grpc_lb_policy_registry_init(grpc_lb_policy_factory *default_factory);
+void grpc_lb_policy_registry_shutdown(void);
+
+/** Register a LB policy factory. */
+void grpc_register_lb_policy(grpc_lb_policy_factory *factory);
+
+/** Create a \a grpc_lb_policy instance.
+ *
+ * If \a name is NULL, the default factory from \a grpc_lb_policy_registry_init
+ * will be returned. */
+grpc_lb_policy *grpc_lb_policy_create(grpc_exec_ctx *exec_ctx, const char *name,
+                                      grpc_lb_policy_args *args);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_LB_POLICY_REGISTRY_H */
diff --git a/src/core/lib/client_config/resolver.c b/src/core/lib/client_config/resolver.c
new file mode 100644
index 0000000..32f0643
--- /dev/null
+++ b/src/core/lib/client_config/resolver.c
@@ -0,0 +1,82 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/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, grpc_closure_list *closure_list,
+                       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,
+                         grpc_closure_list *closure_list, 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_exec_ctx *exec_ctx, grpc_resolver *resolver) {
+#endif
+  if (gpr_unref(&resolver->refs)) {
+    resolver->vtable->destroy(exec_ctx, resolver);
+  }
+}
+
+void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) {
+  resolver->vtable->shutdown(exec_ctx, resolver);
+}
+
+void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx,
+                                     grpc_resolver *resolver) {
+  resolver->vtable->channel_saw_error(exec_ctx, resolver);
+}
+
+void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
+                        grpc_client_config **target_config,
+                        grpc_closure *on_complete) {
+  resolver->vtable->next(exec_ctx, resolver, target_config, on_complete);
+}
diff --git a/src/core/lib/client_config/resolver.h b/src/core/lib/client_config/resolver.h
new file mode 100644
index 0000000..1ee8792
--- /dev/null
+++ b/src/core/lib/client_config/resolver.h
@@ -0,0 +1,94 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVER_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVER_H
+
+#include "src/core/lib/client_config/client_config.h"
+#include "src/core/lib/client_config/subchannel.h"
+#include "src/core/lib/iomgr/iomgr.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_exec_ctx *exec_ctx, grpc_resolver *resolver);
+  void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
+  void (*channel_saw_error)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
+  void (*next)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
+               grpc_client_config **target_config, grpc_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(cl, p, r) \
+  grpc_resolver_unref((cl), (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, grpc_closure_list *closure_list,
+                         const char *file, int line, const char *reason);
+#else
+#define GRPC_RESOLVER_REF(p, r) grpc_resolver_ref((p))
+#define GRPC_RESOLVER_UNREF(cl, p, r) grpc_resolver_unref((cl), (p))
+void grpc_resolver_ref(grpc_resolver *policy);
+void grpc_resolver_unref(grpc_exec_ctx *exec_ctx, grpc_resolver *policy);
+#endif
+
+void grpc_resolver_init(grpc_resolver *resolver,
+                        const grpc_resolver_vtable *vtable);
+
+void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx,
+                                     grpc_resolver *resolver);
+
+/** 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_exec_ctx *exec_ctx, grpc_resolver *resolver,
+                        grpc_client_config **target_config,
+                        grpc_closure *on_complete);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVER_H */
diff --git a/src/core/lib/client_config/resolver_factory.c b/src/core/lib/client_config/resolver_factory.c
new file mode 100644
index 0000000..0f76c66
--- /dev/null
+++ b/src/core/lib/client_config/resolver_factory.c
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/resolver_factory.h"
+
+void grpc_resolver_factory_ref(grpc_resolver_factory* factory) {
+  factory->vtable->ref(factory);
+}
+
+void grpc_resolver_factory_unref(grpc_resolver_factory* factory) {
+  factory->vtable->unref(factory);
+}
+
+/** Create a resolver instance for a name */
+grpc_resolver* grpc_resolver_factory_create_resolver(
+    grpc_resolver_factory* factory, grpc_resolver_args* args) {
+  if (factory == NULL) return NULL;
+  return factory->vtable->create_resolver(factory, args);
+}
+
+char* grpc_resolver_factory_get_default_authority(
+    grpc_resolver_factory* factory, grpc_uri* uri) {
+  if (factory == NULL) return NULL;
+  return factory->vtable->get_default_authority(factory, uri);
+}
diff --git a/src/core/lib/client_config/resolver_factory.h b/src/core/lib/client_config/resolver_factory.h
new file mode 100644
index 0000000..7765c3c
--- /dev/null
+++ b/src/core/lib/client_config/resolver_factory.h
@@ -0,0 +1,82 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVER_FACTORY_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVER_FACTORY_H
+
+#include "src/core/lib/client_config/resolver.h"
+#include "src/core/lib/client_config/subchannel_factory.h"
+#include "src/core/lib/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;
+};
+
+typedef struct grpc_resolver_args {
+  grpc_uri *uri;
+  grpc_subchannel_factory *subchannel_factory;
+} grpc_resolver_args;
+
+struct grpc_resolver_factory_vtable {
+  void (*ref)(grpc_resolver_factory *factory);
+  void (*unref)(grpc_resolver_factory *factory);
+
+  /** Implementation of grpc_resolver_factory_create_resolver */
+  grpc_resolver *(*create_resolver)(grpc_resolver_factory *factory,
+                                    grpc_resolver_args *args);
+
+  /** Implementation of grpc_resolver_factory_get_default_authority */
+  char *(*get_default_authority)(grpc_resolver_factory *factory, grpc_uri *uri);
+
+  /** URI scheme that this factory implements */
+  const char *scheme;
+};
+
+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_resolver_args *args);
+
+/** Return a (freshly allocated with gpr_malloc) string representing
+    the default authority to use for this scheme. */
+char *grpc_resolver_factory_get_default_authority(
+    grpc_resolver_factory *factory, grpc_uri *uri);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVER_FACTORY_H */
diff --git a/src/core/lib/client_config/resolver_registry.c b/src/core/lib/client_config/resolver_registry.c
new file mode 100644
index 0000000..29bd00c
--- /dev/null
+++ b/src/core/lib/client_config/resolver_registry.c
@@ -0,0 +1,137 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/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
+
+static grpc_resolver_factory *g_all_of_the_resolvers[MAX_RESOLVERS];
+static int g_number_of_resolvers = 0;
+
+static char *g_default_resolver_prefix;
+
+void grpc_resolver_registry_init(const char *default_resolver_prefix) {
+  g_number_of_resolvers = 0;
+  g_default_resolver_prefix = gpr_strdup(default_resolver_prefix);
+}
+
+void grpc_resolver_registry_shutdown(void) {
+  int i;
+  for (i = 0; i < g_number_of_resolvers; i++) {
+    grpc_resolver_factory_unref(g_all_of_the_resolvers[i]);
+  }
+  gpr_free(g_default_resolver_prefix);
+}
+
+void grpc_register_resolver_type(grpc_resolver_factory *factory) {
+  int i;
+  for (i = 0; i < g_number_of_resolvers; i++) {
+    GPR_ASSERT(0 != strcmp(factory->vtable->scheme,
+                           g_all_of_the_resolvers[i]->vtable->scheme));
+  }
+  GPR_ASSERT(g_number_of_resolvers != MAX_RESOLVERS);
+  grpc_resolver_factory_ref(factory);
+  g_all_of_the_resolvers[g_number_of_resolvers++] = factory;
+}
+
+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]->vtable->scheme)) {
+      return g_all_of_the_resolvers[i];
+    }
+  }
+
+  return NULL;
+}
+
+static grpc_resolver_factory *resolve_factory(const char *target,
+                                              grpc_uri **uri) {
+  char *tmp;
+  grpc_resolver_factory *factory = NULL;
+
+  GPR_ASSERT(uri != NULL);
+  *uri = grpc_uri_parse(target, 1);
+  factory = lookup_factory(*uri);
+  if (factory == NULL) {
+    if (g_default_resolver_prefix != NULL) {
+      grpc_uri_destroy(*uri);
+      gpr_asprintf(&tmp, "%s%s", g_default_resolver_prefix, target);
+      *uri = grpc_uri_parse(tmp, 1);
+      factory = lookup_factory(*uri);
+      if (factory == NULL) {
+        grpc_uri_destroy(grpc_uri_parse(target, 0));
+        grpc_uri_destroy(grpc_uri_parse(tmp, 0));
+        gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target,
+                tmp);
+      }
+      gpr_free(tmp);
+    } else {
+      grpc_uri_destroy(grpc_uri_parse(target, 0));
+      gpr_log(GPR_ERROR, "don't know how to resolve '%s'", target);
+    }
+  }
+  return factory;
+}
+
+grpc_resolver *grpc_resolver_create(
+    const char *target, grpc_subchannel_factory *subchannel_factory) {
+  grpc_uri *uri = NULL;
+  grpc_resolver_factory *factory = resolve_factory(target, &uri);
+  grpc_resolver *resolver;
+  grpc_resolver_args args;
+  memset(&args, 0, sizeof(args));
+  args.uri = uri;
+  args.subchannel_factory = subchannel_factory;
+  resolver = grpc_resolver_factory_create_resolver(factory, &args);
+  grpc_uri_destroy(uri);
+  return resolver;
+}
+
+char *grpc_get_default_authority(const char *target) {
+  grpc_uri *uri = NULL;
+  grpc_resolver_factory *factory = resolve_factory(target, &uri);
+  char *authority = grpc_resolver_factory_get_default_authority(factory, uri);
+  grpc_uri_destroy(uri);
+  return authority;
+}
diff --git a/src/core/lib/client_config/resolver_registry.h b/src/core/lib/client_config/resolver_registry.h
new file mode 100644
index 0000000..22289ca
--- /dev/null
+++ b/src/core/lib/client_config/resolver_registry.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVER_REGISTRY_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVER_REGISTRY_H
+
+#include "src/core/lib/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(grpc_resolver_factory *factory);
+
+/** Create a resolver given \a target.
+    First tries to parse \a target 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 target, 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 *target, grpc_subchannel_factory *subchannel_factory);
+
+/** Given a target, return a (freshly allocated with gpr_malloc) string
+    representing the default authority to pass from a client. */
+char *grpc_get_default_authority(const char *target);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVER_REGISTRY_H */
diff --git a/src/core/lib/client_config/resolvers/dns_resolver.c b/src/core/lib/client_config/resolvers/dns_resolver.c
new file mode 100644
index 0000000..62bccdd
--- /dev/null
+++ b/src/core/lib/client_config/resolvers/dns_resolver.c
@@ -0,0 +1,294 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/resolvers/dns_resolver.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/client_config/lb_policy_registry.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/support/backoff.h"
+#include "src/core/lib/support/string.h"
+
+#define BACKOFF_MULTIPLIER 1.6
+#define BACKOFF_JITTER 0.2
+#define BACKOFF_MIN_SECONDS 1
+#define BACKOFF_MAX_SECONDS 120
+
+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 name */
+  char *lb_policy_name;
+
+  /** 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_closure *next_completion;
+  /** target config address for next completion */
+  grpc_client_config **target_config;
+  /** current (fully resolved) config */
+  grpc_client_config *resolved_config;
+  /** retry timer */
+  bool have_retry_timer;
+  grpc_timer retry_timer;
+  /** retry backoff state */
+  gpr_backoff backoff_state;
+} dns_resolver;
+
+static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
+
+static void dns_start_resolving_locked(dns_resolver *r);
+static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
+                                         dns_resolver *r);
+
+static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
+static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
+static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
+                     grpc_client_config **target_config,
+                     grpc_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_exec_ctx *exec_ctx, grpc_resolver *resolver) {
+  dns_resolver *r = (dns_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  if (r->have_retry_timer) {
+    grpc_timer_cancel(exec_ctx, &r->retry_timer);
+  }
+  if (r->next_completion != NULL) {
+    *r->target_config = NULL;
+    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
+    r->next_completion = NULL;
+  }
+  gpr_mu_unlock(&r->mu);
+}
+
+static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx,
+                                  grpc_resolver *resolver) {
+  dns_resolver *r = (dns_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  if (!r->resolving) {
+    gpr_backoff_reset(&r->backoff_state);
+    dns_start_resolving_locked(r);
+  }
+  gpr_mu_unlock(&r->mu);
+}
+
+static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
+                     grpc_client_config **target_config,
+                     grpc_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) {
+    gpr_backoff_reset(&r->backoff_state);
+    dns_start_resolving_locked(r);
+  } else {
+    dns_maybe_finish_next_locked(exec_ctx, r);
+  }
+  gpr_mu_unlock(&r->mu);
+}
+
+static void dns_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg,
+                               bool success) {
+  dns_resolver *r = arg;
+
+  gpr_mu_lock(&r->mu);
+  r->have_retry_timer = false;
+  if (success) {
+    if (!r->resolving) {
+      dns_start_resolving_locked(r);
+    }
+  }
+  gpr_mu_unlock(&r->mu);
+
+  GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "retry-timer");
+}
+
+static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
+                            grpc_resolved_addresses *addresses) {
+  dns_resolver *r = arg;
+  grpc_client_config *config = NULL;
+  grpc_lb_policy *lb_policy;
+  gpr_mu_lock(&r->mu);
+  GPR_ASSERT(r->resolving);
+  r->resolving = 0;
+  if (addresses != NULL) {
+    grpc_lb_policy_args lb_policy_args;
+    config = grpc_client_config_create();
+    memset(&lb_policy_args, 0, sizeof(lb_policy_args));
+    lb_policy_args.addresses = addresses;
+    lb_policy_args.subchannel_factory = r->subchannel_factory;
+    lb_policy =
+        grpc_lb_policy_create(exec_ctx, r->lb_policy_name, &lb_policy_args);
+    if (lb_policy != NULL) {
+      grpc_client_config_set_lb_policy(config, lb_policy);
+      GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction");
+    }
+    grpc_resolved_addresses_destroy(addresses);
+  } else {
+    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+    gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
+    gpr_timespec timeout = gpr_time_sub(next_try, now);
+    gpr_log(GPR_DEBUG, "dns resolution failed: retrying in %d.%09d seconds",
+            timeout.tv_sec, timeout.tv_nsec);
+    GPR_ASSERT(!r->have_retry_timer);
+    r->have_retry_timer = true;
+    GRPC_RESOLVER_REF(&r->base, "retry-timer");
+    grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r,
+                    now);
+  }
+  if (r->resolved_config) {
+    grpc_client_config_unref(exec_ctx, r->resolved_config);
+  }
+  r->resolved_config = config;
+  r->resolved_version++;
+  dns_maybe_finish_next_locked(exec_ctx, r);
+  gpr_mu_unlock(&r->mu);
+
+  GRPC_RESOLVER_UNREF(exec_ctx, &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(grpc_exec_ctx *exec_ctx,
+                                         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_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
+    r->next_completion = NULL;
+    r->published_version = r->resolved_version;
+  }
+}
+
+static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
+  dns_resolver *r = (dns_resolver *)gr;
+  gpr_mu_destroy(&r->mu);
+  if (r->resolved_config) {
+    grpc_client_config_unref(exec_ctx, r->resolved_config);
+  }
+  grpc_subchannel_factory_unref(exec_ctx, r->subchannel_factory);
+  gpr_free(r->name);
+  gpr_free(r->default_port);
+  gpr_free(r->lb_policy_name);
+  gpr_free(r);
+}
+
+static grpc_resolver *dns_create(grpc_resolver_args *args,
+                                 const char *default_port,
+                                 const char *lb_policy_name) {
+  dns_resolver *r;
+  const char *path = args->uri->path;
+
+  if (0 != strcmp(args->uri->authority, "")) {
+    gpr_log(GPR_ERROR, "authority based dns 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 = args->subchannel_factory;
+  gpr_backoff_init(&r->backoff_state, BACKOFF_MULTIPLIER, BACKOFF_JITTER,
+                   BACKOFF_MIN_SECONDS * 1000, BACKOFF_MAX_SECONDS * 1000);
+  grpc_subchannel_factory_ref(r->subchannel_factory);
+  r->lb_policy_name = gpr_strdup(lb_policy_name);
+  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_resolver_args *args) {
+  return dns_create(args, "https", "pick_first");
+}
+
+char *dns_factory_get_default_host_name(grpc_resolver_factory *factory,
+                                        grpc_uri *uri) {
+  const char *path = uri->path;
+  if (path[0] == '/') ++path;
+  return gpr_strdup(path);
+}
+
+static const grpc_resolver_factory_vtable dns_factory_vtable = {
+    dns_factory_ref, dns_factory_unref, dns_factory_create_resolver,
+    dns_factory_get_default_host_name, "dns"};
+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/lib/client_config/resolvers/dns_resolver.h b/src/core/lib/client_config/resolvers/dns_resolver.h
new file mode 100644
index 0000000..eb46e41
--- /dev/null
+++ b/src/core/lib/client_config/resolvers/dns_resolver.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H
+
+#include "src/core/lib/client_config/resolver_factory.h"
+
+/** Create a dns resolver factory */
+grpc_resolver_factory *grpc_dns_resolver_factory_create(void);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVERS_DNS_RESOLVER_H */
diff --git a/src/core/lib/client_config/resolvers/sockaddr_resolver.c b/src/core/lib/client_config/resolvers/sockaddr_resolver.c
new file mode 100644
index 0000000..c787bd5
--- /dev/null
+++ b/src/core/lib/client_config/resolvers/sockaddr_resolver.c
@@ -0,0 +1,354 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/client_config/resolvers/sockaddr_resolver.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/client_config/lb_policy_registry.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/unix_sockets_posix.h"
+#include "src/core/lib/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 name */
+  char *lb_policy_name;
+
+  /** the addresses that we've 'resolved' */
+  grpc_resolved_addresses *addresses;
+
+  /** mutex guarding the rest of the state */
+  gpr_mu mu;
+  /** have we published? */
+  int published;
+  /** pending next completion, or NULL */
+  grpc_closure *next_completion;
+  /** target config address for next completion */
+  grpc_client_config **target_config;
+} sockaddr_resolver;
+
+static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
+
+static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
+                                              sockaddr_resolver *r);
+
+static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
+static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx,
+                                       grpc_resolver *r);
+static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
+                          grpc_client_config **target_config,
+                          grpc_closure *on_complete);
+
+static const grpc_resolver_vtable sockaddr_resolver_vtable = {
+    sockaddr_destroy, sockaddr_shutdown, sockaddr_channel_saw_error,
+    sockaddr_next};
+
+static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx,
+                              grpc_resolver *resolver) {
+  sockaddr_resolver *r = (sockaddr_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  if (r->next_completion != NULL) {
+    *r->target_config = NULL;
+    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
+    r->next_completion = NULL;
+  }
+  gpr_mu_unlock(&r->mu);
+}
+
+static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx,
+                                       grpc_resolver *resolver) {
+  sockaddr_resolver *r = (sockaddr_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  r->published = 0;
+  sockaddr_maybe_finish_next_locked(exec_ctx, r);
+  gpr_mu_unlock(&r->mu);
+}
+
+static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
+                          grpc_client_config **target_config,
+                          grpc_closure *on_complete) {
+  sockaddr_resolver *r = (sockaddr_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  GPR_ASSERT(!r->next_completion);
+  r->next_completion = on_complete;
+  r->target_config = target_config;
+  sockaddr_maybe_finish_next_locked(exec_ctx, r);
+  gpr_mu_unlock(&r->mu);
+}
+
+static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
+                                              sockaddr_resolver *r) {
+  if (r->next_completion != NULL && !r->published) {
+    grpc_client_config *cfg = grpc_client_config_create();
+    grpc_lb_policy_args lb_policy_args;
+    memset(&lb_policy_args, 0, sizeof(lb_policy_args));
+    lb_policy_args.addresses = r->addresses;
+    lb_policy_args.subchannel_factory = r->subchannel_factory;
+    grpc_lb_policy *lb_policy =
+        grpc_lb_policy_create(exec_ctx, r->lb_policy_name, &lb_policy_args);
+    grpc_client_config_set_lb_policy(cfg, lb_policy);
+    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "sockaddr");
+    r->published = 1;
+    *r->target_config = cfg;
+    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
+    r->next_completion = NULL;
+  }
+}
+
+static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
+  sockaddr_resolver *r = (sockaddr_resolver *)gr;
+  gpr_mu_destroy(&r->mu);
+  grpc_subchannel_factory_unref(exec_ctx, r->subchannel_factory);
+  grpc_resolved_addresses_destroy(r->addresses);
+  gpr_free(r->lb_policy_name);
+  gpr_free(r);
+}
+
+static char *ip_get_default_authority(grpc_uri *uri) {
+  const char *path = uri->path;
+  if (path[0] == '/') ++path;
+  return gpr_strdup(path);
+}
+
+static char *ipv4_get_default_authority(grpc_resolver_factory *factory,
+                                        grpc_uri *uri) {
+  return ip_get_default_authority(uri);
+}
+
+static char *ipv6_get_default_authority(grpc_resolver_factory *factory,
+                                        grpc_uri *uri) {
+  return ip_get_default_authority(uri);
+}
+
+static int parse_ipv4(grpc_uri *uri, struct sockaddr_storage *addr,
+                      size_t *len) {
+  const char *host_port = uri->path;
+  char *host;
+  char *port;
+  int port_num;
+  int result = 0;
+  struct sockaddr_in *in = (struct sockaddr_in *)addr;
+
+  if (*host_port == '/') ++host_port;
+  if (!gpr_split_host_port(host_port, &host, &port)) {
+    return 0;
+  }
+
+  memset(in, 0, sizeof(*in));
+  *len = sizeof(*in);
+  in->sin_family = AF_INET;
+  if (inet_pton(AF_INET, host, &in->sin_addr) == 0) {
+    gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host);
+    goto done;
+  }
+
+  if (port != NULL) {
+    if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 ||
+        port_num > 65535) {
+      gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port);
+      goto done;
+    }
+    in->sin_port = htons((uint16_t)port_num);
+  } else {
+    gpr_log(GPR_ERROR, "no port given for ipv4 scheme");
+    goto done;
+  }
+
+  result = 1;
+done:
+  gpr_free(host);
+  gpr_free(port);
+  return result;
+}
+
+static int parse_ipv6(grpc_uri *uri, struct sockaddr_storage *addr,
+                      size_t *len) {
+  const char *host_port = uri->path;
+  char *host;
+  char *port;
+  int port_num;
+  int result = 0;
+  struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
+
+  if (*host_port == '/') ++host_port;
+  if (!gpr_split_host_port(host_port, &host, &port)) {
+    return 0;
+  }
+
+  memset(in6, 0, sizeof(*in6));
+  *len = sizeof(*in6);
+  in6->sin6_family = AF_INET6;
+  if (inet_pton(AF_INET6, host, &in6->sin6_addr) == 0) {
+    gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host);
+    goto done;
+  }
+
+  if (port != NULL) {
+    if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 ||
+        port_num > 65535) {
+      gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port);
+      goto done;
+    }
+    in6->sin6_port = htons((uint16_t)port_num);
+  } else {
+    gpr_log(GPR_ERROR, "no port given for ipv6 scheme");
+    goto done;
+  }
+
+  result = 1;
+done:
+  gpr_free(host);
+  gpr_free(port);
+  return result;
+}
+
+static void do_nothing(void *ignored) {}
+
+static grpc_resolver *sockaddr_create(
+    grpc_resolver_args *args, const char *default_lb_policy_name,
+    int parse(grpc_uri *uri, struct sockaddr_storage *dst, size_t *len)) {
+  int errors_found = 0; /* GPR_FALSE */
+  sockaddr_resolver *r;
+  gpr_slice path_slice;
+  gpr_slice_buffer path_parts;
+
+  if (0 != strcmp(args->uri->authority, "")) {
+    gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme",
+            args->uri->scheme);
+    return NULL;
+  }
+
+  r = gpr_malloc(sizeof(sockaddr_resolver));
+  memset(r, 0, sizeof(*r));
+
+  r->lb_policy_name = NULL;
+  if (0 != strcmp(args->uri->query, "")) {
+    gpr_slice query_slice;
+    gpr_slice_buffer query_parts;
+
+    query_slice =
+        gpr_slice_new(args->uri->query, strlen(args->uri->query), do_nothing);
+    gpr_slice_buffer_init(&query_parts);
+    gpr_slice_split(query_slice, "=", &query_parts);
+    GPR_ASSERT(query_parts.count == 2);
+    if (0 == gpr_slice_str_cmp(query_parts.slices[0], "lb_policy")) {
+      r->lb_policy_name = gpr_dump_slice(query_parts.slices[1], GPR_DUMP_ASCII);
+    }
+    gpr_slice_buffer_destroy(&query_parts);
+    gpr_slice_unref(query_slice);
+  }
+  if (r->lb_policy_name == NULL) {
+    r->lb_policy_name = gpr_strdup(default_lb_policy_name);
+  }
+
+  path_slice =
+      gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing);
+  gpr_slice_buffer_init(&path_parts);
+
+  gpr_slice_split(path_slice, ",", &path_parts);
+  r->addresses = gpr_malloc(sizeof(grpc_resolved_addresses));
+  r->addresses->naddrs = path_parts.count;
+  r->addresses->addrs =
+      gpr_malloc(sizeof(grpc_resolved_address) * r->addresses->naddrs);
+
+  for (size_t i = 0; i < r->addresses->naddrs; i++) {
+    grpc_uri ith_uri = *args->uri;
+    char *part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII);
+    ith_uri.path = part_str;
+    if (!parse(&ith_uri,
+               (struct sockaddr_storage *)(&r->addresses->addrs[i].addr),
+               &r->addresses->addrs[i].len)) {
+      errors_found = 1; /* GPR_TRUE */
+    }
+    gpr_free(part_str);
+    if (errors_found) break;
+  }
+
+  gpr_slice_buffer_destroy(&path_parts);
+  gpr_slice_unref(path_slice);
+  if (errors_found) {
+    gpr_free(r->lb_policy_name);
+    grpc_resolved_addresses_destroy(r->addresses);
+    gpr_free(r);
+    return NULL;
+  }
+
+  gpr_ref_init(&r->refs, 1);
+  gpr_mu_init(&r->mu);
+  grpc_resolver_init(&r->base, &sockaddr_resolver_vtable);
+  r->subchannel_factory = args->subchannel_factory;
+  grpc_subchannel_factory_ref(r->subchannel_factory);
+
+  return &r->base;
+}
+
+/*
+ * FACTORY
+ */
+
+static void sockaddr_factory_ref(grpc_resolver_factory *factory) {}
+
+static void sockaddr_factory_unref(grpc_resolver_factory *factory) {}
+
+#define DECL_FACTORY(name, prefix)                                          \
+  static grpc_resolver *name##_factory_create_resolver(                     \
+      grpc_resolver_factory *factory, grpc_resolver_args *args) {           \
+    return sockaddr_create(args, "pick_first", prefix##parse_##name);       \
+  }                                                                         \
+  static const grpc_resolver_factory_vtable name##_factory_vtable = {       \
+      sockaddr_factory_ref, sockaddr_factory_unref,                         \
+      name##_factory_create_resolver, prefix##name##_get_default_authority, \
+      #name};                                                               \
+  static grpc_resolver_factory name##_resolver_factory = {                  \
+      &name##_factory_vtable};                                              \
+  grpc_resolver_factory *grpc_##name##_resolver_factory_create() {          \
+    return &name##_resolver_factory;                                        \
+  }
+
+#ifdef GPR_HAVE_UNIX_SOCKET
+DECL_FACTORY(unix, grpc_)
+#endif
+DECL_FACTORY(ipv4, ) DECL_FACTORY(ipv6, )
diff --git a/src/core/lib/client_config/resolvers/sockaddr_resolver.h b/src/core/lib/client_config/resolvers/sockaddr_resolver.h
new file mode 100644
index 0000000..45c55bd
--- /dev/null
+++ b/src/core/lib/client_config/resolvers/sockaddr_resolver.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVERS_SOCKADDR_RESOLVER_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVERS_SOCKADDR_RESOLVER_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/client_config/resolver_factory.h"
+
+grpc_resolver_factory *grpc_ipv4_resolver_factory_create(void);
+
+grpc_resolver_factory *grpc_ipv6_resolver_factory_create(void);
+
+#ifdef GPR_POSIX_SOCKET
+/** Create a unix resolver factory */
+grpc_resolver_factory *grpc_unix_resolver_factory_create(void);
+#endif
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVERS_SOCKADDR_RESOLVER_H */
diff --git a/src/core/lib/client_config/resolvers/zookeeper_resolver.c b/src/core/lib/client_config/resolvers/zookeeper_resolver.c
new file mode 100644
index 0000000..404dfcd
--- /dev/null
+++ b/src/core/lib/client_config/resolvers/zookeeper_resolver.c
@@ -0,0 +1,514 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/resolvers/zookeeper_resolver.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include <grpc/grpc_zookeeper.h>
+#include <zookeeper/zookeeper.h>
+
+#include "src/core/lib/client_config/lb_policy_registry.h"
+#include "src/core/lib/client_config/resolver_registry.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/api_trace.h"
+
+/** Zookeeper session expiration time in milliseconds */
+#define GRPC_ZOOKEEPER_SESSION_TIMEOUT 15000
+
+typedef struct {
+  /** base class: must be first */
+  grpc_resolver base;
+  /** refcount */
+  gpr_refcount refs;
+  /** name to resolve */
+  char *name;
+  /** subchannel factory */
+  grpc_subchannel_factory *subchannel_factory;
+  /** load balancing policy name */
+  char *lb_policy_name;
+
+  /** 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_closure *next_completion;
+  /** target config address for next completion */
+  grpc_client_config **target_config;
+  /** current (fully resolved) config */
+  grpc_client_config *resolved_config;
+
+  /** zookeeper handle */
+  zhandle_t *zookeeper_handle;
+  /** zookeeper resolved addresses */
+  grpc_resolved_addresses *resolved_addrs;
+  /** total number of addresses to be resolved */
+  int resolved_total;
+  /** number of addresses resolved */
+  int resolved_num;
+} zookeeper_resolver;
+
+static void zookeeper_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
+
+static void zookeeper_start_resolving_locked(zookeeper_resolver *r);
+static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
+                                               zookeeper_resolver *r);
+
+static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
+static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx,
+                                        grpc_resolver *r);
+static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
+                           grpc_client_config **target_config,
+                           grpc_closure *on_complete);
+
+static const grpc_resolver_vtable zookeeper_resolver_vtable = {
+    zookeeper_destroy, zookeeper_shutdown, zookeeper_channel_saw_error,
+    zookeeper_next};
+
+static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx,
+                               grpc_resolver *resolver) {
+  zookeeper_resolver *r = (zookeeper_resolver *)resolver;
+  grpc_closure *call = NULL;
+  gpr_mu_lock(&r->mu);
+  if (r->next_completion != NULL) {
+    *r->target_config = NULL;
+    call = r->next_completion;
+    r->next_completion = NULL;
+  }
+  zookeeper_close(r->zookeeper_handle);
+  gpr_mu_unlock(&r->mu);
+  if (call != NULL) {
+    call->cb(exec_ctx, call->cb_arg, 1);
+  }
+}
+
+static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx,
+                                        grpc_resolver *resolver) {
+  zookeeper_resolver *r = (zookeeper_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  if (r->resolving == 0) {
+    zookeeper_start_resolving_locked(r);
+  }
+  gpr_mu_unlock(&r->mu);
+}
+
+static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
+                           grpc_client_config **target_config,
+                           grpc_closure *on_complete) {
+  zookeeper_resolver *r = (zookeeper_resolver *)resolver;
+  gpr_mu_lock(&r->mu);
+  GPR_ASSERT(r->next_completion == NULL);
+  r->next_completion = on_complete;
+  r->target_config = target_config;
+  if (r->resolved_version == 0 && r->resolving == 0) {
+    zookeeper_start_resolving_locked(r);
+  } else {
+    zookeeper_maybe_finish_next_locked(exec_ctx, r);
+  }
+  gpr_mu_unlock(&r->mu);
+}
+
+/** Zookeeper global watcher for connection management
+    TODO: better connection management besides logs */
+static void zookeeper_global_watcher(zhandle_t *zookeeper_handle, int type,
+                                     int state, const char *path,
+                                     void *watcher_ctx) {
+  if (type == ZOO_SESSION_EVENT) {
+    if (state == ZOO_EXPIRED_SESSION_STATE) {
+      gpr_log(GPR_ERROR, "Zookeeper session expired");
+    } else if (state == ZOO_AUTH_FAILED_STATE) {
+      gpr_log(GPR_ERROR, "Zookeeper authentication failed");
+    }
+  }
+}
+
+/** Zookeeper watcher triggered by changes to watched nodes
+    Once triggered, it tries to resolve again to get updated addresses */
+static void zookeeper_watcher(zhandle_t *zookeeper_handle, int type, int state,
+                              const char *path, void *watcher_ctx) {
+  if (watcher_ctx != NULL) {
+    zookeeper_resolver *r = (zookeeper_resolver *)watcher_ctx;
+    if (state == ZOO_CONNECTED_STATE) {
+      gpr_mu_lock(&r->mu);
+      if (r->resolving == 0) {
+        zookeeper_start_resolving_locked(r);
+      }
+      gpr_mu_unlock(&r->mu);
+    }
+  }
+}
+
+/** Callback function after getting all resolved addresses
+    Creates a subchannel for each address */
+static void zookeeper_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
+                                  grpc_resolved_addresses *addresses) {
+  zookeeper_resolver *r = arg;
+  grpc_client_config *config = NULL;
+  grpc_lb_policy *lb_policy;
+
+  if (addresses != NULL) {
+    grpc_lb_policy_args lb_policy_args;
+    config = grpc_client_config_create();
+
+    lb_policy_args.addresses = addresses;
+    lb_policy_args.subchannel_factory = r->subchannel_factory;
+    lb_policy =
+        grpc_lb_policy_create(exec_ctx, r->lb_policy_name, &lb_policy_args);
+
+    if (lb_policy != NULL) {
+      grpc_client_config_set_lb_policy(config, lb_policy);
+      GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction");
+    }
+    grpc_resolved_addresses_destroy(addresses);
+  }
+  gpr_mu_lock(&r->mu);
+  GPR_ASSERT(r->resolving == 1);
+  r->resolving = 0;
+  if (r->resolved_config != NULL) {
+    grpc_client_config_unref(exec_ctx, r->resolved_config);
+  }
+  r->resolved_config = config;
+  r->resolved_version++;
+  zookeeper_maybe_finish_next_locked(exec_ctx, r);
+  gpr_mu_unlock(&r->mu);
+
+  GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "zookeeper-resolving");
+}
+
+/** Callback function for each DNS resolved address */
+static void zookeeper_dns_resolved(grpc_exec_ctx *exec_ctx, void *arg,
+                                   grpc_resolved_addresses *addresses) {
+  size_t i;
+  zookeeper_resolver *r = arg;
+  int resolve_done = 0;
+
+  gpr_mu_lock(&r->mu);
+  r->resolved_num++;
+  r->resolved_addrs->addrs =
+      gpr_realloc(r->resolved_addrs->addrs,
+                  sizeof(grpc_resolved_address) *
+                      (r->resolved_addrs->naddrs + addresses->naddrs));
+  for (i = 0; i < addresses->naddrs; i++) {
+    memcpy(r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].addr,
+           addresses->addrs[i].addr, addresses->addrs[i].len);
+    r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].len =
+        addresses->addrs[i].len;
+  }
+
+  r->resolved_addrs->naddrs += addresses->naddrs;
+  grpc_resolved_addresses_destroy(addresses);
+
+  /** Wait for all addresses to be resolved */
+  resolve_done = (r->resolved_num == r->resolved_total);
+  gpr_mu_unlock(&r->mu);
+  if (resolve_done) {
+    zookeeper_on_resolved(exec_ctx, r, r->resolved_addrs);
+  }
+}
+
+/** Parses JSON format address of a zookeeper node */
+static char *zookeeper_parse_address(const char *value, size_t value_len) {
+  grpc_json *json;
+  grpc_json *cur;
+  const char *host;
+  const char *port;
+  char *buffer;
+  char *address = NULL;
+
+  buffer = gpr_malloc(value_len);
+  memcpy(buffer, value, value_len);
+  json = grpc_json_parse_string_with_len(buffer, value_len);
+  if (json != NULL) {
+    host = NULL;
+    port = NULL;
+    for (cur = json->child; cur != NULL; cur = cur->next) {
+      if (!strcmp(cur->key, "host")) {
+        host = cur->value;
+        if (port != NULL) {
+          break;
+        }
+      } else if (!strcmp(cur->key, "port")) {
+        port = cur->value;
+        if (host != NULL) {
+          break;
+        }
+      }
+    }
+    if (host != NULL && port != NULL) {
+      gpr_asprintf(&address, "%s:%s", host, port);
+    }
+    grpc_json_destroy(json);
+  }
+  gpr_free(buffer);
+
+  return address;
+}
+
+static void zookeeper_get_children_node_completion(int rc, const char *value,
+                                                   int value_len,
+                                                   const struct Stat *stat,
+                                                   const void *arg) {
+  char *address = NULL;
+  zookeeper_resolver *r = (zookeeper_resolver *)arg;
+  int resolve_done = 0;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  if (rc != 0) {
+    gpr_log(GPR_ERROR, "Error in getting a child node of %s", r->name);
+    grpc_exec_ctx_finish(&exec_ctx);
+    return;
+  }
+
+  address = zookeeper_parse_address(value, (size_t)value_len);
+  if (address != NULL) {
+    /** Further resolves address by DNS */
+    grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r);
+    gpr_free(address);
+  } else {
+    gpr_log(GPR_ERROR, "Error in resolving a child node of %s", r->name);
+    gpr_mu_lock(&r->mu);
+    r->resolved_total--;
+    resolve_done = (r->resolved_num == r->resolved_total);
+    gpr_mu_unlock(&r->mu);
+    if (resolve_done) {
+      zookeeper_on_resolved(&exec_ctx, r, r->resolved_addrs);
+    }
+  }
+
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void zookeeper_get_children_completion(
+    int rc, const struct String_vector *children, const void *arg) {
+  char *path;
+  int status;
+  int i;
+  zookeeper_resolver *r = (zookeeper_resolver *)arg;
+
+  if (rc != 0) {
+    gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name);
+    return;
+  }
+
+  if (children->count == 0) {
+    gpr_log(GPR_ERROR, "Error in resolving zookeeper address %s", r->name);
+    return;
+  }
+
+  r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
+  r->resolved_addrs->addrs = NULL;
+  r->resolved_addrs->naddrs = 0;
+  r->resolved_total = children->count;
+
+  /** TODO: Replace expensive heap allocation with stack
+      if we can get maximum length of zookeeper path */
+  for (i = 0; i < children->count; i++) {
+    gpr_asprintf(&path, "%s/%s", r->name, children->data[i]);
+    status = zoo_awget(r->zookeeper_handle, path, zookeeper_watcher, r,
+                       zookeeper_get_children_node_completion, r);
+    gpr_free(path);
+    if (status != 0) {
+      gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", path);
+    }
+  }
+}
+
+static void zookeeper_get_node_completion(int rc, const char *value,
+                                          int value_len,
+                                          const struct Stat *stat,
+                                          const void *arg) {
+  int status;
+  char *address = NULL;
+  zookeeper_resolver *r = (zookeeper_resolver *)arg;
+  r->resolved_addrs = NULL;
+  r->resolved_total = 0;
+  r->resolved_num = 0;
+
+  if (rc != 0) {
+    gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name);
+    return;
+  }
+
+  /** If zookeeper node of path r->name does not have address
+      (i.e. service node), get its children */
+  address = zookeeper_parse_address(value, (size_t)value_len);
+  if (address != NULL) {
+    r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
+    r->resolved_addrs->addrs = NULL;
+    r->resolved_addrs->naddrs = 0;
+    r->resolved_total = 1;
+    /** Further resolves address by DNS */
+    grpc_resolve_address(address, NULL, zookeeper_dns_resolved, r);
+    gpr_free(address);
+    return;
+  }
+
+  status = zoo_awget_children(r->zookeeper_handle, r->name, zookeeper_watcher,
+                              r, zookeeper_get_children_completion, r);
+  if (status != 0) {
+    gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name);
+  }
+}
+
+static void zookeeper_resolve_address(zookeeper_resolver *r) {
+  int status;
+  status = zoo_awget(r->zookeeper_handle, r->name, zookeeper_watcher, r,
+                     zookeeper_get_node_completion, r);
+  if (status != 0) {
+    gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name);
+  }
+}
+
+static void zookeeper_start_resolving_locked(zookeeper_resolver *r) {
+  GRPC_RESOLVER_REF(&r->base, "zookeeper-resolving");
+  GPR_ASSERT(r->resolving == 0);
+  r->resolving = 1;
+  zookeeper_resolve_address(r);
+}
+
+static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
+                                               zookeeper_resolver *r) {
+  if (r->next_completion != NULL &&
+      r->resolved_version != r->published_version) {
+    *r->target_config = r->resolved_config;
+    if (r->resolved_config != NULL) {
+      grpc_client_config_ref(r->resolved_config);
+    }
+    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
+    r->next_completion = NULL;
+    r->published_version = r->resolved_version;
+  }
+}
+
+static void zookeeper_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
+  zookeeper_resolver *r = (zookeeper_resolver *)gr;
+  gpr_mu_destroy(&r->mu);
+  if (r->resolved_config != NULL) {
+    grpc_client_config_unref(exec_ctx, r->resolved_config);
+  }
+  grpc_subchannel_factory_unref(exec_ctx, r->subchannel_factory);
+  gpr_free(r->name);
+  gpr_free(r->lb_policy_name);
+  gpr_free(r);
+}
+
+static grpc_resolver *zookeeper_create(grpc_resolver_args *args,
+                                       const char *lb_policy_name) {
+  zookeeper_resolver *r;
+  size_t length;
+  char *path = args->uri->path;
+
+  if (0 == strcmp(args->uri->authority, "")) {
+    gpr_log(GPR_ERROR, "No authority specified in zookeeper uri");
+    return NULL;
+  }
+
+  /** Removes the trailing slash if exists */
+  length = strlen(path);
+  if (length > 1 && path[length - 1] == '/') {
+    path[length - 1] = 0;
+  }
+
+  r = gpr_malloc(sizeof(zookeeper_resolver));
+  memset(r, 0, sizeof(*r));
+  gpr_ref_init(&r->refs, 1);
+  gpr_mu_init(&r->mu);
+  grpc_resolver_init(&r->base, &zookeeper_resolver_vtable);
+  r->name = gpr_strdup(path);
+
+  r->subchannel_factory = args->subchannel_factory;
+  grpc_subchannel_factory_ref(r->subchannel_factory);
+
+  r->lb_policy_name = gpr_strdup(lb_policy_name);
+
+  /** Initializes zookeeper client */
+  zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
+  r->zookeeper_handle =
+      zookeeper_init(args->uri->authority, zookeeper_global_watcher,
+                     GRPC_ZOOKEEPER_SESSION_TIMEOUT, 0, 0, 0);
+  if (r->zookeeper_handle == NULL) {
+    gpr_log(GPR_ERROR, "Unable to connect to zookeeper server");
+    return NULL;
+  }
+
+  return &r->base;
+}
+
+static void zookeeper_plugin_init() {
+  grpc_register_resolver_type(grpc_zookeeper_resolver_factory_create());
+}
+
+void grpc_zookeeper_register() {
+  GRPC_API_TRACE("grpc_zookeeper_register(void)", 0, ());
+  grpc_register_plugin(zookeeper_plugin_init, NULL);
+}
+
+/*
+ * FACTORY
+ */
+
+static void zookeeper_factory_ref(grpc_resolver_factory *factory) {}
+
+static void zookeeper_factory_unref(grpc_resolver_factory *factory) {}
+
+static char *zookeeper_factory_get_default_hostname(
+    grpc_resolver_factory *factory, grpc_uri *uri) {
+  return NULL;
+}
+
+static grpc_resolver *zookeeper_factory_create_resolver(
+    grpc_resolver_factory *factory, grpc_resolver_args *args) {
+  return zookeeper_create(args, "pick_first");
+}
+
+static const grpc_resolver_factory_vtable zookeeper_factory_vtable = {
+    zookeeper_factory_ref, zookeeper_factory_unref,
+    zookeeper_factory_create_resolver, zookeeper_factory_get_default_hostname,
+    "zookeeper"};
+
+static grpc_resolver_factory zookeeper_resolver_factory = {
+    &zookeeper_factory_vtable};
+
+grpc_resolver_factory *grpc_zookeeper_resolver_factory_create() {
+  return &zookeeper_resolver_factory;
+}
diff --git a/src/core/lib/client_config/resolvers/zookeeper_resolver.h b/src/core/lib/client_config/resolvers/zookeeper_resolver.h
new file mode 100644
index 0000000..7ee7604
--- /dev/null
+++ b/src/core/lib/client_config/resolvers/zookeeper_resolver.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H
+
+#include "src/core/lib/client_config/resolver_factory.h"
+
+/** Create a zookeeper resolver factory */
+grpc_resolver_factory *grpc_zookeeper_resolver_factory_create(void);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_RESOLVERS_ZOOKEEPER_RESOLVER_H */
diff --git a/src/core/lib/client_config/subchannel.c b/src/core/lib/client_config/subchannel.c
new file mode 100644
index 0000000..41242f0
--- /dev/null
+++ b/src/core/lib/client_config/subchannel.c
@@ -0,0 +1,678 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/subchannel.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/avl.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/client_config/initial_connect_string.h"
+#include "src/core/lib/client_config/subchannel_index.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/backoff.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/channel_init.h"
+#include "src/core/lib/transport/connectivity_state.h"
+
+#define INTERNAL_REF_BITS 16
+#define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1))
+
+#define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20
+#define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1
+#define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6
+#define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120
+#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2
+
+#define GET_CONNECTED_SUBCHANNEL(subchannel, barrier)      \
+  ((grpc_connected_subchannel *)(gpr_atm_##barrier##_load( \
+      &(subchannel)->connected_subchannel)))
+
+typedef struct {
+  grpc_closure closure;
+  grpc_subchannel *subchannel;
+  grpc_connectivity_state connectivity_state;
+} state_watcher;
+
+typedef struct external_state_watcher {
+  grpc_subchannel *subchannel;
+  grpc_pollset_set *pollset_set;
+  grpc_closure *notify;
+  grpc_closure closure;
+  struct external_state_watcher *next;
+  struct external_state_watcher *prev;
+} external_state_watcher;
+
+struct grpc_subchannel {
+  grpc_connector *connector;
+
+  /** refcount
+      - lower INTERNAL_REF_BITS bits are for internal references:
+        these do not keep the subchannel open.
+      - upper remaining bits are for public references: these do
+        keep the subchannel open */
+  gpr_atm ref_pair;
+
+  /** 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;
+
+  grpc_subchannel_key *key;
+
+  /** initial string to send to peer */
+  gpr_slice initial_connect_string;
+
+  /** set during connection */
+  grpc_connect_out_args connecting_result;
+
+  /** callback for connection finishing */
+  grpc_closure connected;
+
+  /** pollset_set tracking who's interested in a connection
+      being setup */
+  grpc_pollset_set *pollset_set;
+
+  /** active connection, or null; of type grpc_connected_subchannel */
+  gpr_atm connected_subchannel;
+
+  /** mutex protecting remaining elements */
+  gpr_mu mu;
+
+  /** have we seen a disconnection? */
+  int disconnected;
+  /** are we connecting */
+  int connecting;
+  /** connectivity state tracking */
+  grpc_connectivity_state_tracker state_tracker;
+
+  external_state_watcher root_external_state_watcher;
+
+  /** next connect attempt time */
+  gpr_timespec next_attempt;
+  /** backoff state */
+  gpr_backoff backoff_state;
+  /** do we have an active alarm? */
+  int have_alarm;
+  /** our alarm */
+  grpc_timer alarm;
+  /** current random value */
+  uint32_t random;
+};
+
+struct grpc_subchannel_call {
+  grpc_connected_subchannel *connection;
+};
+
+#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1))
+#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)(con))
+#define CALLSTACK_TO_SUBCHANNEL_CALL(callstack) \
+  (((grpc_subchannel_call *)(callstack)) - 1)
+
+static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel,
+                                 bool iomgr_success);
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+#define REF_REASON reason
+#define REF_LOG(name, p)                                                  \
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p   ref %d -> %d %s", \
+          (name), (p), (p)->refs.count, (p)->refs.count + 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.count, (p)->refs.count - 1, reason)
+#define REF_MUTATE_EXTRA_ARGS \
+  GRPC_SUBCHANNEL_REF_EXTRA_ARGS, const char *purpose
+#define REF_MUTATE_PURPOSE(x) , file, line, reason, x
+#else
+#define REF_REASON ""
+#define REF_LOG(name, p) \
+  do {                   \
+  } while (0)
+#define UNREF_LOG(name, p) \
+  do {                     \
+  } while (0)
+#define REF_MUTATE_EXTRA_ARGS
+#define REF_MUTATE_PURPOSE(x)
+#endif
+
+/*
+ * connection implementation
+ */
+
+static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg,
+                               bool success) {
+  grpc_connected_subchannel *c = arg;
+  grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c));
+  gpr_free(c);
+}
+
+void grpc_connected_subchannel_ref(
+    grpc_connected_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON);
+}
+
+void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
+                                     grpc_connected_subchannel *c
+                                         GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c),
+                           REF_REASON);
+}
+
+/*
+ * grpc_subchannel implementation
+ */
+
+static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg,
+                               bool success) {
+  grpc_subchannel *c = arg;
+  gpr_free((void *)c->filters);
+  grpc_channel_args_destroy(c->args);
+  gpr_free(c->addr);
+  gpr_slice_unref(c->initial_connect_string);
+  grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
+  grpc_connector_unref(exec_ctx, c->connector);
+  grpc_pollset_set_destroy(c->pollset_set);
+  grpc_subchannel_key_destroy(exec_ctx, c->key);
+  gpr_free(c);
+}
+
+static gpr_atm ref_mutate(grpc_subchannel *c, gpr_atm delta,
+                          int barrier REF_MUTATE_EXTRA_ARGS) {
+  gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta)
+                            : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+          "SUBCHANNEL: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val,
+          old_val + delta, reason);
+#endif
+  return old_val;
+}
+
+grpc_subchannel *grpc_subchannel_ref(
+    grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  gpr_atm old_refs;
+  old_refs = ref_mutate(c, (1 << INTERNAL_REF_BITS),
+                        0 REF_MUTATE_PURPOSE("STRONG_REF"));
+  GPR_ASSERT((old_refs & STRONG_REF_MASK) != 0);
+  return c;
+}
+
+grpc_subchannel *grpc_subchannel_weak_ref(
+    grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  gpr_atm old_refs;
+  old_refs = ref_mutate(c, 1, 0 REF_MUTATE_PURPOSE("WEAK_REF"));
+  GPR_ASSERT(old_refs != 0);
+  return c;
+}
+
+grpc_subchannel *grpc_subchannel_ref_from_weak_ref(
+    grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  if (!c) return NULL;
+  for (;;) {
+    gpr_atm old_refs = gpr_atm_acq_load(&c->ref_pair);
+    if (old_refs >= (1 << INTERNAL_REF_BITS)) {
+      gpr_atm new_refs = old_refs + (1 << INTERNAL_REF_BITS);
+      if (gpr_atm_rel_cas(&c->ref_pair, old_refs, new_refs)) {
+        return c;
+      }
+    } else {
+      return NULL;
+    }
+  }
+}
+
+static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
+  grpc_connected_subchannel *con;
+  grpc_subchannel_index_unregister(exec_ctx, c->key, c);
+  gpr_mu_lock(&c->mu);
+  GPR_ASSERT(!c->disconnected);
+  c->disconnected = 1;
+  grpc_connector_shutdown(exec_ctx, c->connector);
+  con = GET_CONNECTED_SUBCHANNEL(c, no_barrier);
+  if (con != NULL) {
+    GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection");
+    gpr_atm_no_barrier_store(&c->connected_subchannel, 0xdeadbeef);
+  }
+  gpr_mu_unlock(&c->mu);
+}
+
+void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx,
+                           grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  gpr_atm old_refs;
+  old_refs = ref_mutate(c, (gpr_atm)1 - (gpr_atm)(1 << INTERNAL_REF_BITS),
+                        1 REF_MUTATE_PURPOSE("STRONG_UNREF"));
+  if ((old_refs & STRONG_REF_MASK) == (1 << INTERNAL_REF_BITS)) {
+    disconnect(exec_ctx, c);
+  }
+  GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "strong-unref");
+}
+
+void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
+                                grpc_subchannel *c
+                                    GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  gpr_atm old_refs;
+  old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF"));
+  if (old_refs == 1) {
+    grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(subchannel_destroy, c),
+                          true, NULL);
+  }
+}
+
+static uint32_t random_seed() {
+  return (uint32_t)(gpr_time_to_millis(gpr_now(GPR_CLOCK_MONOTONIC)));
+}
+
+grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
+                                        grpc_connector *connector,
+                                        grpc_subchannel_args *args) {
+  grpc_subchannel_key *key = grpc_subchannel_key_create(connector, args);
+  grpc_subchannel *c = grpc_subchannel_index_find(exec_ctx, key);
+  if (c) {
+    grpc_subchannel_key_destroy(exec_ctx, key);
+    return c;
+  }
+
+  c = gpr_malloc(sizeof(*c));
+  memset(c, 0, sizeof(*c));
+  c->key = key;
+  gpr_atm_no_barrier_store(&c->ref_pair, 1 << INTERNAL_REF_BITS);
+  c->connector = connector;
+  grpc_connector_ref(c->connector);
+  c->num_filters = args->filter_count;
+  if (c->num_filters > 0) {
+    c->filters = gpr_malloc(sizeof(grpc_channel_filter *) * c->num_filters);
+    memcpy((void *)c->filters, args->filters,
+           sizeof(grpc_channel_filter *) * c->num_filters);
+  } else {
+    c->filters = NULL;
+  }
+  c->addr = gpr_malloc(args->addr_len);
+  memcpy(c->addr, args->addr, args->addr_len);
+  c->pollset_set = grpc_pollset_set_create();
+  c->addr_len = args->addr_len;
+  grpc_set_initial_connect_string(&c->addr, &c->addr_len,
+                                  &c->initial_connect_string);
+  c->args = grpc_channel_args_copy(args->args);
+  c->random = random_seed();
+  c->root_external_state_watcher.next = c->root_external_state_watcher.prev =
+      &c->root_external_state_watcher;
+  grpc_closure_init(&c->connected, subchannel_connected, c);
+  grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE,
+                               "subchannel");
+  gpr_backoff_init(&c->backoff_state,
+                   GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER,
+                   GRPC_SUBCHANNEL_RECONNECT_JITTER,
+                   GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS * 1000,
+                   GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
+  if (c->args) {
+    for (size_t i = 0; i < c->args->num_args; i++) {
+      if (0 == strcmp(c->args->args[i].key,
+                      "grpc.testing.fixed_reconnect_backoff")) {
+        GPR_ASSERT(c->args->args[i].type == GRPC_ARG_INTEGER);
+        gpr_backoff_init(&c->backoff_state, 1.0, 0.0,
+                         c->args->args[i].value.integer,
+                         c->args->args[i].value.integer);
+      }
+    }
+  }
+  gpr_mu_init(&c->mu);
+
+  return grpc_subchannel_index_register(exec_ctx, key, c);
+}
+
+static void continue_connect(grpc_exec_ctx *exec_ctx, 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 = c->next_attempt;
+  args.channel_args = c->args;
+  args.initial_connect_string = c->initial_connect_string;
+
+  grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
+                              GRPC_CHANNEL_CONNECTING, "state_change");
+  grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result,
+                         &c->connected);
+}
+
+static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
+  c->next_attempt =
+      gpr_backoff_begin(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC));
+  continue_connect(exec_ctx, c);
+}
+
+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;
+}
+
+static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg,
+                                           bool success) {
+  external_state_watcher *w = arg;
+  grpc_closure *follow_up = w->notify;
+  if (w->pollset_set != NULL) {
+    grpc_pollset_set_del_pollset_set(exec_ctx, w->subchannel->pollset_set,
+                                     w->pollset_set);
+  }
+  gpr_mu_lock(&w->subchannel->mu);
+  w->next->prev = w->prev;
+  w->prev->next = w->next;
+  gpr_mu_unlock(&w->subchannel->mu);
+  GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, w->subchannel, "external_state_watcher");
+  gpr_free(w);
+  follow_up->cb(exec_ctx, follow_up->cb_arg, success);
+}
+
+void grpc_subchannel_notify_on_state_change(
+    grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
+    grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
+    grpc_closure *notify) {
+  external_state_watcher *w;
+
+  if (state == NULL) {
+    gpr_mu_lock(&c->mu);
+    for (w = c->root_external_state_watcher.next;
+         w != &c->root_external_state_watcher; w = w->next) {
+      if (w->notify == notify) {
+        grpc_connectivity_state_notify_on_state_change(
+            exec_ctx, &c->state_tracker, NULL, &w->closure);
+      }
+    }
+    gpr_mu_unlock(&c->mu);
+  } else {
+    w = gpr_malloc(sizeof(*w));
+    w->subchannel = c;
+    w->pollset_set = interested_parties;
+    w->notify = notify;
+    grpc_closure_init(&w->closure, on_external_state_watcher_done, w);
+    if (interested_parties != NULL) {
+      grpc_pollset_set_add_pollset_set(exec_ctx, c->pollset_set,
+                                       interested_parties);
+    }
+    GRPC_SUBCHANNEL_WEAK_REF(c, "external_state_watcher");
+    gpr_mu_lock(&c->mu);
+    w->next = &c->root_external_state_watcher;
+    w->prev = w->next->prev;
+    w->next->prev = w->prev->next = w;
+    if (grpc_connectivity_state_notify_on_state_change(
+            exec_ctx, &c->state_tracker, state, &w->closure)) {
+      c->connecting = 1;
+      /* released by connection */
+      GRPC_SUBCHANNEL_WEAK_REF(c, "connecting");
+      start_connect(exec_ctx, c);
+    }
+    gpr_mu_unlock(&c->mu);
+  }
+}
+
+void grpc_connected_subchannel_process_transport_op(
+    grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
+    grpc_transport_op *op) {
+  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(exec_ctx, top_elem, op);
+}
+
+static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p,
+                                              bool iomgr_success) {
+  state_watcher *sw = p;
+  grpc_subchannel *c = sw->subchannel;
+  gpr_mu *mu = &c->mu;
+
+  gpr_mu_lock(mu);
+
+  /* if we failed just leave this closure */
+  if (iomgr_success) {
+    if (sw->connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
+      /* any errors on a subchannel ==> we're done, create a new one */
+      sw->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE;
+    }
+    grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
+                                sw->connectivity_state, "reflect_child");
+    if (sw->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) {
+      grpc_connected_subchannel_notify_on_state_change(
+          exec_ctx, GET_CONNECTED_SUBCHANNEL(c, no_barrier), NULL,
+          &sw->connectivity_state, &sw->closure);
+      GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
+      sw = NULL;
+    }
+  }
+
+  gpr_mu_unlock(mu);
+  GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "state_watcher");
+  gpr_free(sw);
+}
+
+static void connected_subchannel_state_op(grpc_exec_ctx *exec_ctx,
+                                          grpc_connected_subchannel *con,
+                                          grpc_pollset_set *interested_parties,
+                                          grpc_connectivity_state *state,
+                                          grpc_closure *closure) {
+  grpc_transport_op op;
+  grpc_channel_element *elem;
+  memset(&op, 0, sizeof(op));
+  op.connectivity_state = state;
+  op.on_connectivity_state_change = closure;
+  op.bind_pollset_set = interested_parties;
+  elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
+  elem->filter->start_transport_op(exec_ctx, elem, &op);
+}
+
+void grpc_connected_subchannel_notify_on_state_change(
+    grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
+    grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
+    grpc_closure *closure) {
+  connected_subchannel_state_op(exec_ctx, con, interested_parties, state,
+                                closure);
+}
+
+void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx,
+                                    grpc_connected_subchannel *con,
+                                    grpc_closure *closure) {
+  grpc_transport_op op;
+  grpc_channel_element *elem;
+  memset(&op, 0, sizeof(op));
+  op.send_ping = closure;
+  elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
+  elem->filter->start_transport_op(exec_ctx, elem, &op);
+}
+
+static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
+                                     grpc_subchannel *c) {
+  grpc_connected_subchannel *con;
+  grpc_channel_stack *stk;
+  state_watcher *sw_subchannel;
+
+  /* construct channel stack */
+  con = grpc_channel_init_create_stack(
+      exec_ctx, GRPC_CLIENT_SUBCHANNEL, 0, c->connecting_result.channel_args, 1,
+      connection_destroy, NULL, c->connecting_result.transport);
+  stk = CHANNEL_STACK_FROM_CONNECTION(con);
+  memset(&c->connecting_result, 0, sizeof(c->connecting_result));
+
+  /* initialize state watcher */
+  sw_subchannel = gpr_malloc(sizeof(*sw_subchannel));
+  sw_subchannel->subchannel = c;
+  sw_subchannel->connectivity_state = GRPC_CHANNEL_READY;
+  grpc_closure_init(&sw_subchannel->closure, subchannel_on_child_state_changed,
+                    sw_subchannel);
+
+  if (c->disconnected) {
+    gpr_free(sw_subchannel);
+    grpc_channel_stack_destroy(exec_ctx, stk);
+    gpr_free(con);
+    GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
+    return;
+  }
+
+  /* publish */
+  /* TODO(ctiller): this full barrier seems to clear up a TSAN failure.
+                    I'd have expected the rel_cas below to be enough, but
+                    seemingly it's not.
+                    Re-evaluate if we really need this. */
+  gpr_atm_full_barrier();
+  GPR_ASSERT(gpr_atm_rel_cas(&c->connected_subchannel, 0, (gpr_atm)con));
+  c->connecting = 0;
+
+  /* setup subchannel watching connected subchannel for changes; subchannel ref
+     for connecting is donated
+     to the state watcher */
+  GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
+  GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
+  grpc_connected_subchannel_notify_on_state_change(
+      exec_ctx, con, c->pollset_set, &sw_subchannel->connectivity_state,
+      &sw_subchannel->closure);
+
+  /* signal completion */
+  grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY,
+                              "connected");
+}
+
+static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) {
+  grpc_subchannel *c = arg;
+  gpr_mu_lock(&c->mu);
+  c->have_alarm = 0;
+  if (c->disconnected) {
+    iomgr_success = 0;
+  }
+  if (iomgr_success) {
+    c->next_attempt =
+        gpr_backoff_step(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC));
+    continue_connect(exec_ctx, c);
+    gpr_mu_unlock(&c->mu);
+  } else {
+    gpr_mu_unlock(&c->mu);
+    GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
+  }
+}
+
+static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
+                                 bool iomgr_success) {
+  grpc_subchannel *c = arg;
+
+  GRPC_SUBCHANNEL_WEAK_REF(c, "connected");
+  gpr_mu_lock(&c->mu);
+  if (c->connecting_result.transport != NULL) {
+    publish_transport_locked(exec_ctx, c);
+  } else if (c->disconnected) {
+    GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
+  } else {
+    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+    GPR_ASSERT(!c->have_alarm);
+    c->have_alarm = 1;
+    grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
+                                GRPC_CHANNEL_TRANSIENT_FAILURE,
+                                "connect_failed");
+    grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now);
+  }
+  gpr_mu_unlock(&c->mu);
+  GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
+}
+
+/*
+ * grpc_subchannel_call implementation
+ */
+
+static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call,
+                                    bool success) {
+  grpc_subchannel_call *c = call;
+  GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
+  grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c));
+  GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, c->connection, "subchannel_call");
+  gpr_free(c);
+  GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0);
+}
+
+void grpc_subchannel_call_ref(
+    grpc_subchannel_call *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
+}
+
+void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
+                                grpc_subchannel_call *c
+                                    GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+  GRPC_CALL_STACK_UNREF(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
+}
+
+char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx,
+                                    grpc_subchannel_call *call) {
+  grpc_call_stack *call_stack = SUBCHANNEL_CALL_TO_CALL_STACK(call);
+  grpc_call_element *top_elem = grpc_call_stack_element(call_stack, 0);
+  return top_elem->filter->get_peer(exec_ctx, top_elem);
+}
+
+void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx,
+                                     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(exec_ctx, top_elem, op);
+}
+
+grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
+    grpc_subchannel *c) {
+  return GET_CONNECTED_SUBCHANNEL(c, acq);
+}
+
+grpc_subchannel_call *grpc_connected_subchannel_create_call(
+    grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
+    grpc_pollset *pollset) {
+  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;
+  GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
+  grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, call,
+                       NULL, NULL, callstk);
+  grpc_call_stack_set_pollset(exec_ctx, callstk, pollset);
+  return call;
+}
+
+grpc_call_stack *grpc_subchannel_call_get_call_stack(
+    grpc_subchannel_call *subchannel_call) {
+  return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call);
+}
diff --git a/src/core/lib/client_config/subchannel.h b/src/core/lib/client_config/subchannel.h
new file mode 100644
index 0000000..b4f545b
--- /dev/null
+++ b/src/core/lib/client_config/subchannel.h
@@ -0,0 +1,174 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_SUBCHANNEL_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_SUBCHANNEL_H
+
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/client_config/connector.h"
+#include "src/core/lib/transport/connectivity_state.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_connected_subchannel grpc_connected_subchannel;
+typedef struct grpc_subchannel_call grpc_subchannel_call;
+typedef struct grpc_subchannel_args grpc_subchannel_args;
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+#define GRPC_SUBCHANNEL_REF(p, r) \
+  grpc_subchannel_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(p, r) \
+  grpc_subchannel_ref_from_weak_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_SUBCHANNEL_UNREF(cl, p, r) \
+  grpc_subchannel_unref((cl), (p), __FILE__, __LINE__, (r))
+#define GRPC_SUBCHANNEL_WEAK_REF(p, r) \
+  grpc_subchannel_weak_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \
+  grpc_subchannel_weak_unref((cl), (p), __FILE__, __LINE__, (r))
+#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) \
+  grpc_connected_subchannel_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_CONNECTED_SUBCHANNEL_UNREF(cl, p, r) \
+  grpc_connected_subchannel_unref((cl), (p), __FILE__, __LINE__, (r))
+#define GRPC_SUBCHANNEL_CALL_REF(p, r) \
+  grpc_subchannel_call_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \
+  grpc_subchannel_call_unref((cl), (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_REF_FROM_WEAK_REF(p, r) \
+  grpc_subchannel_ref_from_weak_ref((p))
+#define GRPC_SUBCHANNEL_UNREF(cl, p, r) grpc_subchannel_unref((cl), (p))
+#define GRPC_SUBCHANNEL_WEAK_REF(p, r) grpc_subchannel_weak_ref((p))
+#define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \
+  grpc_subchannel_weak_unref((cl), (p))
+#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) grpc_connected_subchannel_ref((p))
+#define GRPC_CONNECTED_SUBCHANNEL_UNREF(cl, p, r) \
+  grpc_connected_subchannel_unref((cl), (p))
+#define GRPC_SUBCHANNEL_CALL_REF(p, r) grpc_subchannel_call_ref((p))
+#define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \
+  grpc_subchannel_call_unref((cl), (p))
+#define GRPC_SUBCHANNEL_REF_EXTRA_ARGS
+#endif
+
+grpc_subchannel *grpc_subchannel_ref(
+    grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+grpc_subchannel *grpc_subchannel_ref_from_weak_ref(
+    grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx,
+                           grpc_subchannel *channel
+                               GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+grpc_subchannel *grpc_subchannel_weak_ref(
+    grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
+                                grpc_subchannel *channel
+                                    GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+void grpc_connected_subchannel_ref(
+    grpc_connected_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
+                                     grpc_connected_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_exec_ctx *exec_ctx,
+                                grpc_subchannel_call *call
+                                    GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+
+/** construct a subchannel call */
+grpc_subchannel_call *grpc_connected_subchannel_create_call(
+    grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel,
+    grpc_pollset *pollset);
+
+/** process a transport level op */
+void grpc_connected_subchannel_process_transport_op(
+    grpc_exec_ctx *exec_ctx, grpc_connected_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_exec_ctx *exec_ctx, grpc_subchannel *channel,
+    grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
+    grpc_closure *notify);
+void grpc_connected_subchannel_notify_on_state_change(
+    grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *channel,
+    grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
+    grpc_closure *notify);
+void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx,
+                                    grpc_connected_subchannel *channel,
+                                    grpc_closure *notify);
+
+/** retrieve the grpc_connected_subchannel - or NULL if called before
+    the subchannel becomes connected */
+grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
+    grpc_subchannel *subchannel);
+
+/** continue processing a transport op */
+void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx,
+                                     grpc_subchannel_call *subchannel_call,
+                                     grpc_transport_stream_op *op);
+
+/** continue querying for peer */
+char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx,
+                                    grpc_subchannel_call *subchannel_call);
+
+grpc_call_stack *grpc_subchannel_call_get_call_stack(
+    grpc_subchannel_call *subchannel_call);
+
+struct grpc_subchannel_args {
+  /* When updating this struct, also update subchannel_index.c */
+
+  /** 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;
+};
+
+/** create a subchannel given a connector */
+grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
+                                        grpc_connector *connector,
+                                        grpc_subchannel_args *args);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_SUBCHANNEL_H */
diff --git a/src/core/lib/client_config/subchannel_factory.c b/src/core/lib/client_config/subchannel_factory.c
new file mode 100644
index 0000000..727a48a
--- /dev/null
+++ b/src/core/lib/client_config/subchannel_factory.c
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/subchannel_factory.h"
+
+void grpc_subchannel_factory_ref(grpc_subchannel_factory* factory) {
+  factory->vtable->ref(factory);
+}
+
+void grpc_subchannel_factory_unref(grpc_exec_ctx* exec_ctx,
+                                   grpc_subchannel_factory* factory) {
+  factory->vtable->unref(exec_ctx, factory);
+}
+
+grpc_subchannel* grpc_subchannel_factory_create_subchannel(
+    grpc_exec_ctx* exec_ctx, grpc_subchannel_factory* factory,
+    grpc_subchannel_args* args) {
+  return factory->vtable->create_subchannel(exec_ctx, factory, args);
+}
diff --git a/src/core/lib/client_config/subchannel_factory.h b/src/core/lib/client_config/subchannel_factory.h
new file mode 100644
index 0000000..3ba2f86
--- /dev/null
+++ b/src/core/lib/client_config/subchannel_factory.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H
+
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/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_exec_ctx *exec_ctx, grpc_subchannel_factory *factory);
+  grpc_subchannel *(*create_subchannel)(grpc_exec_ctx *exec_ctx,
+                                        grpc_subchannel_factory *factory,
+                                        grpc_subchannel_args *args);
+};
+
+void grpc_subchannel_factory_ref(grpc_subchannel_factory *factory);
+void grpc_subchannel_factory_unref(grpc_exec_ctx *exec_ctx,
+                                   grpc_subchannel_factory *factory);
+
+/** Create a new grpc_subchannel */
+grpc_subchannel *grpc_subchannel_factory_create_subchannel(
+    grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *factory,
+    grpc_subchannel_args *args);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_SUBCHANNEL_FACTORY_H */
diff --git a/src/core/lib/client_config/subchannel_index.c b/src/core/lib/client_config/subchannel_index.c
new file mode 100644
index 0000000..2c54500
--- /dev/null
+++ b/src/core/lib/client_config/subchannel_index.c
@@ -0,0 +1,262 @@
+//
+//
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//
+
+#include "src/core/lib/client_config/subchannel_index.h"
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/avl.h>
+#include <grpc/support/tls.h>
+
+#include "src/core/lib/channel/channel_args.h"
+
+// a map of subchannel_key --> subchannel, used for detecting connections
+// to the same destination in order to share them
+static gpr_avl g_subchannel_index;
+
+static gpr_mu g_mu;
+
+struct grpc_subchannel_key {
+  grpc_connector *connector;
+  grpc_subchannel_args args;
+};
+
+GPR_TLS_DECL(subchannel_index_exec_ctx);
+
+static void enter_ctx(grpc_exec_ctx *exec_ctx) {
+  GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == 0);
+  gpr_tls_set(&subchannel_index_exec_ctx, (intptr_t)exec_ctx);
+}
+
+static void leave_ctx(grpc_exec_ctx *exec_ctx) {
+  GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == (intptr_t)exec_ctx);
+  gpr_tls_set(&subchannel_index_exec_ctx, 0);
+}
+
+static grpc_exec_ctx *current_ctx() {
+  grpc_exec_ctx *c = (grpc_exec_ctx *)gpr_tls_get(&subchannel_index_exec_ctx);
+  GPR_ASSERT(c != NULL);
+  return c;
+}
+
+static grpc_subchannel_key *create_key(
+    grpc_connector *connector, grpc_subchannel_args *args,
+    grpc_channel_args *(*copy_channel_args)(const grpc_channel_args *args)) {
+  grpc_subchannel_key *k = gpr_malloc(sizeof(*k));
+  k->connector = grpc_connector_ref(connector);
+  k->args.filter_count = args->filter_count;
+  k->args.filters = gpr_malloc(sizeof(*k->args.filters) * k->args.filter_count);
+  memcpy((grpc_channel_filter *)k->args.filters, args->filters,
+         sizeof(*k->args.filters) * k->args.filter_count);
+  k->args.addr_len = args->addr_len;
+  k->args.addr = gpr_malloc(args->addr_len);
+  memcpy(k->args.addr, args->addr, k->args.addr_len);
+  k->args.args = copy_channel_args(args->args);
+  return k;
+}
+
+grpc_subchannel_key *grpc_subchannel_key_create(grpc_connector *connector,
+                                                grpc_subchannel_args *args) {
+  return create_key(connector, args, grpc_channel_args_normalize);
+}
+
+static grpc_subchannel_key *subchannel_key_copy(grpc_subchannel_key *k) {
+  return create_key(k->connector, &k->args, grpc_channel_args_copy);
+}
+
+static int subchannel_key_compare(grpc_subchannel_key *a,
+                                  grpc_subchannel_key *b) {
+  int c = GPR_ICMP(a->connector, b->connector);
+  if (c != 0) return c;
+  c = GPR_ICMP(a->args.addr_len, b->args.addr_len);
+  if (c != 0) return c;
+  c = GPR_ICMP(a->args.filter_count, b->args.filter_count);
+  if (c != 0) return c;
+  c = memcmp(a->args.addr, b->args.addr, a->args.addr_len);
+  if (c != 0) return c;
+  c = memcmp(a->args.filters, b->args.filters,
+             a->args.filter_count * sizeof(*a->args.filters));
+  if (c != 0) return c;
+  return grpc_channel_args_compare(a->args.args, b->args.args);
+}
+
+void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx,
+                                 grpc_subchannel_key *k) {
+  grpc_connector_unref(exec_ctx, k->connector);
+  gpr_free(k->args.addr);
+  gpr_free((grpc_channel_args *)k->args.filters);
+  grpc_channel_args_destroy((grpc_channel_args *)k->args.args);
+  gpr_free(k);
+}
+
+static void sck_avl_destroy(void *p) {
+  grpc_subchannel_key_destroy(current_ctx(), p);
+}
+
+static void *sck_avl_copy(void *p) { return subchannel_key_copy(p); }
+
+static long sck_avl_compare(void *a, void *b) {
+  return subchannel_key_compare(a, b);
+}
+
+static void scv_avl_destroy(void *p) {
+  GRPC_SUBCHANNEL_WEAK_UNREF(current_ctx(), p, "subchannel_index");
+}
+
+static void *scv_avl_copy(void *p) {
+  GRPC_SUBCHANNEL_WEAK_REF(p, "subchannel_index");
+  return p;
+}
+
+static const gpr_avl_vtable subchannel_avl_vtable = {
+    .destroy_key = sck_avl_destroy,
+    .copy_key = sck_avl_copy,
+    .compare_keys = sck_avl_compare,
+    .destroy_value = scv_avl_destroy,
+    .copy_value = scv_avl_copy};
+
+void grpc_subchannel_index_init(void) {
+  g_subchannel_index = gpr_avl_create(&subchannel_avl_vtable);
+  gpr_mu_init(&g_mu);
+  gpr_tls_init(&subchannel_index_exec_ctx);
+}
+
+void grpc_subchannel_index_shutdown(void) {
+  gpr_mu_destroy(&g_mu);
+  gpr_avl_unref(g_subchannel_index);
+  gpr_tls_destroy(&subchannel_index_exec_ctx);
+}
+
+grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx,
+                                            grpc_subchannel_key *key) {
+  enter_ctx(exec_ctx);
+
+  // Lock, and take a reference to the subchannel index.
+  // We don't need to do the search under a lock as avl's are immutable.
+  gpr_mu_lock(&g_mu);
+  gpr_avl index = gpr_avl_ref(g_subchannel_index);
+  gpr_mu_unlock(&g_mu);
+
+  grpc_subchannel *c =
+      GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(gpr_avl_get(index, key), "index_find");
+  gpr_avl_unref(index);
+
+  leave_ctx(exec_ctx);
+  return c;
+}
+
+grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx,
+                                                grpc_subchannel_key *key,
+                                                grpc_subchannel *constructed) {
+  enter_ctx(exec_ctx);
+
+  grpc_subchannel *c = NULL;
+
+  while (c == NULL) {
+    // Compare and swap loop:
+    // - take a reference to the current index
+    gpr_mu_lock(&g_mu);
+    gpr_avl index = gpr_avl_ref(g_subchannel_index);
+    gpr_mu_unlock(&g_mu);
+
+    // - Check to see if a subchannel already exists
+    c = gpr_avl_get(index, key);
+    if (c != NULL) {
+      // yes -> we're done
+      GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, constructed, "index_register");
+    } else {
+      // no -> update the avl and compare/swap
+      gpr_avl updated =
+          gpr_avl_add(gpr_avl_ref(index), subchannel_key_copy(key),
+                      GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"));
+
+      // it may happen (but it's expected to be unlikely)
+      // that some other thread has changed the index:
+      // compare/swap here to check that, and retry as necessary
+      gpr_mu_lock(&g_mu);
+      if (index.root == g_subchannel_index.root) {
+        GPR_SWAP(gpr_avl, updated, g_subchannel_index);
+        c = constructed;
+      }
+      gpr_mu_unlock(&g_mu);
+
+      gpr_avl_unref(updated);
+    }
+    gpr_avl_unref(index);
+  }
+
+  leave_ctx(exec_ctx);
+
+  return c;
+}
+
+void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx,
+                                      grpc_subchannel_key *key,
+                                      grpc_subchannel *constructed) {
+  enter_ctx(exec_ctx);
+
+  bool done = false;
+  while (!done) {
+    // Compare and swap loop:
+    // - take a reference to the current index
+    gpr_mu_lock(&g_mu);
+    gpr_avl index = gpr_avl_ref(g_subchannel_index);
+    gpr_mu_unlock(&g_mu);
+
+    // Check to see if this key still refers to the previously
+    // registered subchannel
+    grpc_subchannel *c = gpr_avl_get(index, key);
+    if (c != constructed) {
+      gpr_avl_unref(index);
+      break;
+    }
+
+    // compare and swap the update (some other thread may have
+    // mutated the index behind us)
+    gpr_avl updated = gpr_avl_remove(gpr_avl_ref(index), key);
+
+    gpr_mu_lock(&g_mu);
+    if (index.root == g_subchannel_index.root) {
+      GPR_SWAP(gpr_avl, updated, g_subchannel_index);
+      done = true;
+    }
+    gpr_mu_unlock(&g_mu);
+
+    gpr_avl_unref(updated);
+    gpr_avl_unref(index);
+  }
+
+  leave_ctx(exec_ctx);
+}
diff --git a/src/core/lib/client_config/subchannel_index.h b/src/core/lib/client_config/subchannel_index.h
new file mode 100644
index 0000000..bc5f03b
--- /dev/null
+++ b/src/core/lib/client_config/subchannel_index.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_SUBCHANNEL_INDEX_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_SUBCHANNEL_INDEX_H
+
+#include "src/core/lib/client_config/connector.h"
+#include "src/core/lib/client_config/subchannel.h"
+
+/** \file Provides an index of active subchannels so that they can be
+    shared amongst channels */
+
+typedef struct grpc_subchannel_key grpc_subchannel_key;
+
+/** Create a key that can be used to uniquely identify a subchannel */
+grpc_subchannel_key *grpc_subchannel_key_create(grpc_connector *con,
+                                                grpc_subchannel_args *args);
+
+/** Destroy a subchannel key */
+void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx,
+                                 grpc_subchannel_key *key);
+
+/** Given a subchannel key, find the subchannel registered for it.
+    Returns NULL if no such channel exists.
+    Thread-safe. */
+grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx,
+                                            grpc_subchannel_key *key);
+
+/** Register a subchannel against a key.
+    Takes ownership of \a constructed.
+    Returns the registered subchannel. This may be different from
+    \a constructed in the case of a registration race. */
+grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx,
+                                                grpc_subchannel_key *key,
+                                                grpc_subchannel *constructed);
+
+/** Remove \a constructed as the registered subchannel for \a key. */
+void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx,
+                                      grpc_subchannel_key *key,
+                                      grpc_subchannel *constructed);
+
+/** Initialize the subchannel index (global) */
+void grpc_subchannel_index_init(void);
+/** Shutdown the subchannel index (global) */
+void grpc_subchannel_index_shutdown(void);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_SUBCHANNEL_INDEX_H */
diff --git a/src/core/lib/client_config/uri_parser.c b/src/core/lib/client_config/uri_parser.c
new file mode 100644
index 0000000..d3228de
--- /dev/null
+++ b/src/core/lib/client_config/uri_parser.c
@@ -0,0 +1,242 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/uri_parser.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/string_util.h>
+
+/** a size_t default value... maps to all 1's */
+#define NOT_SET (~(size_t)0)
+
+static grpc_uri *bad_uri(const char *uri_text, size_t pos, const char *section,
+                         int suppress_errors) {
+  char *line_prefix;
+  size_t 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;
+}
+
+/** Returns a copy of \a src[begin, end) */
+static char *copy_component(const char *src, size_t begin, size_t end) {
+  char *out = gpr_malloc(end - begin + 1);
+  memcpy(out, src + begin, end - begin);
+  out[end - begin] = 0;
+  return out;
+}
+
+/** Returns how many chars to advance if \a uri_text[i] begins a valid \a pchar
+ * production. If \a uri_text[i] introduces an invalid \a pchar (such as percent
+ * sign not followed by two hex digits), NOT_SET is returned. */
+static size_t parse_pchar(const char *uri_text, size_t i) {
+  /* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+   * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+   * pct-encoded = "%" HEXDIG HEXDIG
+   * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+   / "*" / "+" / "," / ";" / "=" */
+  char c = uri_text[i];
+  if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
+      ((c >= '0') && (c <= '9')) ||
+      (c == '-' || c == '.' || c == '_' || c == '~') || /* unreserved */
+      (c == '!' || c == '$' || c == '&' || c == '\'' || c == '$' || c == '&' ||
+       c == '(' || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' ||
+       c == '=') /* sub-delims */) {
+    return 1;
+  }
+  if (c == '%') { /* pct-encoded */
+    size_t j;
+    if (uri_text[i + 1] == 0 || uri_text[i + 2] == 0) {
+      return NOT_SET;
+    }
+    for (j = i + 1; j < 2; j++) {
+      c = uri_text[j];
+      if (!(((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) ||
+            ((c >= 'A') && (c <= 'F')))) {
+        return NOT_SET;
+      }
+    }
+    return 2;
+  }
+  return 0;
+}
+
+/* *( pchar / "?" / "/" ) */
+static int parse_fragment_or_query(const char *uri_text, size_t *i) {
+  char c;
+  while ((c = uri_text[*i]) != 0) {
+    const size_t advance = parse_pchar(uri_text, *i); /* pchar */
+    switch (advance) {
+      case 0: /* uri_text[i] isn't in pchar */
+        /* maybe it's ? or / */
+        if (uri_text[*i] == '?' || uri_text[*i] == '/') {
+          (*i)++;
+          break;
+        } else {
+          return 1;
+        }
+        GPR_UNREACHABLE_CODE(return 0);
+      default:
+        (*i) += advance;
+        break;
+      case NOT_SET: /* uri_text[i] introduces an invalid URI */
+        return 0;
+    }
+  }
+  /* *i is the first uri_text position past the \a query production, maybe \0 */
+  return 1;
+}
+
+grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
+  grpc_uri *uri;
+  size_t scheme_begin = 0;
+  size_t scheme_end = NOT_SET;
+  size_t authority_begin = NOT_SET;
+  size_t authority_end = NOT_SET;
+  size_t path_begin = NOT_SET;
+  size_t path_end = NOT_SET;
+  size_t query_begin = NOT_SET;
+  size_t query_end = NOT_SET;
+  size_t fragment_begin = NOT_SET;
+  size_t fragment_end = NOT_SET;
+  size_t 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 == NOT_SET) {
+    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 == NOT_SET;
+         i++) {
+      if (uri_text[i] == '/' || uri_text[i] == '?' || uri_text[i] == '#') {
+        authority_end = i;
+      }
+    }
+    if (authority_end == NOT_SET && uri_text[i] == 0) {
+      authority_end = i;
+    }
+    if (authority_end == NOT_SET) {
+      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] == '?' || uri_text[i] == '#') {
+      path_end = i;
+      break;
+    }
+  }
+  if (path_end == NOT_SET && uri_text[i] == 0) {
+    path_end = i;
+  }
+  if (path_end == NOT_SET) {
+    return bad_uri(uri_text, i, "path", suppress_errors);
+  }
+
+  if (uri_text[i] == '?') {
+    query_begin = ++i;
+    if (!parse_fragment_or_query(uri_text, &i)) {
+      return bad_uri(uri_text, i, "query", suppress_errors);
+    } else if (uri_text[i] != 0 && uri_text[i] != '#') {
+      /* We must be at the end or at the beginning of a fragment */
+      return bad_uri(uri_text, i, "query", suppress_errors);
+    }
+    query_end = i;
+  }
+  if (uri_text[i] == '#') {
+    fragment_begin = ++i;
+    if (!parse_fragment_or_query(uri_text, &i)) {
+      return bad_uri(uri_text, i - fragment_end, "fragment", suppress_errors);
+    } else if (uri_text[i] != 0) {
+      /* We must be at the end */
+      return bad_uri(uri_text, i, "fragment", suppress_errors);
+    }
+    fragment_end = i;
+  }
+
+  uri = gpr_malloc(sizeof(*uri));
+  memset(uri, 0, sizeof(*uri));
+  uri->scheme = copy_component(uri_text, scheme_begin, scheme_end);
+  uri->authority = copy_component(uri_text, authority_begin, authority_end);
+  uri->path = copy_component(uri_text, path_begin, path_end);
+  uri->query = copy_component(uri_text, query_begin, query_end);
+  uri->fragment = copy_component(uri_text, fragment_begin, fragment_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->query);
+  gpr_free(uri->fragment);
+  gpr_free(uri);
+}
diff --git a/src/core/lib/client_config/uri_parser.h b/src/core/lib/client_config/uri_parser.h
new file mode 100644
index 0000000..d70d451
--- /dev/null
+++ b/src/core/lib/client_config/uri_parser.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_URI_PARSER_H
+#define GRPC_CORE_LIB_CLIENT_CONFIG_URI_PARSER_H
+
+typedef struct {
+  char *scheme;
+  char *authority;
+  char *path;
+  char *query;
+  char *fragment;
+} grpc_uri;
+
+/** parse a uri, return NULL on failure */
+grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors);
+
+/** destroy a uri */
+void grpc_uri_destroy(grpc_uri *uri);
+
+#endif /* GRPC_CORE_LIB_CLIENT_CONFIG_URI_PARSER_H */
diff --git a/src/core/lib/compression/algorithm_metadata.h b/src/core/lib/compression/algorithm_metadata.h
new file mode 100644
index 0000000..47f33ab
--- /dev/null
+++ b/src/core/lib/compression/algorithm_metadata.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_COMPRESSION_ALGORITHM_METADATA_H
+#define GRPC_CORE_LIB_COMPRESSION_ALGORITHM_METADATA_H
+
+#include <grpc/compression.h>
+#include "src/core/lib/transport/metadata.h"
+
+/** Return compression algorithm based metadata value */
+grpc_mdstr *grpc_compression_algorithm_mdstr(
+    grpc_compression_algorithm algorithm);
+
+/** Return compression algorithm based metadata element (grpc-encoding: xxx) */
+grpc_mdelem *grpc_compression_encoding_mdelem(
+    grpc_compression_algorithm algorithm);
+
+/** Find compression algorithm based on passed in mdstr - returns
+ * GRPC_COMPRESS_ALGORITHM_COUNT on failure */
+grpc_compression_algorithm grpc_compression_algorithm_from_mdstr(
+    grpc_mdstr *str);
+
+#endif /* GRPC_CORE_LIB_COMPRESSION_ALGORITHM_METADATA_H */
diff --git a/src/core/lib/compression/compression_algorithm.c b/src/core/lib/compression/compression_algorithm.c
new file mode 100644
index 0000000..f781b45
--- /dev/null
+++ b/src/core/lib/compression/compression_algorithm.c
@@ -0,0 +1,203 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/compression.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/compression/algorithm_metadata.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+int grpc_compression_algorithm_parse(const char *name, size_t name_length,
+                                     grpc_compression_algorithm *algorithm) {
+  /* we use strncmp not only because it's safer (even though in this case it
+   * doesn't matter, given that we are comparing against string literals, but
+   * because this way we needn't have "name" nil-terminated (useful for slice
+   * data, for example) */
+  GRPC_API_TRACE(
+      "grpc_compression_algorithm_parse("
+      "name=%*.*s, name_length=%lu, algorithm=%p)",
+      5, ((int)name_length, (int)name_length, name, (unsigned long)name_length,
+          algorithm));
+  if (name_length == 0) {
+    return 0;
+  }
+  if (strncmp(name, "identity", name_length) == 0) {
+    *algorithm = GRPC_COMPRESS_NONE;
+  } else if (strncmp(name, "gzip", name_length) == 0) {
+    *algorithm = GRPC_COMPRESS_GZIP;
+  } else if (strncmp(name, "deflate", name_length) == 0) {
+    *algorithm = GRPC_COMPRESS_DEFLATE;
+  } else {
+    return 0;
+  }
+  return 1;
+}
+
+int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm,
+                                    char **name) {
+  GRPC_API_TRACE("grpc_compression_algorithm_parse(algorithm=%d, name=%p)", 2,
+                 ((int)algorithm, name));
+  switch (algorithm) {
+    case GRPC_COMPRESS_NONE:
+      *name = "identity";
+      return 1;
+    case GRPC_COMPRESS_DEFLATE:
+      *name = "deflate";
+      return 1;
+    case GRPC_COMPRESS_GZIP:
+      *name = "gzip";
+      return 1;
+    case GRPC_COMPRESS_ALGORITHMS_COUNT:
+      return 0;
+  }
+  return 0;
+}
+
+grpc_compression_algorithm grpc_compression_algorithm_from_mdstr(
+    grpc_mdstr *str) {
+  if (str == GRPC_MDSTR_IDENTITY) return GRPC_COMPRESS_NONE;
+  if (str == GRPC_MDSTR_DEFLATE) return GRPC_COMPRESS_DEFLATE;
+  if (str == GRPC_MDSTR_GZIP) return GRPC_COMPRESS_GZIP;
+  return GRPC_COMPRESS_ALGORITHMS_COUNT;
+}
+
+grpc_mdstr *grpc_compression_algorithm_mdstr(
+    grpc_compression_algorithm algorithm) {
+  switch (algorithm) {
+    case GRPC_COMPRESS_NONE:
+      return GRPC_MDSTR_IDENTITY;
+    case GRPC_COMPRESS_DEFLATE:
+      return GRPC_MDSTR_DEFLATE;
+    case GRPC_COMPRESS_GZIP:
+      return GRPC_MDSTR_GZIP;
+    case GRPC_COMPRESS_ALGORITHMS_COUNT:
+      return NULL;
+  }
+  return NULL;
+}
+
+grpc_mdelem *grpc_compression_encoding_mdelem(
+    grpc_compression_algorithm algorithm) {
+  switch (algorithm) {
+    case GRPC_COMPRESS_NONE:
+      return GRPC_MDELEM_GRPC_ENCODING_IDENTITY;
+    case GRPC_COMPRESS_DEFLATE:
+      return GRPC_MDELEM_GRPC_ENCODING_DEFLATE;
+    case GRPC_COMPRESS_GZIP:
+      return GRPC_MDELEM_GRPC_ENCODING_GZIP;
+    default:
+      break;
+  }
+  return NULL;
+}
+
+/* TODO(dgq): Add the ability to specify parameters to the individual
+ * compression algorithms */
+grpc_compression_algorithm grpc_compression_algorithm_for_level(
+    grpc_compression_level level, uint32_t accepted_encodings) {
+  GRPC_API_TRACE("grpc_compression_algorithm_for_level(level=%d)", 1,
+                 ((int)level));
+  if (level > GRPC_COMPRESS_LEVEL_HIGH) {
+    gpr_log(GPR_ERROR, "Unknown compression level %d.", (int)level);
+    abort();
+  }
+
+  const size_t num_supported =
+      GPR_BITCOUNT(accepted_encodings) - 1; /* discard NONE */
+  if (level == GRPC_COMPRESS_LEVEL_NONE || num_supported == 0) {
+    return GRPC_COMPRESS_NONE;
+  }
+
+  GPR_ASSERT(level > 0);
+
+  /* Establish a "ranking" or compression algorithms in increasing order of
+   * compression.
+   * This is simplistic and we will probably want to introduce other dimensions
+   * in the future (cpu/memory cost, etc). */
+  const grpc_compression_algorithm algos_ranking[] = {GRPC_COMPRESS_GZIP,
+                                                      GRPC_COMPRESS_DEFLATE};
+
+  /* intersect algos_ranking with the supported ones keeping the ranked order */
+  grpc_compression_algorithm
+      sorted_supported_algos[GRPC_COMPRESS_ALGORITHMS_COUNT];
+  size_t algos_supported_idx = 0;
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(algos_ranking); i++) {
+    const grpc_compression_algorithm alg = algos_ranking[i];
+    for (size_t j = 0; j < num_supported; j++) {
+      if (GPR_BITGET(accepted_encodings, alg) == 1) {
+        /* if \a alg in supported */
+        sorted_supported_algos[algos_supported_idx++] = alg;
+        break;
+      }
+    }
+    if (algos_supported_idx == num_supported) break;
+  }
+
+  switch (level) {
+    case GRPC_COMPRESS_LEVEL_NONE:
+      abort(); /* should have been handled already */
+    case GRPC_COMPRESS_LEVEL_LOW:
+      return sorted_supported_algos[0];
+    case GRPC_COMPRESS_LEVEL_MED:
+      return sorted_supported_algos[num_supported / 2];
+    case GRPC_COMPRESS_LEVEL_HIGH:
+      return sorted_supported_algos[num_supported - 1];
+    default:
+      abort();
+  };
+}
+
+void grpc_compression_options_init(grpc_compression_options *opts) {
+  opts->enabled_algorithms_bitset = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
+  opts->default_compression_algorithm = GRPC_COMPRESS_NONE;
+}
+
+void grpc_compression_options_enable_algorithm(
+    grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
+  GPR_BITSET(&opts->enabled_algorithms_bitset, algorithm);
+}
+
+void grpc_compression_options_disable_algorithm(
+    grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
+  GPR_BITCLEAR(&opts->enabled_algorithms_bitset, algorithm);
+}
+
+int grpc_compression_options_is_algorithm_enabled(
+    const grpc_compression_options *opts,
+    grpc_compression_algorithm algorithm) {
+  return GPR_BITGET(opts->enabled_algorithms_bitset, algorithm);
+}
diff --git a/src/core/lib/compression/message_compress.c b/src/core/lib/compression/message_compress.c
new file mode 100644
index 0000000..b4b6a2d
--- /dev/null
+++ b/src/core/lib/compression/message_compress.c
@@ -0,0 +1,198 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/compression/message_compress.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include <zlib.h>
+
+#define OUTPUT_BLOCK_SIZE 1024
+
+static int zlib_body(z_stream* zs, gpr_slice_buffer* input,
+                     gpr_slice_buffer* output,
+                     int (*flate)(z_stream* zs, int flush)) {
+  int r;
+  int flush;
+  size_t i;
+  gpr_slice outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
+  const uInt uint_max = ~(uInt)0;
+
+  GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max);
+  zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf);
+  zs->next_out = GPR_SLICE_START_PTR(outbuf);
+  flush = Z_NO_FLUSH;
+  for (i = 0; i < input->count; i++) {
+    if (i == input->count - 1) flush = Z_FINISH;
+    GPR_ASSERT(GPR_SLICE_LENGTH(input->slices[i]) <= uint_max);
+    zs->avail_in = (uInt)GPR_SLICE_LENGTH(input->slices[i]);
+    zs->next_in = GPR_SLICE_START_PTR(input->slices[i]);
+    do {
+      if (zs->avail_out == 0) {
+        gpr_slice_buffer_add_indexed(output, outbuf);
+        outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
+        GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max);
+        zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf);
+        zs->next_out = GPR_SLICE_START_PTR(outbuf);
+      }
+      r = flate(zs, flush);
+      if (r < 0 && r != Z_BUF_ERROR /* not fatal */) {
+        gpr_log(GPR_INFO, "zlib error (%d)", r);
+        goto error;
+      }
+    } while (zs->avail_out == 0);
+    if (zs->avail_in) {
+      gpr_log(GPR_INFO, "zlib: not all input consumed");
+      goto error;
+    }
+  }
+
+  GPR_ASSERT(outbuf.refcount);
+  outbuf.data.refcounted.length -= zs->avail_out;
+  gpr_slice_buffer_add_indexed(output, outbuf);
+
+  return 1;
+
+error:
+  gpr_slice_unref(outbuf);
+  return 0;
+}
+
+static void* zalloc_gpr(void* opaque, unsigned int items, unsigned int size) {
+  return gpr_malloc(items * size);
+}
+
+static void zfree_gpr(void* opaque, void* address) { gpr_free(address); }
+
+static int zlib_compress(gpr_slice_buffer* input, gpr_slice_buffer* output,
+                         int gzip) {
+  z_stream zs;
+  int r;
+  size_t i;
+  size_t count_before = output->count;
+  size_t length_before = output->length;
+  memset(&zs, 0, sizeof(zs));
+  zs.zalloc = zalloc_gpr;
+  zs.zfree = zfree_gpr;
+  r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0),
+                   8, Z_DEFAULT_STRATEGY);
+  GPR_ASSERT(r == Z_OK);
+  r = zlib_body(&zs, input, output, deflate) && output->length < input->length;
+  if (!r) {
+    for (i = count_before; i < output->count; i++) {
+      gpr_slice_unref(output->slices[i]);
+    }
+    output->count = count_before;
+    output->length = length_before;
+  }
+  deflateEnd(&zs);
+  return r;
+}
+
+static int zlib_decompress(gpr_slice_buffer* input, gpr_slice_buffer* output,
+                           int gzip) {
+  z_stream zs;
+  int r;
+  size_t i;
+  size_t count_before = output->count;
+  size_t length_before = output->length;
+  memset(&zs, 0, sizeof(zs));
+  zs.zalloc = zalloc_gpr;
+  zs.zfree = zfree_gpr;
+  r = inflateInit2(&zs, 15 | (gzip ? 16 : 0));
+  GPR_ASSERT(r == Z_OK);
+  r = zlib_body(&zs, input, output, inflate);
+  if (!r) {
+    for (i = count_before; i < output->count; i++) {
+      gpr_slice_unref(output->slices[i]);
+    }
+    output->count = count_before;
+    output->length = length_before;
+  }
+  inflateEnd(&zs);
+  return r;
+}
+
+static int copy(gpr_slice_buffer* input, gpr_slice_buffer* output) {
+  size_t i;
+  for (i = 0; i < input->count; i++) {
+    gpr_slice_buffer_add(output, gpr_slice_ref(input->slices[i]));
+  }
+  return 1;
+}
+
+static int compress_inner(grpc_compression_algorithm algorithm,
+                          gpr_slice_buffer* input, gpr_slice_buffer* output) {
+  switch (algorithm) {
+    case GRPC_COMPRESS_NONE:
+      /* the fallback path always needs to be send uncompressed: we simply
+         rely on that here */
+      return 0;
+    case GRPC_COMPRESS_DEFLATE:
+      return zlib_compress(input, output, 0);
+    case GRPC_COMPRESS_GZIP:
+      return zlib_compress(input, output, 1);
+    case GRPC_COMPRESS_ALGORITHMS_COUNT:
+      break;
+  }
+  gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
+  return 0;
+}
+
+int grpc_msg_compress(grpc_compression_algorithm algorithm,
+                      gpr_slice_buffer* input, gpr_slice_buffer* output) {
+  if (!compress_inner(algorithm, input, output)) {
+    copy(input, output);
+    return 0;
+  }
+  return 1;
+}
+
+int grpc_msg_decompress(grpc_compression_algorithm algorithm,
+                        gpr_slice_buffer* input, gpr_slice_buffer* output) {
+  switch (algorithm) {
+    case GRPC_COMPRESS_NONE:
+      return copy(input, output);
+    case GRPC_COMPRESS_DEFLATE:
+      return zlib_decompress(input, output, 0);
+    case GRPC_COMPRESS_GZIP:
+      return zlib_decompress(input, output, 1);
+    case GRPC_COMPRESS_ALGORITHMS_COUNT:
+      break;
+  }
+  gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
+  return 0;
+}
diff --git a/src/core/lib/compression/message_compress.h b/src/core/lib/compression/message_compress.h
new file mode 100644
index 0000000..b716081
--- /dev/null
+++ b/src/core/lib/compression/message_compress.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H
+#define GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H
+
+#include <grpc/compression.h>
+#include <grpc/support/slice_buffer.h>
+
+/* compress 'input' to 'output' using 'algorithm'.
+   On success, appends compressed slices to output and returns 1.
+   On failure, appends uncompressed slices to output and returns 0. */
+int grpc_msg_compress(grpc_compression_algorithm algorithm,
+                      gpr_slice_buffer* input, gpr_slice_buffer* output);
+
+/* decompress 'input' to 'output' using 'algorithm'.
+   On success, appends slices to output and returns 1.
+   On failure, output is unchanged, and returns 0. */
+int grpc_msg_decompress(grpc_compression_algorithm algorithm,
+                        gpr_slice_buffer* input, gpr_slice_buffer* output);
+
+#endif /* GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H */
diff --git a/src/core/lib/debug/trace.c b/src/core/lib/debug/trace.c
new file mode 100644
index 0000000..786dd93
--- /dev/null
+++ b/src/core/lib/debug/trace.c
@@ -0,0 +1,136 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/debug/trace.h"
+
+#include <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "src/core/lib/support/env.h"
+
+typedef struct tracer {
+  const char *name;
+  int *flag;
+  struct tracer *next;
+} tracer;
+static tracer *tracers;
+
+void grpc_register_tracer(const char *name, int *flag) {
+  tracer *t = gpr_malloc(sizeof(*t));
+  t->name = name;
+  t->flag = flag;
+  t->next = tracers;
+  *flag = 0;
+  tracers = t;
+}
+
+static void add(const char *beg, const char *end, char ***ss, size_t *ns) {
+  size_t n = *ns;
+  size_t np = n + 1;
+  char *s;
+  size_t len;
+  GPR_ASSERT(end >= beg);
+  len = (size_t)(end - beg);
+  s = gpr_malloc(len + 1);
+  memcpy(s, beg, len);
+  s[len] = 0;
+  *ss = gpr_realloc(*ss, sizeof(char **) * np);
+  (*ss)[n] = s;
+  *ns = np;
+}
+
+static void split(const char *s, char ***ss, size_t *ns) {
+  const char *c = strchr(s, ',');
+  if (c == NULL) {
+    add(s, s + strlen(s), ss, ns);
+  } else {
+    add(s, c, ss, ns);
+    split(c + 1, ss, ns);
+  }
+}
+
+static void parse(const char *s) {
+  char **strings = NULL;
+  size_t nstrings = 0;
+  size_t i;
+  split(s, &strings, &nstrings);
+
+  for (i = 0; i < nstrings; i++) {
+    grpc_tracer_set_enabled(strings[i], 1);
+  }
+
+  for (i = 0; i < nstrings; i++) {
+    gpr_free(strings[i]);
+  }
+  gpr_free(strings);
+}
+
+void grpc_tracer_init(const char *env_var) {
+  char *e = gpr_getenv(env_var);
+  if (e != NULL) {
+    parse(e);
+    gpr_free(e);
+  }
+}
+
+void grpc_tracer_shutdown(void) {
+  while (tracers) {
+    tracer *t = tracers;
+    tracers = t->next;
+    gpr_free(t);
+  }
+}
+
+int grpc_tracer_set_enabled(const char *name, int enabled) {
+  tracer *t;
+  if (0 == strcmp(name, "all")) {
+    for (t = tracers; t; t = t->next) {
+      *t->flag = 1;
+    }
+  } else {
+    int found = 0;
+    for (t = tracers; t; t = t->next) {
+      if (0 == strcmp(name, t->name)) {
+        *t->flag = enabled;
+        found = 1;
+      }
+    }
+    if (!found) {
+      gpr_log(GPR_ERROR, "Unknown trace var: '%s'", name);
+      return 0; /* early return */
+    }
+  }
+  return 1;
+}
diff --git a/src/core/lib/debug/trace.h b/src/core/lib/debug/trace.h
new file mode 100644
index 0000000..76ea5a7
--- /dev/null
+++ b/src/core/lib/debug/trace.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_DEBUG_TRACE_H
+#define GRPC_CORE_LIB_DEBUG_TRACE_H
+
+#include <grpc/support/port_platform.h>
+
+void grpc_register_tracer(const char *name, int *flag);
+void grpc_tracer_init(const char *env_var_name);
+void grpc_tracer_shutdown(void);
+
+#endif /* GRPC_CORE_LIB_DEBUG_TRACE_H */
diff --git a/src/core/lib/http/format_request.c b/src/core/lib/http/format_request.c
new file mode 100644
index 0000000..95b3918
--- /dev/null
+++ b/src/core/lib/http/format_request.c
@@ -0,0 +1,120 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/http/format_request.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
+
+static void fill_common_header(const grpc_httpcli_request *request,
+                               gpr_strvec *buf) {
+  size_t i;
+  gpr_strvec_add(buf, gpr_strdup(request->http.path));
+  gpr_strvec_add(buf, gpr_strdup(" HTTP/1.0\r\n"));
+  /* just in case some crazy server really expects HTTP/1.1 */
+  gpr_strvec_add(buf, gpr_strdup("Host: "));
+  gpr_strvec_add(buf, gpr_strdup(request->host));
+  gpr_strvec_add(buf, gpr_strdup("\r\n"));
+  gpr_strvec_add(buf, gpr_strdup("Connection: close\r\n"));
+  gpr_strvec_add(buf,
+                 gpr_strdup("User-Agent: " GRPC_HTTPCLI_USER_AGENT "\r\n"));
+  /* user supplied headers */
+  for (i = 0; i < request->http.hdr_count; i++) {
+    gpr_strvec_add(buf, gpr_strdup(request->http.hdrs[i].key));
+    gpr_strvec_add(buf, gpr_strdup(": "));
+    gpr_strvec_add(buf, gpr_strdup(request->http.hdrs[i].value));
+    gpr_strvec_add(buf, gpr_strdup("\r\n"));
+  }
+}
+
+gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request) {
+  gpr_strvec out;
+  char *flat;
+  size_t flat_len;
+
+  gpr_strvec_init(&out);
+  gpr_strvec_add(&out, gpr_strdup("GET "));
+  fill_common_header(request, &out);
+  gpr_strvec_add(&out, gpr_strdup("\r\n"));
+
+  flat = gpr_strvec_flatten(&out, &flat_len);
+  gpr_strvec_destroy(&out);
+
+  return gpr_slice_new(flat, flat_len, gpr_free);
+}
+
+gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
+                                           const char *body_bytes,
+                                           size_t body_size) {
+  gpr_strvec out;
+  char *tmp;
+  size_t out_len;
+  size_t i;
+
+  gpr_strvec_init(&out);
+
+  gpr_strvec_add(&out, gpr_strdup("POST "));
+  fill_common_header(request, &out);
+  if (body_bytes) {
+    uint8_t has_content_type = 0;
+    for (i = 0; i < request->http.hdr_count; i++) {
+      if (strcmp(request->http.hdrs[i].key, "Content-Type") == 0) {
+        has_content_type = 1;
+        break;
+      }
+    }
+    if (!has_content_type) {
+      gpr_strvec_add(&out, gpr_strdup("Content-Type: text/plain\r\n"));
+    }
+    gpr_asprintf(&tmp, "Content-Length: %lu\r\n", (unsigned long)body_size);
+    gpr_strvec_add(&out, tmp);
+  }
+  gpr_strvec_add(&out, gpr_strdup("\r\n"));
+  tmp = gpr_strvec_flatten(&out, &out_len);
+  gpr_strvec_destroy(&out);
+
+  if (body_bytes) {
+    tmp = gpr_realloc(tmp, out_len + body_size);
+    memcpy(tmp + out_len, body_bytes, body_size);
+    out_len += body_size;
+  }
+
+  return gpr_slice_new(tmp, out_len, gpr_free);
+}
diff --git a/src/core/lib/http/format_request.h b/src/core/lib/http/format_request.h
new file mode 100644
index 0000000..2e933d8
--- /dev/null
+++ b/src/core/lib/http/format_request.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_HTTP_FORMAT_REQUEST_H
+#define GRPC_CORE_LIB_HTTP_FORMAT_REQUEST_H
+
+#include <grpc/support/slice.h>
+#include "src/core/lib/http/httpcli.h"
+
+gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request);
+gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
+                                           const char *body_bytes,
+                                           size_t body_size);
+
+#endif /* GRPC_CORE_LIB_HTTP_FORMAT_REQUEST_H */
diff --git a/src/core/lib/http/httpcli.c b/src/core/lib/http/httpcli.c
new file mode 100644
index 0000000..aab28ad
--- /dev/null
+++ b/src/core/lib/http/httpcli.c
@@ -0,0 +1,293 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/http/format_request.h"
+#include "src/core/lib/http/parser.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/support/string.h"
+
+typedef struct {
+  gpr_slice request_text;
+  grpc_http_parser parser;
+  grpc_resolved_addresses *addresses;
+  size_t next_address;
+  grpc_endpoint *ep;
+  char *host;
+  char *ssl_host_override;
+  gpr_timespec deadline;
+  int have_read_byte;
+  const grpc_httpcli_handshaker *handshaker;
+  grpc_httpcli_response_cb on_response;
+  void *user_data;
+  grpc_httpcli_context *context;
+  grpc_pollset *pollset;
+  grpc_iomgr_object iomgr_obj;
+  gpr_slice_buffer incoming;
+  gpr_slice_buffer outgoing;
+  grpc_closure on_read;
+  grpc_closure done_write;
+  grpc_closure connected;
+} internal_request;
+
+static grpc_httpcli_get_override g_get_override = NULL;
+static grpc_httpcli_post_override g_post_override = NULL;
+
+static void plaintext_handshake(grpc_exec_ctx *exec_ctx, void *arg,
+                                grpc_endpoint *endpoint, const char *host,
+                                void (*on_done)(grpc_exec_ctx *exec_ctx,
+                                                void *arg,
+                                                grpc_endpoint *endpoint)) {
+  on_done(exec_ctx, arg, endpoint);
+}
+
+const grpc_httpcli_handshaker grpc_httpcli_plaintext = {"http",
+                                                        plaintext_handshake};
+
+void grpc_httpcli_context_init(grpc_httpcli_context *context) {
+  context->pollset_set = grpc_pollset_set_create();
+}
+
+void grpc_httpcli_context_destroy(grpc_httpcli_context *context) {
+  grpc_pollset_set_destroy(context->pollset_set);
+}
+
+static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req);
+
+static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
+                   int success) {
+  grpc_pollset_set_del_pollset(exec_ctx, req->context->pollset_set,
+                               req->pollset);
+  req->on_response(exec_ctx, req->user_data,
+                   success ? &req->parser.http.response : NULL);
+  grpc_http_parser_destroy(&req->parser);
+  if (req->addresses != NULL) {
+    grpc_resolved_addresses_destroy(req->addresses);
+  }
+  if (req->ep != NULL) {
+    grpc_endpoint_destroy(exec_ctx, req->ep);
+  }
+  gpr_slice_unref(req->request_text);
+  gpr_free(req->host);
+  gpr_free(req->ssl_host_override);
+  grpc_iomgr_unregister_object(&req->iomgr_obj);
+  gpr_slice_buffer_destroy(&req->incoming);
+  gpr_slice_buffer_destroy(&req->outgoing);
+  gpr_free(req);
+}
+
+static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success);
+
+static void do_read(grpc_exec_ctx *exec_ctx, internal_request *req) {
+  grpc_endpoint_read(exec_ctx, req->ep, &req->incoming, &req->on_read);
+}
+
+static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
+  internal_request *req = user_data;
+  size_t i;
+
+  for (i = 0; i < req->incoming.count; i++) {
+    if (GPR_SLICE_LENGTH(req->incoming.slices[i])) {
+      req->have_read_byte = 1;
+      if (!grpc_http_parser_parse(&req->parser, req->incoming.slices[i])) {
+        finish(exec_ctx, req, 0);
+        return;
+      }
+    }
+  }
+
+  if (success) {
+    do_read(exec_ctx, req);
+  } else if (!req->have_read_byte) {
+    next_address(exec_ctx, req);
+  } else {
+    int parse_success = grpc_http_parser_eof(&req->parser);
+    if (parse_success && (req->parser.type != GRPC_HTTP_RESPONSE)) {
+      parse_success = 0;
+    }
+    finish(exec_ctx, req, parse_success);
+  }
+}
+
+static void on_written(grpc_exec_ctx *exec_ctx, internal_request *req) {
+  do_read(exec_ctx, req);
+}
+
+static void done_write(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  internal_request *req = arg;
+  if (success) {
+    on_written(exec_ctx, req);
+  } else {
+    next_address(exec_ctx, req);
+  }
+}
+
+static void start_write(grpc_exec_ctx *exec_ctx, internal_request *req) {
+  gpr_slice_ref(req->request_text);
+  gpr_slice_buffer_add(&req->outgoing, req->request_text);
+  grpc_endpoint_write(exec_ctx, req->ep, &req->outgoing, &req->done_write);
+}
+
+static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
+                              grpc_endpoint *ep) {
+  internal_request *req = arg;
+
+  if (!ep) {
+    next_address(exec_ctx, req);
+    return;
+  }
+
+  req->ep = ep;
+  start_write(exec_ctx, req);
+}
+
+static void on_connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  internal_request *req = arg;
+
+  if (!req->ep) {
+    next_address(exec_ctx, req);
+    return;
+  }
+  req->handshaker->handshake(
+      exec_ctx, req, req->ep,
+      req->ssl_host_override ? req->ssl_host_override : req->host,
+      on_handshake_done);
+}
+
+static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) {
+  grpc_resolved_address *addr;
+  if (req->next_address == req->addresses->naddrs) {
+    finish(exec_ctx, req, 0);
+    return;
+  }
+  addr = &req->addresses->addrs[req->next_address++];
+  grpc_closure_init(&req->connected, on_connected, req);
+  grpc_tcp_client_connect(
+      exec_ctx, &req->connected, &req->ep, req->context->pollset_set,
+      (struct sockaddr *)&addr->addr, addr->len, req->deadline);
+}
+
+static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
+                        grpc_resolved_addresses *addresses) {
+  internal_request *req = arg;
+  if (!addresses) {
+    finish(exec_ctx, req, 0);
+    return;
+  }
+  req->addresses = addresses;
+  req->next_address = 0;
+  next_address(exec_ctx, req);
+}
+
+static void internal_request_begin(
+    grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
+    grpc_pollset *pollset, const grpc_httpcli_request *request,
+    gpr_timespec deadline, grpc_httpcli_response_cb on_response,
+    void *user_data, const char *name, gpr_slice request_text) {
+  internal_request *req = gpr_malloc(sizeof(internal_request));
+  memset(req, 0, sizeof(*req));
+  req->request_text = request_text;
+  grpc_http_parser_init(&req->parser);
+  req->on_response = on_response;
+  req->user_data = user_data;
+  req->deadline = deadline;
+  req->handshaker =
+      request->handshaker ? request->handshaker : &grpc_httpcli_plaintext;
+  req->context = context;
+  req->pollset = pollset;
+  grpc_closure_init(&req->on_read, on_read, req);
+  grpc_closure_init(&req->done_write, done_write, req);
+  gpr_slice_buffer_init(&req->incoming);
+  gpr_slice_buffer_init(&req->outgoing);
+  grpc_iomgr_register_object(&req->iomgr_obj, name);
+  req->host = gpr_strdup(request->host);
+  req->ssl_host_override = gpr_strdup(request->ssl_host_override);
+
+  grpc_pollset_set_add_pollset(exec_ctx, req->context->pollset_set,
+                               req->pollset);
+  grpc_resolve_address(request->host, req->handshaker->default_port,
+                       on_resolved, req);
+}
+
+void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
+                      grpc_pollset *pollset,
+                      const grpc_httpcli_request *request,
+                      gpr_timespec deadline,
+                      grpc_httpcli_response_cb on_response, void *user_data) {
+  char *name;
+  if (g_get_override &&
+      g_get_override(exec_ctx, request, deadline, on_response, user_data)) {
+    return;
+  }
+  gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->http.path);
+  internal_request_begin(exec_ctx, context, pollset, request, deadline,
+                         on_response, user_data, name,
+                         grpc_httpcli_format_get_request(request));
+  gpr_free(name);
+}
+
+void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, 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) {
+  char *name;
+  if (g_post_override &&
+      g_post_override(exec_ctx, request, body_bytes, body_size, deadline,
+                      on_response, user_data)) {
+    return;
+  }
+  gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->http.path);
+  internal_request_begin(
+      exec_ctx, context, pollset, request, deadline, on_response, user_data,
+      name, grpc_httpcli_format_post_request(request, body_bytes, body_size));
+  gpr_free(name);
+}
+
+void grpc_httpcli_set_override(grpc_httpcli_get_override get,
+                               grpc_httpcli_post_override post) {
+  g_get_override = get;
+  g_post_override = post;
+}
diff --git a/src/core/lib/http/httpcli.h b/src/core/lib/http/httpcli.h
new file mode 100644
index 0000000..b8d54a8
--- /dev/null
+++ b/src/core/lib/http/httpcli.h
@@ -0,0 +1,144 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_HTTP_HTTPCLI_H
+#define GRPC_CORE_LIB_HTTP_HTTPCLI_H
+
+#include <stddef.h>
+
+#include <grpc/support/time.h>
+
+#include "src/core/lib/http/parser.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/pollset_set.h"
+
+/* User agent this library reports */
+#define GRPC_HTTPCLI_USER_AGENT "grpc-httpcli/0.0"
+
+/* 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;
+
+typedef struct {
+  const char *default_port;
+  void (*handshake)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint,
+                    const char *host,
+                    void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
+                                    grpc_endpoint *endpoint));
+} grpc_httpcli_handshaker;
+
+extern const grpc_httpcli_handshaker grpc_httpcli_plaintext;
+extern const grpc_httpcli_handshaker grpc_httpcli_ssl;
+
+/* A request */
+typedef struct grpc_httpcli_request {
+  /* The host name to connect to */
+  char *host;
+  /* The host to verify in the SSL handshake (or NULL) */
+  char *ssl_host_override;
+  /* The main part of the request
+     The following headers are supplied automatically and MUST NOT be set here:
+     Host, Connection, User-Agent */
+  grpc_http_request http;
+  /* handshaker to use ssl for the request */
+  const grpc_httpcli_handshaker *handshaker;
+} grpc_httpcli_request;
+
+/* Expose the parser response type as a httpcli response too */
+typedef struct grpc_http_response grpc_httpcli_response;
+
+/* Callback for grpc_httpcli_get and grpc_httpcli_post. */
+typedef void (*grpc_httpcli_response_cb)(grpc_exec_ctx *exec_ctx,
+                                         void *user_data,
+                                         const grpc_http_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)
+   '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(grpc_exec_ctx *exec_ctx, 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.
+   '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(grpc_exec_ctx *exec_ctx, 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);
+
+/* override functions return 1 if they handled the request, 0 otherwise */
+typedef int (*grpc_httpcli_get_override)(grpc_exec_ctx *exec_ctx,
+                                         const grpc_httpcli_request *request,
+                                         gpr_timespec deadline,
+                                         grpc_httpcli_response_cb on_response,
+                                         void *user_data);
+typedef int (*grpc_httpcli_post_override)(
+    grpc_exec_ctx *exec_ctx, 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);
+
+void grpc_httpcli_set_override(grpc_httpcli_get_override get,
+                               grpc_httpcli_post_override post);
+
+#endif /* GRPC_CORE_LIB_HTTP_HTTPCLI_H */
diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c
new file mode 100644
index 0000000..6f1630a
--- /dev/null
+++ b/src/core/lib/http/httpcli_security_connector.c
@@ -0,0 +1,188 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/http/httpcli.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include "src/core/lib/security/handshake.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/tsi/ssl_transport_security.h"
+
+typedef struct {
+  grpc_channel_security_connector base;
+  tsi_ssl_handshaker_factory *handshaker_factory;
+  char *secure_peer_name;
+} grpc_httpcli_ssl_channel_security_connector;
+
+static void httpcli_ssl_destroy(grpc_security_connector *sc) {
+  grpc_httpcli_ssl_channel_security_connector *c =
+      (grpc_httpcli_ssl_channel_security_connector *)sc;
+  if (c->handshaker_factory != NULL) {
+    tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
+  }
+  if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name);
+  gpr_free(sc);
+}
+
+static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_security_connector *sc,
+                                     grpc_endpoint *nonsecure_endpoint,
+                                     grpc_security_handshake_done_cb cb,
+                                     void *user_data) {
+  grpc_httpcli_ssl_channel_security_connector *c =
+      (grpc_httpcli_ssl_channel_security_connector *)sc;
+  tsi_result result = TSI_OK;
+  tsi_handshaker *handshaker;
+  if (c->handshaker_factory == NULL) {
+    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
+    return;
+  }
+  result = tsi_ssl_handshaker_factory_create_handshaker(
+      c->handshaker_factory, c->secure_peer_name, &handshaker);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
+            tsi_result_to_string(result));
+    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
+  } else {
+    grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
+                               nonsecure_endpoint, cb, user_data);
+  }
+}
+
+static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx,
+                                   grpc_security_connector *sc, tsi_peer peer,
+                                   grpc_security_peer_check_cb cb,
+                                   void *user_data) {
+  grpc_httpcli_ssl_channel_security_connector *c =
+      (grpc_httpcli_ssl_channel_security_connector *)sc;
+  grpc_security_status status = GRPC_SECURITY_OK;
+
+  /* Check the peer name. */
+  if (c->secure_peer_name != NULL &&
+      !tsi_ssl_peer_matches_name(&peer, c->secure_peer_name)) {
+    gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate",
+            c->secure_peer_name);
+    status = GRPC_SECURITY_ERROR;
+  }
+  cb(exec_ctx, user_data, status, NULL);
+  tsi_peer_destruct(&peer);
+}
+
+static grpc_security_connector_vtable httpcli_ssl_vtable = {
+    httpcli_ssl_destroy, httpcli_ssl_check_peer};
+
+static grpc_security_status httpcli_ssl_channel_security_connector_create(
+    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
+    const char *secure_peer_name, grpc_channel_security_connector **sc) {
+  tsi_result result = TSI_OK;
+  grpc_httpcli_ssl_channel_security_connector *c;
+
+  if (secure_peer_name != NULL && pem_root_certs == NULL) {
+    gpr_log(GPR_ERROR,
+            "Cannot assert a secure peer name without a trust root.");
+    return GRPC_SECURITY_ERROR;
+  }
+
+  c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_connector));
+  memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector));
+
+  gpr_ref_init(&c->base.base.refcount, 1);
+  c->base.base.vtable = &httpcli_ssl_vtable;
+  if (secure_peer_name != NULL) {
+    c->secure_peer_name = gpr_strdup(secure_peer_name);
+  }
+  result = tsi_create_ssl_client_handshaker_factory(
+      NULL, 0, NULL, 0, pem_root_certs, pem_root_certs_size, NULL, NULL, NULL,
+      0, &c->handshaker_factory);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
+            tsi_result_to_string(result));
+    httpcli_ssl_destroy(&c->base.base);
+    *sc = NULL;
+    return GRPC_SECURITY_ERROR;
+  }
+  c->base.do_handshake = httpcli_ssl_do_handshake;
+  *sc = &c->base;
+  return GRPC_SECURITY_OK;
+}
+
+/* handshaker */
+
+typedef struct {
+  void (*func)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint);
+  void *arg;
+} on_done_closure;
+
+static void on_secure_transport_setup_done(grpc_exec_ctx *exec_ctx, void *rp,
+                                           grpc_security_status status,
+                                           grpc_endpoint *secure_endpoint,
+                                           grpc_auth_context *auth_context) {
+  on_done_closure *c = rp;
+  if (status != GRPC_SECURITY_OK) {
+    gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status);
+    c->func(exec_ctx, c->arg, NULL);
+  } else {
+    c->func(exec_ctx, c->arg, secure_endpoint);
+  }
+  gpr_free(c);
+}
+
+static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
+                          grpc_endpoint *tcp, const char *host,
+                          void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
+                                          grpc_endpoint *endpoint)) {
+  grpc_channel_security_connector *sc = NULL;
+  const unsigned char *pem_root_certs = NULL;
+  on_done_closure *c = gpr_malloc(sizeof(*c));
+  size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
+  if (pem_root_certs == NULL || pem_root_certs_size == 0) {
+    gpr_log(GPR_ERROR, "Could not get default pem root certs.");
+    on_done(exec_ctx, arg, NULL);
+    gpr_free(c);
+    return;
+  }
+  c->func = on_done;
+  c->arg = arg;
+  GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
+                 pem_root_certs, pem_root_certs_size, host, &sc) ==
+             GRPC_SECURITY_OK);
+  grpc_channel_security_connector_do_handshake(
+      exec_ctx, sc, tcp, on_secure_transport_setup_done, c);
+  GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
+}
+
+const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake};
diff --git a/src/core/lib/http/parser.c b/src/core/lib/http/parser.c
new file mode 100644
index 0000000..2782ad7
--- /dev/null
+++ b/src/core/lib/http/parser.c
@@ -0,0 +1,317 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/http/parser.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+extern int grpc_http_trace;
+
+static char *buf2str(void *buffer, size_t length) {
+  char *out = gpr_malloc(length + 1);
+  memcpy(out, buffer, length);
+  out[length] = 0;
+  return out;
+}
+
+static int handle_response_line(grpc_http_parser *parser) {
+  uint8_t *beg = parser->cur_line;
+  uint8_t *cur = beg;
+  uint8_t *end = beg + parser->cur_line_length;
+
+  if (cur == end || *cur++ != 'H') goto error;
+  if (cur == end || *cur++ != 'T') goto error;
+  if (cur == end || *cur++ != 'T') goto error;
+  if (cur == end || *cur++ != 'P') goto error;
+  if (cur == end || *cur++ != '/') goto error;
+  if (cur == end || *cur++ != '1') goto error;
+  if (cur == end || *cur++ != '.') goto error;
+  if (cur == end || *cur < '0' || *cur++ > '1') goto error;
+  if (cur == end || *cur++ != ' ') goto error;
+  if (cur == end || *cur < '1' || *cur++ > '9') goto error;
+  if (cur == end || *cur < '0' || *cur++ > '9') goto error;
+  if (cur == end || *cur < '0' || *cur++ > '9') goto error;
+  parser->http.response.status =
+      (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
+  if (cur == end || *cur++ != ' ') goto error;
+
+  /* we don't really care about the status code message */
+
+  return 1;
+
+error:
+  if (grpc_http_trace) gpr_log(GPR_ERROR, "Failed parsing response line");
+  return 0;
+}
+
+static int handle_request_line(grpc_http_parser *parser) {
+  uint8_t *beg = parser->cur_line;
+  uint8_t *cur = beg;
+  uint8_t *end = beg + parser->cur_line_length;
+  uint8_t vers_major = 0;
+  uint8_t vers_minor = 0;
+
+  while (cur != end && *cur++ != ' ')
+    ;
+  if (cur == end) goto error;
+  parser->http.request.method = buf2str(beg, (size_t)(cur - beg - 1));
+
+  beg = cur;
+  while (cur != end && *cur++ != ' ')
+    ;
+  if (cur == end) goto error;
+  parser->http.request.path = buf2str(beg, (size_t)(cur - beg - 1));
+
+  if (cur == end || *cur++ != 'H') goto error;
+  if (cur == end || *cur++ != 'T') goto error;
+  if (cur == end || *cur++ != 'T') goto error;
+  if (cur == end || *cur++ != 'P') goto error;
+  if (cur == end || *cur++ != '/') goto error;
+  vers_major = (uint8_t)(*cur++ - '1' + 1);
+  ++cur;
+  if (cur == end) goto error;
+  vers_minor = (uint8_t)(*cur++ - '1' + 1);
+
+  if (vers_major == 1) {
+    if (vers_minor == 0) {
+      parser->http.request.version = GRPC_HTTP_HTTP10;
+    } else if (vers_minor == 1) {
+      parser->http.request.version = GRPC_HTTP_HTTP11;
+    } else {
+      goto error;
+    }
+  } else if (vers_major == 2) {
+    if (vers_minor == 0) {
+      parser->http.request.version = GRPC_HTTP_HTTP20;
+    } else {
+      goto error;
+    }
+  } else {
+    goto error;
+  }
+
+  return 1;
+
+error:
+  if (grpc_http_trace) gpr_log(GPR_ERROR, "Failed parsing request line");
+  return 0;
+}
+
+static int handle_first_line(grpc_http_parser *parser) {
+  if (parser->cur_line[0] == 'H') {
+    parser->type = GRPC_HTTP_RESPONSE;
+    return handle_response_line(parser);
+  } else {
+    parser->type = GRPC_HTTP_REQUEST;
+    return handle_request_line(parser);
+  }
+}
+
+static int add_header(grpc_http_parser *parser) {
+  uint8_t *beg = parser->cur_line;
+  uint8_t *cur = beg;
+  uint8_t *end = beg + parser->cur_line_length;
+  size_t *hdr_count = NULL;
+  grpc_http_header **hdrs = NULL;
+  grpc_http_header hdr = {NULL, NULL};
+
+  GPR_ASSERT(cur != end);
+
+  if (*cur == ' ' || *cur == '\t') {
+    if (grpc_http_trace)
+      gpr_log(GPR_ERROR, "Continued header lines not supported yet");
+    goto error;
+  }
+
+  while (cur != end && *cur != ':') {
+    cur++;
+  }
+  if (cur == end) {
+    if (grpc_http_trace) gpr_log(GPR_ERROR, "Didn't find ':' in header string");
+    goto error;
+  }
+  GPR_ASSERT(cur >= beg);
+  hdr.key = buf2str(beg, (size_t)(cur - beg));
+  cur++; /* skip : */
+
+  while (cur != end && (*cur == ' ' || *cur == '\t')) {
+    cur++;
+  }
+  GPR_ASSERT(end - cur >= 2);
+  hdr.value = buf2str(cur, (size_t)(end - cur) - 2);
+
+  if (parser->type == GRPC_HTTP_RESPONSE) {
+    hdr_count = &parser->http.response.hdr_count;
+    hdrs = &parser->http.response.hdrs;
+  } else if (parser->type == GRPC_HTTP_REQUEST) {
+    hdr_count = &parser->http.request.hdr_count;
+    hdrs = &parser->http.request.hdrs;
+  } else {
+    return 0;
+  }
+
+  if (*hdr_count == parser->hdr_capacity) {
+    parser->hdr_capacity =
+        GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2);
+    *hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs));
+  }
+  (*hdrs)[(*hdr_count)++] = hdr;
+  return 1;
+
+error:
+  gpr_free(hdr.key);
+  gpr_free(hdr.value);
+  return 0;
+}
+
+static int finish_line(grpc_http_parser *parser) {
+  switch (parser->state) {
+    case GRPC_HTTP_FIRST_LINE:
+      if (!handle_first_line(parser)) {
+        return 0;
+      }
+      parser->state = GRPC_HTTP_HEADERS;
+      break;
+    case GRPC_HTTP_HEADERS:
+      if (parser->cur_line_length == 2) {
+        parser->state = GRPC_HTTP_BODY;
+        break;
+      }
+      if (!add_header(parser)) {
+        return 0;
+      }
+      break;
+    case GRPC_HTTP_BODY:
+      GPR_UNREACHABLE_CODE(return 0);
+  }
+
+  parser->cur_line_length = 0;
+  return 1;
+}
+
+static int addbyte_body(grpc_http_parser *parser, uint8_t byte) {
+  size_t *body_length = NULL;
+  char **body = NULL;
+
+  if (parser->type == GRPC_HTTP_RESPONSE) {
+    body_length = &parser->http.response.body_length;
+    body = &parser->http.response.body;
+  } else if (parser->type == GRPC_HTTP_REQUEST) {
+    body_length = &parser->http.request.body_length;
+    body = &parser->http.request.body;
+  } else {
+    return 0;
+  }
+
+  if (*body_length == parser->body_capacity) {
+    parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2);
+    *body = gpr_realloc((void *)*body, parser->body_capacity);
+  }
+  (*body)[*body_length] = (char)byte;
+  (*body_length)++;
+
+  return 1;
+}
+
+static int addbyte(grpc_http_parser *parser, uint8_t byte) {
+  switch (parser->state) {
+    case GRPC_HTTP_FIRST_LINE:
+    case GRPC_HTTP_HEADERS:
+      if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) {
+        if (grpc_http_trace)
+          gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded",
+                  GRPC_HTTP_PARSER_MAX_HEADER_LENGTH);
+        return 0;
+      }
+      parser->cur_line[parser->cur_line_length] = byte;
+      parser->cur_line_length++;
+      if (parser->cur_line_length >= 2 &&
+          parser->cur_line[parser->cur_line_length - 2] == '\r' &&
+          parser->cur_line[parser->cur_line_length - 1] == '\n') {
+        return finish_line(parser);
+      } else {
+        return 1;
+      }
+      GPR_UNREACHABLE_CODE(return 0);
+    case GRPC_HTTP_BODY:
+      return addbyte_body(parser, byte);
+  }
+  GPR_UNREACHABLE_CODE(return 0);
+}
+
+void grpc_http_parser_init(grpc_http_parser *parser) {
+  memset(parser, 0, sizeof(*parser));
+  parser->state = GRPC_HTTP_FIRST_LINE;
+  parser->type = GRPC_HTTP_UNKNOWN;
+}
+
+void grpc_http_parser_destroy(grpc_http_parser *parser) {
+  size_t i;
+  if (parser->type == GRPC_HTTP_RESPONSE) {
+    gpr_free(parser->http.response.body);
+    for (i = 0; i < parser->http.response.hdr_count; i++) {
+      gpr_free(parser->http.response.hdrs[i].key);
+      gpr_free(parser->http.response.hdrs[i].value);
+    }
+    gpr_free(parser->http.response.hdrs);
+  } else if (parser->type == GRPC_HTTP_REQUEST) {
+    gpr_free(parser->http.request.body);
+    for (i = 0; i < parser->http.request.hdr_count; i++) {
+      gpr_free(parser->http.request.hdrs[i].key);
+      gpr_free(parser->http.request.hdrs[i].value);
+    }
+    gpr_free(parser->http.request.hdrs);
+    gpr_free(parser->http.request.method);
+    gpr_free(parser->http.request.path);
+  }
+}
+
+int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) {
+  size_t i;
+
+  for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) {
+    if (!addbyte(parser, GPR_SLICE_START_PTR(slice)[i])) {
+      return 0;
+    }
+  }
+
+  return 1;
+}
+
+int grpc_http_parser_eof(grpc_http_parser *parser) {
+  return parser->state == GRPC_HTTP_BODY;
+}
diff --git a/src/core/lib/http/parser.h b/src/core/lib/http/parser.h
new file mode 100644
index 0000000..6a72174
--- /dev/null
+++ b/src/core/lib/http/parser.h
@@ -0,0 +1,116 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_HTTP_PARSER_H
+#define GRPC_CORE_LIB_HTTP_PARSER_H
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+
+/* Maximum length of a header string of the form 'Key: Value\r\n' */
+#define GRPC_HTTP_PARSER_MAX_HEADER_LENGTH 4096
+
+/* A single header to be passed in a request */
+typedef struct grpc_http_header {
+  char *key;
+  char *value;
+} grpc_http_header;
+
+typedef enum {
+  GRPC_HTTP_FIRST_LINE,
+  GRPC_HTTP_HEADERS,
+  GRPC_HTTP_BODY
+} grpc_http_parser_state;
+
+typedef enum {
+  GRPC_HTTP_HTTP10,
+  GRPC_HTTP_HTTP11,
+  GRPC_HTTP_HTTP20,
+} grpc_http_version;
+
+typedef enum {
+  GRPC_HTTP_RESPONSE,
+  GRPC_HTTP_REQUEST,
+  GRPC_HTTP_UNKNOWN
+} grpc_http_type;
+
+/* A request */
+typedef struct grpc_http_request {
+  /* Method of the request (e.g. GET, POST) */
+  char *method;
+  /* The path of the resource to fetch */
+  char *path;
+  /* HTTP version to use */
+  grpc_http_version version;
+  /* Headers attached to the request */
+  size_t hdr_count;
+  grpc_http_header *hdrs;
+  /* Body: length and contents; contents are NOT null-terminated */
+  size_t body_length;
+  char *body;
+} grpc_http_request;
+
+/* A response */
+typedef struct grpc_http_response {
+  /* HTTP status code */
+  int status;
+  /* Headers: count and key/values */
+  size_t hdr_count;
+  grpc_http_header *hdrs;
+  /* Body: length and contents; contents are NOT null-terminated */
+  size_t body_length;
+  char *body;
+} grpc_http_response;
+
+typedef struct {
+  grpc_http_parser_state state;
+  grpc_http_type type;
+
+  union {
+    grpc_http_response response;
+    grpc_http_request request;
+  } http;
+  size_t body_capacity;
+  size_t hdr_capacity;
+
+  uint8_t cur_line[GRPC_HTTP_PARSER_MAX_HEADER_LENGTH];
+  size_t cur_line_length;
+} grpc_http_parser;
+
+void grpc_http_parser_init(grpc_http_parser *parser);
+void grpc_http_parser_destroy(grpc_http_parser *parser);
+
+int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice);
+int grpc_http_parser_eof(grpc_http_parser *parser);
+
+#endif /* GRPC_CORE_LIB_HTTP_PARSER_H */
diff --git a/src/core/lib/iomgr/closure.c b/src/core/lib/iomgr/closure.c
new file mode 100644
index 0000000..724ebc2
--- /dev/null
+++ b/src/core/lib/iomgr/closure.c
@@ -0,0 +1,98 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/closure.h"
+
+#include <grpc/support/alloc.h>
+
+void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
+                       void *cb_arg) {
+  closure->cb = cb;
+  closure->cb_arg = cb_arg;
+  closure->final_data = 0;
+}
+
+void grpc_closure_list_add(grpc_closure_list *closure_list,
+                           grpc_closure *closure, bool success) {
+  if (closure == NULL) return;
+  closure->final_data = (success != 0);
+  if (closure_list->head == NULL) {
+    closure_list->head = closure;
+  } else {
+    closure_list->tail->final_data |= (uintptr_t)closure;
+  }
+  closure_list->tail = closure;
+}
+
+bool grpc_closure_list_empty(grpc_closure_list closure_list) {
+  return closure_list.head == NULL;
+}
+
+void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst) {
+  if (src->head == NULL) {
+    return;
+  }
+  if (dst->head == NULL) {
+    *dst = *src;
+  } else {
+    dst->tail->final_data |= (uintptr_t)src->head;
+    dst->tail = src->tail;
+  }
+  src->head = src->tail = NULL;
+}
+
+typedef struct {
+  grpc_iomgr_cb_func cb;
+  void *cb_arg;
+  grpc_closure wrapper;
+} wrapped_closure;
+
+static void closure_wrapper(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  wrapped_closure *wc = arg;
+  grpc_iomgr_cb_func cb = wc->cb;
+  void *cb_arg = wc->cb_arg;
+  gpr_free(wc);
+  cb(exec_ctx, cb_arg, success);
+}
+
+grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) {
+  wrapped_closure *wc = gpr_malloc(sizeof(*wc));
+  wc->cb = cb;
+  wc->cb_arg = cb_arg;
+  grpc_closure_init(&wc->wrapper, closure_wrapper, wc);
+  return &wc->wrapper;
+}
+
+grpc_closure *grpc_closure_next(grpc_closure *closure) {
+  return (grpc_closure *)(closure->final_data & ~(uintptr_t)1);
+}
diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h
new file mode 100644
index 0000000..2597cf1
--- /dev/null
+++ b/src/core/lib/iomgr/closure.h
@@ -0,0 +1,98 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_CLOSURE_H
+#define GRPC_CORE_LIB_IOMGR_CLOSURE_H
+
+#include <grpc/support/port_platform.h>
+#include <stdbool.h>
+
+struct grpc_closure;
+typedef struct grpc_closure grpc_closure;
+
+/* forward declaration for exec_ctx.h */
+struct grpc_exec_ctx;
+typedef struct grpc_exec_ctx grpc_exec_ctx;
+
+typedef struct grpc_closure_list {
+  grpc_closure *head;
+  grpc_closure *tail;
+} grpc_closure_list;
+
+/** gRPC Callback definition.
+ *
+ * \param arg Arbitrary input.
+ * \param success An indication on the state of the iomgr. On false, cleanup
+ * actions should be taken (eg, shutdown). */
+typedef void (*grpc_iomgr_cb_func)(grpc_exec_ctx *exec_ctx, void *arg,
+                                   bool success);
+
+/** A closure over a grpc_iomgr_cb_func. */
+struct grpc_closure {
+  /** Bound callback. */
+  grpc_iomgr_cb_func cb;
+
+  /** Arguments to be passed to "cb". */
+  void *cb_arg;
+
+  /** Once enqueued, contains in the lower bit the success of the closure,
+      and in the upper bits the pointer to the next closure in the list.
+      Before enqueing for execution, this is usable for scratch data. */
+  uintptr_t final_data;
+};
+
+/** Initializes \a closure with \a cb and \a cb_arg. */
+void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
+                       void *cb_arg);
+
+/* Create a heap allocated closure: try to avoid except for very rare events */
+grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg);
+
+#define GRPC_CLOSURE_LIST_INIT \
+  { NULL, NULL }
+
+/** add \a closure to the end of \a list and set \a closure's success to \a
+ * success */
+void grpc_closure_list_add(grpc_closure_list *list, grpc_closure *closure,
+                           bool success);
+
+/** append all closures from \a src to \a dst and empty \a src. */
+void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst);
+
+/** return whether \a list is empty. */
+bool grpc_closure_list_empty(grpc_closure_list list);
+
+/** return the next pointer for a queued closure list */
+grpc_closure *grpc_closure_next(grpc_closure *closure);
+
+#endif /* GRPC_CORE_LIB_IOMGR_CLOSURE_H */
diff --git a/src/core/lib/iomgr/endpoint.c b/src/core/lib/iomgr/endpoint.c
new file mode 100644
index 0000000..576b5a6
--- /dev/null
+++ b/src/core/lib/iomgr/endpoint.c
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/endpoint.h"
+
+void grpc_endpoint_read(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep,
+                        gpr_slice_buffer* slices, grpc_closure* cb) {
+  ep->vtable->read(exec_ctx, ep, slices, cb);
+}
+
+void grpc_endpoint_write(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep,
+                         gpr_slice_buffer* slices, grpc_closure* cb) {
+  ep->vtable->write(exec_ctx, ep, slices, cb);
+}
+
+void grpc_endpoint_add_to_pollset(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep,
+                                  grpc_pollset* pollset) {
+  ep->vtable->add_to_pollset(exec_ctx, ep, pollset);
+}
+
+void grpc_endpoint_add_to_pollset_set(grpc_exec_ctx* exec_ctx,
+                                      grpc_endpoint* ep,
+                                      grpc_pollset_set* pollset_set) {
+  ep->vtable->add_to_pollset_set(exec_ctx, ep, pollset_set);
+}
+
+void grpc_endpoint_shutdown(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) {
+  ep->vtable->shutdown(exec_ctx, ep);
+}
+
+void grpc_endpoint_destroy(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) {
+  ep->vtable->destroy(exec_ctx, ep);
+}
+
+char* grpc_endpoint_get_peer(grpc_endpoint* ep) {
+  return ep->vtable->get_peer(ep);
+}
diff --git a/src/core/lib/iomgr/endpoint.h b/src/core/lib/iomgr/endpoint.h
new file mode 100644
index 0000000..918e705
--- /dev/null
+++ b/src/core/lib/iomgr/endpoint.h
@@ -0,0 +1,102 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_ENDPOINT_H
+#define GRPC_CORE_LIB_IOMGR_ENDPOINT_H
+
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/time.h>
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/pollset_set.h"
+
+/* An endpoint caps a streaming channel between two communicating processes.
+   Examples may be: a tcp socket, <stdin+stdout>, or some shared memory. */
+
+typedef struct grpc_endpoint grpc_endpoint;
+typedef struct grpc_endpoint_vtable grpc_endpoint_vtable;
+
+struct grpc_endpoint_vtable {
+  void (*read)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+               gpr_slice_buffer *slices, grpc_closure *cb);
+  void (*write)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                gpr_slice_buffer *slices, grpc_closure *cb);
+  void (*add_to_pollset)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                         grpc_pollset *pollset);
+  void (*add_to_pollset_set)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                             grpc_pollset_set *pollset);
+  void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
+  void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
+  char *(*get_peer)(grpc_endpoint *ep);
+};
+
+/* When data is available on the connection, calls the callback with slices.
+   Callback success indicates that the endpoint can accept more reads, failure
+   indicates the endpoint is closed.
+   Valid slices may be placed into \a slices even on callback success == 0. */
+void grpc_endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                        gpr_slice_buffer *slices, grpc_closure *cb);
+
+char *grpc_endpoint_get_peer(grpc_endpoint *ep);
+
+/* Write slices out to the socket.
+
+   If the connection is ready for more data after the end of the call, it
+   returns GRPC_ENDPOINT_DONE.
+   Otherwise it returns GRPC_ENDPOINT_PENDING and calls cb when the
+   connection is ready for more data.
+   \a slices may be mutated at will by the endpoint until cb is called.
+   No guarantee is made to the content of slices after a write EXCEPT that
+   it is a valid slice buffer.
+   */
+void grpc_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                         gpr_slice_buffer *slices, grpc_closure *cb);
+
+/* Causes any pending read/write callbacks to run immediately with
+   success==0 */
+void grpc_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
+void grpc_endpoint_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
+
+/* Add an endpoint to a pollset, so that when the pollset is polled, events from
+   this endpoint are considered */
+void grpc_endpoint_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                                  grpc_pollset *pollset);
+void grpc_endpoint_add_to_pollset_set(grpc_exec_ctx *exec_ctx,
+                                      grpc_endpoint *ep,
+                                      grpc_pollset_set *pollset_set);
+
+struct grpc_endpoint {
+  const grpc_endpoint_vtable *vtable;
+};
+
+#endif /* GRPC_CORE_LIB_IOMGR_ENDPOINT_H */
diff --git a/src/core/lib/iomgr/endpoint_pair.h b/src/core/lib/iomgr/endpoint_pair.h
new file mode 100644
index 0000000..bef8bb3
--- /dev/null
+++ b/src/core/lib/iomgr/endpoint_pair.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H
+#define GRPC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H
+
+#include "src/core/lib/iomgr/endpoint.h"
+
+typedef struct {
+  grpc_endpoint *client;
+  grpc_endpoint *server;
+} grpc_endpoint_pair;
+
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
+                                                   size_t read_slice_size);
+
+#endif /* GRPC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H */
diff --git a/src/core/lib/iomgr/endpoint_pair_posix.c b/src/core/lib/iomgr/endpoint_pair_posix.c
new file mode 100644
index 0000000..e0ce47c
--- /dev/null
+++ b/src/core/lib/iomgr/endpoint_pair_posix.c
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+#include "src/core/lib/iomgr/unix_sockets_posix.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include "src/core/lib/iomgr/tcp_posix.h"
+#include "src/core/lib/support/string.h"
+
+static void create_sockets(int sv[2]) {
+  int flags;
+  grpc_create_socketpair_if_unix(sv);
+  flags = fcntl(sv[0], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0);
+  flags = fcntl(sv[1], F_GETFL, 0);
+  GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
+  GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[0]));
+  GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1]));
+}
+
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
+                                                   size_t read_slice_size) {
+  int sv[2];
+  grpc_endpoint_pair p;
+  char *final_name;
+  create_sockets(sv);
+
+  gpr_asprintf(&final_name, "%s:client", name);
+  p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), read_slice_size,
+                             "socketpair-server");
+  gpr_free(final_name);
+  gpr_asprintf(&final_name, "%s:server", name);
+  p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), read_slice_size,
+                             "socketpair-client");
+  gpr_free(final_name);
+  return p;
+}
+
+#endif
diff --git a/src/core/lib/iomgr/endpoint_pair_windows.c b/src/core/lib/iomgr/endpoint_pair_windows.c
new file mode 100644
index 0000000..cba18db
--- /dev/null
+++ b/src/core/lib/iomgr/endpoint_pair_windows.c
@@ -0,0 +1,97 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINSOCK_SOCKET
+#include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include "src/core/lib/iomgr/socket_windows.h"
+#include "src/core/lib/iomgr/tcp_windows.h"
+
+static void create_sockets(SOCKET sv[2]) {
+  SOCKET svr_sock = INVALID_SOCKET;
+  SOCKET lst_sock = INVALID_SOCKET;
+  SOCKET cli_sock = INVALID_SOCKET;
+  SOCKADDR_IN addr;
+  int addr_len = sizeof(addr);
+
+  lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
+                       WSA_FLAG_OVERLAPPED);
+  GPR_ASSERT(lst_sock != INVALID_SOCKET);
+
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  addr.sin_family = AF_INET;
+  GPR_ASSERT(bind(lst_sock, (struct sockaddr *)&addr, sizeof(addr)) !=
+             SOCKET_ERROR);
+  GPR_ASSERT(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR);
+  GPR_ASSERT(getsockname(lst_sock, (struct sockaddr *)&addr, &addr_len) !=
+             SOCKET_ERROR);
+
+  cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
+                       WSA_FLAG_OVERLAPPED);
+  GPR_ASSERT(cli_sock != INVALID_SOCKET);
+
+  GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr *)&addr, addr_len, NULL,
+                        NULL, NULL, NULL) == 0);
+  svr_sock = accept(lst_sock, (struct sockaddr *)&addr, &addr_len);
+  GPR_ASSERT(svr_sock != INVALID_SOCKET);
+
+  closesocket(lst_sock);
+  grpc_tcp_prepare_socket(cli_sock);
+  grpc_tcp_prepare_socket(svr_sock);
+
+  sv[1] = cli_sock;
+  sv[0] = svr_sock;
+}
+
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
+                                                   size_t read_slice_size) {
+  SOCKET sv[2];
+  grpc_endpoint_pair p;
+  create_sockets(sv);
+  p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"),
+                             "endpoint:server");
+  p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"),
+                             "endpoint:client");
+  return p;
+}
+
+#endif
diff --git a/src/core/lib/iomgr/exec_ctx.c b/src/core/lib/iomgr/exec_ctx.c
new file mode 100644
index 0000000..1ed6da6
--- /dev/null
+++ b/src/core/lib/iomgr/exec_ctx.c
@@ -0,0 +1,151 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+
+#include "src/core/lib/profiling/timers.h"
+
+#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER
+bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) {
+  bool did_something = 0;
+  GPR_TIMER_BEGIN("grpc_exec_ctx_flush", 0);
+  while (!grpc_closure_list_empty(exec_ctx->closure_list)) {
+    grpc_closure *c = exec_ctx->closure_list.head;
+    exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL;
+    while (c != NULL) {
+      bool success = (bool)(c->final_data & 1);
+      grpc_closure *next = (grpc_closure *)(c->final_data & ~(uintptr_t)1);
+      did_something = true;
+      GPR_TIMER_BEGIN("grpc_exec_ctx_flush.cb", 0);
+      c->cb(exec_ctx, c->cb_arg, success);
+      GPR_TIMER_END("grpc_exec_ctx_flush.cb", 0);
+      c = next;
+    }
+  }
+  GPR_TIMER_END("grpc_exec_ctx_flush", 0);
+  return did_something;
+}
+
+void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {
+  grpc_exec_ctx_flush(exec_ctx);
+}
+
+void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+                           bool success,
+                           grpc_workqueue *offload_target_or_null) {
+  GPR_ASSERT(offload_target_or_null == NULL);
+  grpc_closure_list_add(&exec_ctx->closure_list, closure, success);
+}
+
+void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
+                                grpc_closure_list *list,
+                                grpc_workqueue *offload_target_or_null) {
+  GPR_ASSERT(offload_target_or_null == NULL);
+  grpc_closure_list_move(list, &exec_ctx->closure_list);
+}
+
+void grpc_exec_ctx_global_init(void) {}
+void grpc_exec_ctx_global_shutdown(void) {}
+#else
+static gpr_mu g_mu;
+static gpr_cv g_cv;
+static int g_threads = 0;
+
+static void run_closure(void *arg) {
+  grpc_closure *closure = arg;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  closure->cb(&exec_ctx, closure->cb_arg, (closure->final_data & 1) != 0);
+  grpc_exec_ctx_finish(&exec_ctx);
+  gpr_mu_lock(&g_mu);
+  if (--g_threads == 0) {
+    gpr_cv_signal(&g_cv);
+  }
+  gpr_mu_unlock(&g_mu);
+}
+
+static void start_closure(grpc_closure *closure) {
+  gpr_thd_id id;
+  gpr_mu_lock(&g_mu);
+  g_threads++;
+  gpr_mu_unlock(&g_mu);
+  gpr_thd_new(&id, run_closure, closure, NULL);
+}
+
+bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) { return false; }
+
+void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {}
+
+void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+                           bool success,
+                           grpc_workqueue *offload_target_or_null) {
+  GPR_ASSERT(offload_target_or_null == NULL);
+  if (closure == NULL) return;
+  closure->final_data = success;
+  start_closure(closure);
+}
+
+void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
+                                grpc_closure_list *list,
+                                grpc_workqueue *offload_target_or_null) {
+  GPR_ASSERT(offload_target_or_null == NULL);
+  if (list == NULL) return;
+  grpc_closure *p = list->head;
+  while (p) {
+    grpc_closure *start = p;
+    p = grpc_closure_next(start);
+    start_closure(start);
+  }
+  grpc_closure_list r = GRPC_CLOSURE_LIST_INIT;
+  *list = r;
+}
+
+void grpc_exec_ctx_global_init(void) {
+  gpr_mu_init(&g_mu);
+  gpr_cv_init(&g_cv);
+}
+
+void grpc_exec_ctx_global_shutdown(void) {
+  gpr_mu_lock(&g_mu);
+  while (g_threads != 0) {
+    gpr_cv_wait(&g_cv, &g_mu, gpr_inf_future(GPR_CLOCK_REALTIME));
+  }
+  gpr_mu_unlock(&g_mu);
+
+  gpr_mu_destroy(&g_mu);
+  gpr_cv_destroy(&g_cv);
+}
+#endif
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h
new file mode 100644
index 0000000..e62ea2d
--- /dev/null
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -0,0 +1,98 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_EXEC_CTX_H
+#define GRPC_CORE_LIB_IOMGR_EXEC_CTX_H
+
+#include "src/core/lib/iomgr/closure.h"
+
+/* #define GRPC_EXECUTION_CONTEXT_SANITIZER 1 */
+
+/** A workqueue represents a list of work to be executed asynchronously.
+    Forward declared here to avoid a circular dependency with workqueue.h. */
+struct grpc_workqueue;
+typedef struct grpc_workqueue grpc_workqueue;
+
+#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER
+/** Execution context.
+ *  A bag of data that collects information along a callstack.
+ *  Generally created at public API entry points, and passed down as
+ *  pointer to child functions that manipulate it.
+ *
+ *  Specific responsibilities (this may grow in the future):
+ *  - track a list of work that needs to be delayed until the top of the
+ *    call stack (this provides a convenient mechanism to run callbacks
+ *    without worrying about locking issues)
+ *
+ *  CONVENTIONS:
+ *  Instance of this must ALWAYS be constructed on the stack, never
+ *  heap allocated. Instances and pointers to them must always be called
+ *  exec_ctx. Instances are always passed as the first argument
+ *  to a function that takes it, and always as a pointer (grpc_exec_ctx
+ *  is never copied).
+ */
+struct grpc_exec_ctx {
+  grpc_closure_list closure_list;
+};
+
+#define GRPC_EXEC_CTX_INIT \
+  { GRPC_CLOSURE_LIST_INIT }
+#else
+struct grpc_exec_ctx {
+  int unused;
+};
+#define GRPC_EXEC_CTX_INIT \
+  { 0 }
+#endif
+
+/** Flush any work that has been enqueued onto this grpc_exec_ctx.
+ *  Caller must guarantee that no interfering locks are held.
+ *  Returns true if work was performed, false otherwise. */
+bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx);
+/** Finish any pending work for a grpc_exec_ctx. Must be called before
+ *  the instance is destroyed, or work may be lost. */
+void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx);
+/** Add a closure to be executed at the next flush/finish point */
+void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+                           bool success,
+                           grpc_workqueue *offload_target_or_null);
+/** Add a list of closures to be executed at the next flush/finish point.
+ *  Leaves \a list empty. */
+void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
+                                grpc_closure_list *list,
+                                grpc_workqueue *offload_target_or_null);
+
+void grpc_exec_ctx_global_init(void);
+void grpc_exec_ctx_global_shutdown(void);
+
+#endif /* GRPC_CORE_LIB_IOMGR_EXEC_CTX_H */
diff --git a/src/core/lib/iomgr/executor.c b/src/core/lib/iomgr/executor.c
new file mode 100644
index 0000000..42a9db3
--- /dev/null
+++ b/src/core/lib/iomgr/executor.c
@@ -0,0 +1,143 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/executor.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+typedef struct grpc_executor_data {
+  int busy;          /**< is the thread currently running? */
+  int shutting_down; /**< has \a grpc_shutdown() been invoked? */
+  int pending_join;  /**< has the thread finished but not been joined? */
+  grpc_closure_list closures; /**< collection of pending work */
+  gpr_thd_id tid; /**< thread id of the thread, only valid if \a busy or \a
+                     pending_join are true */
+  gpr_thd_options options;
+  gpr_mu mu;
+} grpc_executor;
+
+static grpc_executor g_executor;
+
+void grpc_executor_init() {
+  memset(&g_executor, 0, sizeof(grpc_executor));
+  gpr_mu_init(&g_executor.mu);
+  g_executor.options = gpr_thd_options_default();
+  gpr_thd_options_set_joinable(&g_executor.options);
+}
+
+/* thread body */
+static void closure_exec_thread_func(void *ignored) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  while (1) {
+    gpr_mu_lock(&g_executor.mu);
+    if (g_executor.shutting_down != 0) {
+      gpr_mu_unlock(&g_executor.mu);
+      break;
+    }
+    if (grpc_closure_list_empty(g_executor.closures)) {
+      /* no more work, time to die */
+      GPR_ASSERT(g_executor.busy == 1);
+      g_executor.busy = 0;
+      gpr_mu_unlock(&g_executor.mu);
+      break;
+    } else {
+      grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL);
+    }
+    gpr_mu_unlock(&g_executor.mu);
+    grpc_exec_ctx_flush(&exec_ctx);
+  }
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+/* Spawn the thread if new work has arrived a no thread is up */
+static void maybe_spawn_locked() {
+  if (grpc_closure_list_empty(g_executor.closures) == 1) {
+    return;
+  }
+  if (g_executor.shutting_down == 1) {
+    return;
+  }
+
+  if (g_executor.busy != 0) {
+    /* Thread still working. New work will be picked up by already running
+     * thread. Not spawning anything. */
+    return;
+  } else if (g_executor.pending_join != 0) {
+    /* Pickup the remains of the previous incarnations of the thread. */
+    gpr_thd_join(g_executor.tid);
+    g_executor.pending_join = 0;
+  }
+
+  /* All previous instances of the thread should have been joined at this point.
+   * Spawn time! */
+  g_executor.busy = 1;
+  gpr_thd_new(&g_executor.tid, closure_exec_thread_func, NULL,
+              &g_executor.options);
+  g_executor.pending_join = 1;
+}
+
+void grpc_executor_enqueue(grpc_closure *closure, bool success) {
+  gpr_mu_lock(&g_executor.mu);
+  if (g_executor.shutting_down == 0) {
+    grpc_closure_list_add(&g_executor.closures, closure, success);
+    maybe_spawn_locked();
+  }
+  gpr_mu_unlock(&g_executor.mu);
+}
+
+void grpc_executor_shutdown() {
+  int pending_join;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  gpr_mu_lock(&g_executor.mu);
+  pending_join = g_executor.pending_join;
+  g_executor.shutting_down = 1;
+  gpr_mu_unlock(&g_executor.mu);
+  /* we can release the lock at this point despite the access to the closure
+   * list below because we aren't accepting new work */
+
+  /* Execute pending callbacks, some may be performing cleanups */
+  grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL);
+  grpc_exec_ctx_finish(&exec_ctx);
+  GPR_ASSERT(grpc_closure_list_empty(g_executor.closures));
+  if (pending_join) {
+    gpr_thd_join(g_executor.tid);
+  }
+  gpr_mu_destroy(&g_executor.mu);
+}
diff --git a/src/core/lib/iomgr/executor.h b/src/core/lib/iomgr/executor.h
new file mode 100644
index 0000000..f187141
--- /dev/null
+++ b/src/core/lib/iomgr/executor.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_EXECUTOR_H
+#define GRPC_CORE_LIB_IOMGR_EXECUTOR_H
+
+#include "src/core/lib/iomgr/closure.h"
+
+/** Initialize the global executor.
+ *
+ * This mechanism is meant to outsource work (grpc_closure instances) to a
+ * thread, for those cases where blocking isn't an option but there isn't a
+ * non-blocking solution available. */
+void grpc_executor_init();
+
+/** Enqueue \a closure for its eventual execution of \a f(arg) on a separate
+ * thread */
+void grpc_executor_enqueue(grpc_closure *closure, bool success);
+
+/** Shutdown the executor, running all pending work as part of the call */
+void grpc_executor_shutdown();
+
+#endif /* GRPC_CORE_LIB_IOMGR_EXECUTOR_H */
diff --git a/src/core/lib/iomgr/fd_posix.c b/src/core/lib/iomgr/fd_posix.c
new file mode 100644
index 0000000..72c924b
--- /dev/null
+++ b/src/core/lib/iomgr/fd_posix.c
@@ -0,0 +1,454 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/lib/iomgr/fd_posix.h"
+
+#include <assert.h>
+#include <sys/socket.h>
+#include <unistd.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/lib/iomgr/pollset_posix.h"
+
+#define CLOSURE_NOT_READY ((grpc_closure *)0)
+#define CLOSURE_READY ((grpc_closure *)1)
+
+/* We need to keep a freelist not because of any concerns of malloc performance
+ * but instead so that implementations with multiple threads in (for example)
+ * epoll_wait deal with the race between pollset removal and incoming poll
+ * notifications.
+ *
+ * The problem is that the poller ultimately holds a reference to this
+ * object, so it is very difficult to know when is safe to free it, at least
+ * without some expensive synchronization.
+ *
+ * If we keep the object freelisted, in the worst case losing this race just
+ * becomes a spurious read notification on a reused fd.
+ */
+/* TODO(klempner): We could use some form of polling generation count to know
+ * when these are safe to free. */
+/* TODO(klempner): Consider disabling freelisting if we don't have multiple
+ * threads in poll on the same fd */
+/* TODO(klempner): Batch these allocations to reduce fragmentation */
+static grpc_fd *fd_freelist = NULL;
+static gpr_mu fd_freelist_mu;
+
+static void freelist_fd(grpc_fd *fd) {
+  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);
+}
+
+static grpc_fd *alloc_fd(int fd) {
+  grpc_fd *r = NULL;
+  gpr_mu_lock(&fd_freelist_mu);
+  if (fd_freelist != NULL) {
+    r = fd_freelist;
+    fd_freelist = fd_freelist->freelist_next;
+  }
+  gpr_mu_unlock(&fd_freelist_mu);
+  if (r == NULL) {
+    r = gpr_malloc(sizeof(grpc_fd));
+    gpr_mu_init(&r->mu);
+  }
+
+  gpr_mu_lock(&r->mu);
+  r->shutdown = 0;
+  r->read_closure = CLOSURE_NOT_READY;
+  r->write_closure = CLOSURE_NOT_READY;
+  r->fd = fd;
+  r->inactive_watcher_root.next = r->inactive_watcher_root.prev =
+      &r->inactive_watcher_root;
+  r->freelist_next = NULL;
+  r->read_watcher = r->write_watcher = NULL;
+  r->on_done_closure = NULL;
+  r->closed = 0;
+  r->released = 0;
+  gpr_atm_rel_store(&r->refst, 1);
+  gpr_mu_unlock(&r->mu);
+
+  return r;
+}
+
+static void destroy(grpc_fd *fd) {
+  gpr_mu_destroy(&fd->mu);
+  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;
+#endif
+  old = gpr_atm_full_fetch_add(&fd->refst, -n);
+  if (old == n) {
+    freelist_fd(fd);
+  } else {
+    GPR_ASSERT(old > n);
+  }
+}
+
+void grpc_fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); }
+
+void grpc_fd_global_shutdown(void) {
+  gpr_mu_lock(&fd_freelist_mu);
+  gpr_mu_unlock(&fd_freelist_mu);
+  while (fd_freelist != NULL) {
+    grpc_fd *fd = fd_freelist;
+    fd_freelist = fd_freelist->freelist_next;
+    destroy(fd);
+  }
+  gpr_mu_destroy(&fd_freelist_mu);
+}
+
+grpc_fd *grpc_fd_create(int fd, const char *name) {
+  grpc_fd *r = alloc_fd(fd);
+  char *name2;
+  gpr_asprintf(&name2, "%s fd=%d", name, fd);
+  grpc_iomgr_register_object(&r->iomgr_object, name2);
+  gpr_free(name2);
+#ifdef GRPC_FD_REF_COUNT_DEBUG
+  gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, r, name);
+#endif
+  return r;
+}
+
+int grpc_fd_is_orphaned(grpc_fd *fd) {
+  return (gpr_atm_acq_load(&fd->refst) & 1) == 0;
+}
+
+static void pollset_kick_locked(grpc_fd_watcher *watcher) {
+  gpr_mu_lock(&watcher->pollset->mu);
+  GPR_ASSERT(watcher->worker);
+  grpc_pollset_kick_ext(watcher->pollset, watcher->worker,
+                        GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
+  gpr_mu_unlock(&watcher->pollset->mu);
+}
+
+static void maybe_wake_one_watcher_locked(grpc_fd *fd) {
+  if (fd->inactive_watcher_root.next != &fd->inactive_watcher_root) {
+    pollset_kick_locked(fd->inactive_watcher_root.next);
+  } else if (fd->read_watcher) {
+    pollset_kick_locked(fd->read_watcher);
+  } else if (fd->write_watcher) {
+    pollset_kick_locked(fd->write_watcher);
+  }
+}
+
+static void wake_all_watchers_locked(grpc_fd *fd) {
+  grpc_fd_watcher *watcher;
+  for (watcher = fd->inactive_watcher_root.next;
+       watcher != &fd->inactive_watcher_root; watcher = watcher->next) {
+    pollset_kick_locked(watcher);
+  }
+  if (fd->read_watcher) {
+    pollset_kick_locked(fd->read_watcher);
+  }
+  if (fd->write_watcher && fd->write_watcher != fd->read_watcher) {
+    pollset_kick_locked(fd->write_watcher);
+  }
+}
+
+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;
+}
+
+static void close_fd_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
+  fd->closed = 1;
+  if (!fd->released) {
+    close(fd->fd);
+  } else {
+    grpc_remove_fd_from_all_epoll_sets(fd->fd);
+  }
+  grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, true, NULL);
+}
+
+int grpc_fd_wrapped_fd(grpc_fd *fd) {
+  if (fd->released || fd->closed) {
+    return -1;
+  } else {
+    return fd->fd;
+  }
+}
+
+void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
+                    int *release_fd, const char *reason) {
+  fd->on_done_closure = on_done;
+  fd->released = release_fd != NULL;
+  if (!fd->released) {
+    shutdown(fd->fd, SHUT_RDWR);
+  } else {
+    *release_fd = fd->fd;
+  }
+  gpr_mu_lock(&fd->mu);
+  REF_BY(fd, 1, reason); /* remove active status, but keep referenced */
+  if (!has_watchers(fd)) {
+    close_fd_locked(exec_ctx, fd);
+  } else {
+    wake_all_watchers_locked(fd);
+  }
+  gpr_mu_unlock(&fd->mu);
+  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 notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
+                             grpc_closure **st, grpc_closure *closure) {
+  if (*st == CLOSURE_NOT_READY) {
+    /* not ready ==> switch to a waiting state by setting the closure */
+    *st = closure;
+  } else if (*st == CLOSURE_READY) {
+    /* already ready ==> queue the closure to run immediately */
+    *st = CLOSURE_NOT_READY;
+    grpc_exec_ctx_enqueue(exec_ctx, closure, !fd->shutdown, NULL);
+    maybe_wake_one_watcher_locked(fd);
+  } else {
+    /* upcallptr was set to a different closure.  This is an error! */
+    gpr_log(GPR_ERROR,
+            "User called a notify_on function with a previous callback still "
+            "pending");
+    abort();
+  }
+}
+
+/* returns 1 if state becomes not ready */
+static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
+                            grpc_closure **st) {
+  if (*st == CLOSURE_READY) {
+    /* duplicate ready ==> ignore */
+    return 0;
+  } else if (*st == CLOSURE_NOT_READY) {
+    /* not ready, and not waiting ==> flag ready */
+    *st = CLOSURE_READY;
+    return 0;
+  } else {
+    /* waiting ==> queue closure */
+    grpc_exec_ctx_enqueue(exec_ctx, *st, !fd->shutdown, NULL);
+    *st = CLOSURE_NOT_READY;
+    return 1;
+  }
+}
+
+static void set_ready(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure **st) {
+  /* only one set_ready can be active at once (but there may be a racing
+     notify_on) */
+  gpr_mu_lock(&fd->mu);
+  set_ready_locked(exec_ctx, fd, st);
+  gpr_mu_unlock(&fd->mu);
+}
+
+void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
+  gpr_mu_lock(&fd->mu);
+  GPR_ASSERT(!fd->shutdown);
+  fd->shutdown = 1;
+  set_ready_locked(exec_ctx, fd, &fd->read_closure);
+  set_ready_locked(exec_ctx, fd, &fd->write_closure);
+  gpr_mu_unlock(&fd->mu);
+}
+
+void grpc_fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
+                            grpc_closure *closure) {
+  gpr_mu_lock(&fd->mu);
+  notify_on_locked(exec_ctx, fd, &fd->read_closure, closure);
+  gpr_mu_unlock(&fd->mu);
+}
+
+void grpc_fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
+                             grpc_closure *closure) {
+  gpr_mu_lock(&fd->mu);
+  notify_on_locked(exec_ctx, fd, &fd->write_closure, closure);
+  gpr_mu_unlock(&fd->mu);
+}
+
+uint32_t grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
+                            grpc_pollset_worker *worker, uint32_t read_mask,
+                            uint32_t write_mask, grpc_fd_watcher *watcher) {
+  uint32_t mask = 0;
+  grpc_closure *cur;
+  int requested;
+  /* keep track of pollers that have requested our events, in case they change
+   */
+  GRPC_FD_REF(fd, "poll");
+
+  gpr_mu_lock(&fd->mu);
+
+  /* if we are shutdown, then don't add to the watcher set */
+  if (fd->shutdown) {
+    watcher->fd = NULL;
+    watcher->pollset = NULL;
+    watcher->worker = NULL;
+    gpr_mu_unlock(&fd->mu);
+    GRPC_FD_UNREF(fd, "poll");
+    return 0;
+  }
+
+  /* if there is nobody polling for read, but we need to, then start doing so */
+  cur = fd->read_closure;
+  requested = cur != CLOSURE_READY;
+  if (read_mask && fd->read_watcher == NULL && requested) {
+    fd->read_watcher = watcher;
+    mask |= read_mask;
+  }
+  /* if there is nobody polling for write, but we need to, then start doing so
+   */
+  cur = fd->write_closure;
+  requested = cur != CLOSURE_READY;
+  if (write_mask && fd->write_watcher == NULL && requested) {
+    fd->write_watcher = watcher;
+    mask |= write_mask;
+  }
+  /* if not polling, remember this watcher in case we need someone to later */
+  if (mask == 0 && worker != NULL) {
+    watcher->next = &fd->inactive_watcher_root;
+    watcher->prev = watcher->next->prev;
+    watcher->next->prev = watcher->prev->next = watcher;
+  }
+  watcher->pollset = pollset;
+  watcher->worker = worker;
+  watcher->fd = fd;
+  gpr_mu_unlock(&fd->mu);
+
+  return mask;
+}
+
+void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher,
+                      int got_read, int got_write) {
+  int was_polling = 0;
+  int kick = 0;
+  grpc_fd *fd = watcher->fd;
+
+  if (fd == NULL) {
+    return;
+  }
+
+  gpr_mu_lock(&fd->mu);
+
+  if (watcher == fd->read_watcher) {
+    /* remove read watcher, kick if we still need a read */
+    was_polling = 1;
+    if (!got_read) {
+      kick = 1;
+    }
+    fd->read_watcher = NULL;
+  }
+  if (watcher == fd->write_watcher) {
+    /* remove write watcher, kick if we still need a write */
+    was_polling = 1;
+    if (!got_write) {
+      kick = 1;
+    }
+    fd->write_watcher = NULL;
+  }
+  if (!was_polling && watcher->worker != NULL) {
+    /* remove from inactive list */
+    watcher->next->prev = watcher->prev;
+    watcher->prev->next = watcher->next;
+  }
+  if (got_read) {
+    if (set_ready_locked(exec_ctx, fd, &fd->read_closure)) {
+      kick = 1;
+    }
+  }
+  if (got_write) {
+    if (set_ready_locked(exec_ctx, fd, &fd->write_closure)) {
+      kick = 1;
+    }
+  }
+  if (kick) {
+    maybe_wake_one_watcher_locked(fd);
+  }
+  if (grpc_fd_is_orphaned(fd) && !has_watchers(fd) && !fd->closed) {
+    close_fd_locked(exec_ctx, fd);
+  }
+  gpr_mu_unlock(&fd->mu);
+
+  GRPC_FD_UNREF(fd, "poll");
+}
+
+void grpc_fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
+  set_ready(exec_ctx, fd, &fd->read_closure);
+}
+
+void grpc_fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
+  set_ready(exec_ctx, fd, &fd->write_closure);
+}
+
+#endif
diff --git a/src/core/lib/iomgr/fd_posix.h b/src/core/lib/iomgr/fd_posix.h
new file mode 100644
index 0000000..69d09ef
--- /dev/null
+++ b/src/core/lib/iomgr/fd_posix.h
@@ -0,0 +1,192 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_FD_POSIX_H
+#define GRPC_CORE_LIB_IOMGR_FD_POSIX_H
+
+#include <grpc/support/atm.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/pollset.h"
+
+typedef struct grpc_fd grpc_fd;
+
+typedef struct grpc_fd_watcher {
+  struct grpc_fd_watcher *next;
+  struct grpc_fd_watcher *prev;
+  grpc_pollset *pollset;
+  grpc_pollset_worker *worker;
+  grpc_fd *fd;
+} grpc_fd_watcher;
+
+struct grpc_fd {
+  int fd;
+  /* refst format:
+     bit0:   1=active/0=orphaned
+     bit1-n: refcount
+     meaning that mostly we ref by two to avoid altering the orphaned bit,
+     and just unref by 1 when we're ready to flag the object as orphaned */
+  gpr_atm refst;
+
+  gpr_mu mu;
+  int shutdown;
+  int closed;
+  int released;
+
+  /* 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.
+
+     If a watcher is asked to poll for reads or writes, the read_watcher
+     or write_watcher fields are set respectively. A watcher may be asked
+     to poll for both, in which case both fields will be set.
+
+     read_watcher and write_watcher may be NULL if no watcher has been
+     asked to poll for reads or writes.
+
+     If an fd_watcher is not asked to poll for reads or writes, it's added
+     to a linked list of inactive watchers, rooted at inactive_watcher_root.
+     If at a later time there becomes need of a poller to poll, one of
+     the inactive pollers may be kicked out of their poll loops to take
+     that responsibility. */
+  grpc_fd_watcher inactive_watcher_root;
+  grpc_fd_watcher *read_watcher;
+  grpc_fd_watcher *write_watcher;
+
+  grpc_closure *read_closure;
+  grpc_closure *write_closure;
+
+  struct grpc_fd *freelist_next;
+
+  grpc_closure *on_done_closure;
+
+  grpc_iomgr_object iomgr_object;
+};
+
+/* Create a wrapped file descriptor.
+   Requires fd is a non-blocking file descriptor.
+   This takes ownership of closing fd. */
+grpc_fd *grpc_fd_create(int fd, const char *name);
+
+/* Return the wrapped fd, or -1 if it has been released or closed. */
+int grpc_fd_wrapped_fd(grpc_fd *fd);
+
+/* Releases fd to be asynchronously destroyed.
+   on_done is called when the underlying file descriptor is definitely close()d.
+   If on_done is NULL, no callback will be made.
+   If release_fd is not NULL, it's set to fd and fd will not be closed.
+   Requires: *fd initialized; no outstanding notify_on_read or
+   notify_on_write.
+   MUST NOT be called with a pollset lock taken */
+void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
+                    int *release_fd, const char *reason);
+
+/* Begin polling on an fd.
+   Registers that the given pollset is interested in this fd - so that if read
+   or writability interest changes, the pollset can be kicked to pick up that
+   new interest.
+   Return value is:
+     (fd_needs_read? read_mask : 0) | (fd_needs_write? write_mask : 0)
+   i.e. a combination of read_mask and write_mask determined by the fd's current
+   interest in said events.
+   Polling strategies that do not need to alter their behavior depending on the
+   fd's current interest (such as epoll) do not need to call this function.
+   MUST NOT be called with a pollset lock taken */
+uint32_t grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
+                            grpc_pollset_worker *worker, uint32_t read_mask,
+                            uint32_t write_mask, grpc_fd_watcher *rec);
+/* Complete polling previously started with grpc_fd_begin_poll
+   MUST NOT be called with a pollset lock taken
+   if got_read or got_write are 1, also does the become_{readable,writable} as
+   appropriate. */
+void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *rec,
+                      int got_read, int got_write);
+
+/* Return 1 if this fd is orphaned, 0 otherwise */
+int grpc_fd_is_orphaned(grpc_fd *fd);
+
+/* Cause any current callbacks to error out with GRPC_CALLBACK_CANCELLED. */
+void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
+
+/* Register read interest, causing read_cb to be called once when fd becomes
+   readable, on deadline specified by deadline, or on shutdown triggered by
+   grpc_fd_shutdown.
+   read_cb will be called with read_cb_arg when *fd becomes readable.
+   read_cb is Called with status of GRPC_CALLBACK_SUCCESS if readable,
+   GRPC_CALLBACK_TIMED_OUT if the call timed out,
+   and CANCELLED if the call was cancelled.
+
+   Requires:This method must not be called before the read_cb for any previous
+   call runs. Edge triggered events are used whenever they are supported by the
+   underlying platform. This means that users must drain fd in read_cb before
+   calling notify_on_read again. Users are also expected to handle spurious
+   events, i.e read_cb is called while nothing can be readable from fd  */
+void grpc_fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
+                            grpc_closure *closure);
+
+/* Exactly the same semantics as above, except based on writable events.  */
+void grpc_fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
+                             grpc_closure *closure);
+
+/* Notification from the poller to an fd that it has become readable or
+   writable.
+   If allow_synchronous_callback is 1, allow running the fd callback inline
+   in this callstack, otherwise register an asynchronous callback and return */
+void grpc_fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
+void grpc_fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
+
+/* Reference counting for fds */
+/*#define GRPC_FD_REF_COUNT_DEBUG*/
+#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_CORE_LIB_IOMGR_FD_POSIX_H */
diff --git a/src/core/lib/iomgr/iocp_windows.c b/src/core/lib/iomgr/iocp_windows.c
new file mode 100644
index 0000000..682a32c
--- /dev/null
+++ b/src/core/lib/iomgr/iocp_windows.c
@@ -0,0 +1,208 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINSOCK_SOCKET
+
+#include <winsock2.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/log_win32.h>
+#include <grpc/support/thd.h>
+
+#include "src/core/lib/iomgr/iocp_windows.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/socket_windows.h"
+#include "src/core/lib/iomgr/timer.h"
+
+static ULONG g_iocp_kick_token;
+static OVERLAPPED g_iocp_custom_overlap;
+
+static gpr_atm g_custom_events = 0;
+
+static HANDLE g_iocp;
+
+static DWORD deadline_to_millis_timeout(gpr_timespec deadline,
+                                        gpr_timespec now) {
+  gpr_timespec timeout;
+  static const int64_t max_spin_polling_us = 10;
+  if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
+    return INFINITE;
+  }
+  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 (DWORD)gpr_time_to_millis(gpr_time_add(
+      timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN)));
+}
+
+grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx,
+                                     gpr_timespec deadline) {
+  BOOL success;
+  DWORD bytes = 0;
+  DWORD flags = 0;
+  ULONG_PTR completion_key;
+  LPOVERLAPPED overlapped;
+  grpc_winsocket *socket;
+  grpc_winsocket_callback_info *info;
+  grpc_closure *closure = NULL;
+  success = GetQueuedCompletionStatus(
+      g_iocp, &bytes, &completion_key, &overlapped,
+      deadline_to_millis_timeout(deadline, gpr_now(deadline.clock_type)));
+  if (success == 0 && overlapped == NULL) {
+    return GRPC_IOCP_WORK_TIMEOUT;
+  }
+  GPR_ASSERT(completion_key && overlapped);
+  if (overlapped == &g_iocp_custom_overlap) {
+    gpr_atm_full_fetch_add(&g_custom_events, -1);
+    if (completion_key == (ULONG_PTR)&g_iocp_kick_token) {
+      /* We were awoken from a kick. */
+      return GRPC_IOCP_WORK_KICK;
+    }
+    gpr_log(GPR_ERROR, "Unknown custom completion key.");
+    abort();
+  }
+
+  socket = (grpc_winsocket *)completion_key;
+  if (overlapped == &socket->write_info.overlapped) {
+    info = &socket->write_info;
+  } else if (overlapped == &socket->read_info.overlapped) {
+    info = &socket->read_info;
+  } else {
+    gpr_log(GPR_ERROR, "Unknown IOCP operation");
+    abort();
+  }
+  success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes,
+                                   FALSE, &flags);
+  info->bytes_transfered = bytes;
+  info->wsa_error = success ? 0 : WSAGetLastError();
+  GPR_ASSERT(overlapped == &info->overlapped);
+  GPR_ASSERT(!info->has_pending_iocp);
+  gpr_mu_lock(&socket->state_mu);
+  if (info->closure) {
+    closure = info->closure;
+    info->closure = NULL;
+  } else {
+    info->has_pending_iocp = 1;
+  }
+  gpr_mu_unlock(&socket->state_mu);
+  grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
+  return GRPC_IOCP_WORK_WORK;
+}
+
+void grpc_iocp_init(void) {
+  g_iocp =
+      CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0);
+  GPR_ASSERT(g_iocp);
+}
+
+void grpc_iocp_kick(void) {
+  BOOL success;
+
+  gpr_atm_full_fetch_add(&g_custom_events, 1);
+  success = PostQueuedCompletionStatus(g_iocp, 0, (ULONG_PTR)&g_iocp_kick_token,
+                                       &g_iocp_custom_overlap);
+  GPR_ASSERT(success);
+}
+
+void grpc_iocp_flush(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_iocp_work_status work_status;
+
+  do {
+    work_status = grpc_iocp_work(&exec_ctx, gpr_inf_past(GPR_CLOCK_MONOTONIC));
+  } while (work_status == GRPC_IOCP_WORK_KICK ||
+           grpc_exec_ctx_flush(&exec_ctx));
+}
+
+void grpc_iocp_shutdown(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  while (gpr_atm_acq_load(&g_custom_events)) {
+    grpc_iocp_work(&exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC));
+    grpc_exec_ctx_flush(&exec_ctx);
+  }
+  grpc_exec_ctx_finish(&exec_ctx);
+  GPR_ASSERT(CloseHandle(g_iocp));
+}
+
+void grpc_iocp_add_socket(grpc_winsocket *socket) {
+  HANDLE ret;
+  if (socket->added_to_iocp) return;
+  ret = CreateIoCompletionPort((HANDLE)socket->socket, g_iocp,
+                               (uintptr_t)socket, 0);
+  if (!ret) {
+    char *utf8_message = gpr_format_message(WSAGetLastError());
+    gpr_log(GPR_ERROR, "Unable to add socket to iocp: %s", utf8_message);
+    gpr_free(utf8_message);
+    __debugbreak();
+    abort();
+  }
+  socket->added_to_iocp = 1;
+  GPR_ASSERT(ret == g_iocp);
+}
+
+/* Calling notify_on_read or write means either of two things:
+   -) The IOCP already completed in the background, and we need to call
+   the callback now.
+   -) The IOCP hasn't completed yet, and we're queuing it for later. */
+static void socket_notify_on_iocp(grpc_exec_ctx *exec_ctx,
+                                  grpc_winsocket *socket, grpc_closure *closure,
+                                  grpc_winsocket_callback_info *info) {
+  GPR_ASSERT(info->closure == NULL);
+  gpr_mu_lock(&socket->state_mu);
+  if (info->has_pending_iocp) {
+    info->has_pending_iocp = 0;
+    grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
+  } else {
+    info->closure = closure;
+  }
+  gpr_mu_unlock(&socket->state_mu);
+}
+
+void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx,
+                                 grpc_winsocket *socket,
+                                 grpc_closure *closure) {
+  socket_notify_on_iocp(exec_ctx, socket, closure, &socket->write_info);
+}
+
+void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
+                                grpc_closure *closure) {
+  socket_notify_on_iocp(exec_ctx, socket, closure, &socket->read_info);
+}
+
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/iocp_windows.h b/src/core/lib/iomgr/iocp_windows.h
new file mode 100644
index 0000000..856c837
--- /dev/null
+++ b/src/core/lib/iomgr/iocp_windows.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_IOCP_WINDOWS_H
+#define GRPC_CORE_LIB_IOMGR_IOCP_WINDOWS_H
+
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/iomgr/socket_windows.h"
+
+typedef enum {
+  GRPC_IOCP_WORK_WORK,
+  GRPC_IOCP_WORK_TIMEOUT,
+  GRPC_IOCP_WORK_KICK
+} grpc_iocp_work_status;
+
+grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx,
+                                     gpr_timespec deadline);
+void grpc_iocp_init(void);
+void grpc_iocp_kick(void);
+void grpc_iocp_flush(void);
+void grpc_iocp_shutdown(void);
+void grpc_iocp_add_socket(grpc_winsocket *);
+
+void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx,
+                                 grpc_winsocket *winsocket,
+                                 grpc_closure *closure);
+
+void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx,
+                                grpc_winsocket *winsocket,
+                                grpc_closure *closure);
+
+#endif /* GRPC_CORE_LIB_IOMGR_IOCP_WINDOWS_H */
diff --git a/src/core/lib/iomgr/iomgr.c b/src/core/lib/iomgr/iomgr.c
new file mode 100644
index 0000000..bb544c8
--- /dev/null
+++ b/src/core/lib/iomgr/iomgr.c
@@ -0,0 +1,175 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/iomgr.h"
+
+#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/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
+
+static gpr_mu g_mu;
+static gpr_cv g_rcv;
+static int g_shutdown;
+static grpc_iomgr_object g_root_object;
+
+void grpc_iomgr_init(void) {
+  g_shutdown = 0;
+  gpr_mu_init(&g_mu);
+  gpr_cv_init(&g_rcv);
+  grpc_exec_ctx_global_init();
+  grpc_timer_list_init(gpr_now(GPR_CLOCK_MONOTONIC));
+  g_root_object.next = g_root_object.prev = &g_root_object;
+  g_root_object.name = "root";
+  grpc_iomgr_platform_init();
+  grpc_pollset_global_init();
+}
+
+static size_t count_objects(void) {
+  grpc_iomgr_object *obj;
+  size_t n = 0;
+  for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) {
+    n++;
+  }
+  return n;
+}
+
+static void dump_objects(const char *kind) {
+  grpc_iomgr_object *obj;
+  for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) {
+    gpr_log(GPR_DEBUG, "%s OBJECT: %s %p", kind, obj->name, obj);
+  }
+}
+
+void grpc_iomgr_shutdown(void) {
+  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);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  grpc_iomgr_platform_flush();
+
+  gpr_mu_lock(&g_mu);
+  g_shutdown = 1;
+  while (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_root_object.next != &g_root_object) {
+        gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed",
+                count_objects());
+      }
+      last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
+    }
+    if (grpc_timer_check(&exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC),
+                         NULL)) {
+      gpr_mu_unlock(&g_mu);
+      grpc_exec_ctx_flush(&exec_ctx);
+      gpr_mu_lock(&g_mu);
+      continue;
+    }
+    if (g_root_object.next != &g_root_object) {
+      gpr_timespec short_deadline = gpr_time_add(
+          gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100, GPR_TIMESPAN));
+      if (gpr_cv_wait(&g_rcv, &g_mu, short_deadline)) {
+        if (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), shutdown_deadline) > 0) {
+          if (g_root_object.next != &g_root_object) {
+            gpr_log(GPR_DEBUG,
+                    "Failed to free %d iomgr objects before shutdown deadline: "
+                    "memory leaks are likely",
+                    count_objects());
+            dump_objects("LEAKED");
+            if (grpc_iomgr_abort_on_leaks()) {
+              abort();
+            }
+          }
+          break;
+        }
+      }
+    }
+  }
+  gpr_mu_unlock(&g_mu);
+
+  grpc_timer_list_shutdown(&exec_ctx);
+  grpc_exec_ctx_finish(&exec_ctx);
+
+  /* ensure all threads have left g_mu */
+  gpr_mu_lock(&g_mu);
+  gpr_mu_unlock(&g_mu);
+
+  grpc_pollset_global_shutdown();
+  grpc_iomgr_platform_shutdown();
+  grpc_exec_ctx_global_shutdown();
+  gpr_mu_destroy(&g_mu);
+  gpr_cv_destroy(&g_rcv);
+}
+
+void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name) {
+  obj->name = gpr_strdup(name);
+  gpr_mu_lock(&g_mu);
+  obj->next = &g_root_object;
+  obj->prev = g_root_object.prev;
+  obj->next->prev = obj->prev->next = obj;
+  gpr_mu_unlock(&g_mu);
+}
+
+void grpc_iomgr_unregister_object(grpc_iomgr_object *obj) {
+  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);
+}
+
+bool grpc_iomgr_abort_on_leaks(void) {
+  char *env = gpr_getenv("GRPC_ABORT_ON_LEAKS");
+  if (env == NULL) return false;
+  static const char *truthy[] = {"yes",  "Yes",  "YES", "true",
+                                 "True", "TRUE", "1"};
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
+    if (0 == strcmp(env, truthy[i])) return true;
+  }
+  return false;
+}
diff --git a/src/core/lib/iomgr/iomgr.h b/src/core/lib/iomgr/iomgr.h
new file mode 100644
index 0000000..babf0a8
--- /dev/null
+++ b/src/core/lib/iomgr/iomgr.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_IOMGR_H
+#define GRPC_CORE_LIB_IOMGR_IOMGR_H
+
+/** Initializes the iomgr. */
+void grpc_iomgr_init(void);
+
+/** Signals the intention to shutdown the iomgr. */
+void grpc_iomgr_shutdown(void);
+
+#endif /* GRPC_CORE_LIB_IOMGR_IOMGR_H */
diff --git a/src/core/lib/iomgr/iomgr_internal.h b/src/core/lib/iomgr/iomgr_internal.h
new file mode 100644
index 0000000..0963630
--- /dev/null
+++ b/src/core/lib/iomgr/iomgr_internal.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_IOMGR_INTERNAL_H
+#define GRPC_CORE_LIB_IOMGR_IOMGR_INTERNAL_H
+
+#include <stdbool.h>
+
+#include <grpc/support/sync.h>
+#include "src/core/lib/iomgr/iomgr.h"
+
+typedef struct grpc_iomgr_object {
+  char *name;
+  struct grpc_iomgr_object *next;
+  struct grpc_iomgr_object *prev;
+} grpc_iomgr_object;
+
+void grpc_pollset_global_init(void);
+void grpc_pollset_global_shutdown(void);
+
+void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name);
+void grpc_iomgr_unregister_object(grpc_iomgr_object *obj);
+
+void grpc_iomgr_platform_init(void);
+/** flush any globally queued work from iomgr */
+void grpc_iomgr_platform_flush(void);
+/** tear down all platform specific global iomgr structures */
+void grpc_iomgr_platform_shutdown(void);
+
+bool grpc_iomgr_abort_on_leaks(void);
+
+#endif /* GRPC_CORE_LIB_IOMGR_IOMGR_INTERNAL_H */
diff --git a/src/core/lib/iomgr/iomgr_posix.c b/src/core/lib/iomgr/iomgr_posix.c
new file mode 100644
index 0000000..e4990f7
--- /dev/null
+++ b/src/core/lib/iomgr/iomgr_posix.c
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/iomgr/fd_posix.h"
+#include "src/core/lib/iomgr/iomgr_posix.h"
+#include "src/core/lib/iomgr/tcp_posix.h"
+
+void grpc_iomgr_platform_init(void) {
+  grpc_fd_global_init();
+  grpc_register_tracer("tcp", &grpc_tcp_trace);
+}
+
+void grpc_iomgr_platform_flush(void) {}
+
+void grpc_iomgr_platform_shutdown(void) { grpc_fd_global_shutdown(); }
+
+#endif /* GRPC_POSIX_SOCKET */
diff --git a/src/core/lib/iomgr/iomgr_posix.h b/src/core/lib/iomgr/iomgr_posix.h
new file mode 100644
index 0000000..6a8996e
--- /dev/null
+++ b/src/core/lib/iomgr/iomgr_posix.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_IOMGR_POSIX_H
+#define GRPC_CORE_LIB_IOMGR_IOMGR_POSIX_H
+
+#include "src/core/lib/iomgr/iomgr_internal.h"
+
+#endif /* GRPC_CORE_LIB_IOMGR_IOMGR_POSIX_H */
diff --git a/src/core/lib/iomgr/iomgr_windows.c b/src/core/lib/iomgr/iomgr_windows.c
new file mode 100644
index 0000000..af7e616
--- /dev/null
+++ b/src/core/lib/iomgr/iomgr_windows.c
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINSOCK_SOCKET
+
+#include "src/core/lib/iomgr/sockaddr_win32.h"
+
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/iocp_windows.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/socket_windows.h"
+
+/* Windows' io manager is going to be fully designed using IO completion
+   ports. All of what we're doing here is basically make sure that
+   Windows sockets are initialized in and out. */
+
+static void winsock_init(void) {
+  WSADATA wsaData;
+  int status = WSAStartup(MAKEWORD(2, 0), &wsaData);
+  GPR_ASSERT(status == 0);
+}
+
+static void winsock_shutdown(void) {
+  int status = WSACleanup();
+  GPR_ASSERT(status == 0);
+}
+
+void grpc_iomgr_platform_init(void) {
+  winsock_init();
+  grpc_iocp_init();
+}
+
+void grpc_iomgr_platform_flush(void) { grpc_iocp_flush(); }
+
+void grpc_iomgr_platform_shutdown(void) {
+  grpc_iocp_shutdown();
+  winsock_shutdown();
+}
+
+#endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/pollset.h b/src/core/lib/iomgr/pollset.h
new file mode 100644
index 0000000..6156124
--- /dev/null
+++ b/src/core/lib/iomgr/pollset.h
@@ -0,0 +1,94 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_POLLSET_H
+#define GRPC_CORE_LIB_IOMGR_POLLSET_H
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1)
+
+/* A grpc_pollset is a set of file descriptors that a higher level item is
+   interested in. For example:
+    - a server will typically keep a pollset containing all connected channels,
+      so that it can find new calls to service
+    - a completion queue might keep a pollset with an entry for each transport
+      that is servicing a call that it's tracking */
+
+typedef struct grpc_pollset grpc_pollset;
+typedef struct grpc_pollset_worker grpc_pollset_worker;
+
+size_t grpc_pollset_size(void);
+void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu);
+/* Begin shutting down the pollset, and call closure when done.
+ * pollset's mutex must be held */
+void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                           grpc_closure *closure);
+/** Reset the pollset to its initial state (perhaps with some cached objects);
+ *  must have been previously shutdown */
+void grpc_pollset_reset(grpc_pollset *pollset);
+void grpc_pollset_destroy(grpc_pollset *pollset);
+
+/* Do some work on a pollset.
+   May involve invoking asynchronous callbacks, or actually polling file
+   descriptors.
+   Requires pollset's mutex locked.
+   May unlock its mutex during its execution.
+
+   worker is a (platform-specific) handle that can be used to wake up
+   from grpc_pollset_work before any events are received and before the timeout
+   has expired. It is both initialized and destroyed by grpc_pollset_work.
+   Initialization of worker is guaranteed to occur BEFORE the
+   pollset's mutex is released for the first time by grpc_pollset_work
+   and it is guaranteed that it will not be released by grpc_pollset_work
+   AFTER worker has been destroyed.
+
+   Tries not to block past deadline.
+   May call grpc_closure_list_run on grpc_closure_list, without holding the
+   pollset
+   lock */
+void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                       grpc_pollset_worker **worker, gpr_timespec now,
+                       gpr_timespec deadline);
+
+/* Break one polling thread out of polling work for this pollset.
+   If specific_worker is GRPC_POLLSET_KICK_BROADCAST, kick ALL the workers.
+   Otherwise, if specific_worker is non-NULL, then kick that worker. */
+void grpc_pollset_kick(grpc_pollset *pollset,
+                       grpc_pollset_worker *specific_worker);
+
+#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_H */
diff --git a/src/core/lib/iomgr/pollset_multipoller_with_epoll.c b/src/core/lib/iomgr/pollset_multipoller_with_epoll.c
new file mode 100644
index 0000000..fa1b0d2
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_multipoller_with_epoll.c
@@ -0,0 +1,324 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_LINUX_MULTIPOLL_WITH_EPOLL
+
+#include <errno.h>
+#include <poll.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/iomgr/fd_posix.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/block_annotate.h"
+
+struct epoll_fd_list {
+  int *epoll_fds;
+  size_t count;
+  size_t capacity;
+};
+
+static struct epoll_fd_list epoll_fd_global_list;
+static gpr_once init_epoll_fd_list_mu = GPR_ONCE_INIT;
+static gpr_mu epoll_fd_list_mu;
+
+static void init_mu(void) { gpr_mu_init(&epoll_fd_list_mu); }
+
+static void add_epoll_fd_to_global_list(int epoll_fd) {
+  gpr_once_init(&init_epoll_fd_list_mu, init_mu);
+
+  gpr_mu_lock(&epoll_fd_list_mu);
+  if (epoll_fd_global_list.count == epoll_fd_global_list.capacity) {
+    epoll_fd_global_list.capacity =
+        GPR_MAX((size_t)8, epoll_fd_global_list.capacity * 2);
+    epoll_fd_global_list.epoll_fds =
+        gpr_realloc(epoll_fd_global_list.epoll_fds,
+                    epoll_fd_global_list.capacity * sizeof(int));
+  }
+  epoll_fd_global_list.epoll_fds[epoll_fd_global_list.count++] = epoll_fd;
+  gpr_mu_unlock(&epoll_fd_list_mu);
+}
+
+static void remove_epoll_fd_from_global_list(int epoll_fd) {
+  gpr_mu_lock(&epoll_fd_list_mu);
+  GPR_ASSERT(epoll_fd_global_list.count > 0);
+  for (size_t i = 0; i < epoll_fd_global_list.count; i++) {
+    if (epoll_fd == epoll_fd_global_list.epoll_fds[i]) {
+      epoll_fd_global_list.epoll_fds[i] =
+          epoll_fd_global_list.epoll_fds[--(epoll_fd_global_list.count)];
+      break;
+    }
+  }
+  gpr_mu_unlock(&epoll_fd_list_mu);
+}
+
+void grpc_remove_fd_from_all_epoll_sets(int fd) {
+  int err;
+  gpr_once_init(&init_epoll_fd_list_mu, init_mu);
+  gpr_mu_lock(&epoll_fd_list_mu);
+  if (epoll_fd_global_list.count == 0) {
+    gpr_mu_unlock(&epoll_fd_list_mu);
+    return;
+  }
+  for (size_t i = 0; i < epoll_fd_global_list.count; i++) {
+    err = epoll_ctl(epoll_fd_global_list.epoll_fds[i], EPOLL_CTL_DEL, fd, NULL);
+    if (err < 0 && errno != ENOENT) {
+      gpr_log(GPR_ERROR, "epoll_ctl del for %d failed: %s", fd,
+              strerror(errno));
+    }
+  }
+  gpr_mu_unlock(&epoll_fd_list_mu);
+}
+
+typedef struct {
+  grpc_pollset *pollset;
+  grpc_fd *fd;
+  grpc_closure closure;
+} delayed_add;
+
+typedef struct { int epoll_fd; } pollset_hdr;
+
+static void finally_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                           grpc_fd *fd) {
+  pollset_hdr *h = pollset->data.ptr;
+  struct epoll_event ev;
+  int err;
+  grpc_fd_watcher watcher;
+
+  /* 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, NULL, 0, 0, &watcher) == 0);
+  if (watcher.fd != NULL) {
+    ev.events = (uint32_t)(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(exec_ctx, &watcher, 0, 0);
+}
+
+static void perform_delayed_add(grpc_exec_ctx *exec_ctx, void *arg,
+                                bool iomgr_status) {
+  delayed_add *da = arg;
+
+  if (!grpc_fd_is_orphaned(da->fd)) {
+    finally_add_fd(exec_ctx, da->pollset, da->fd);
+  }
+
+  gpr_mu_lock(&da->pollset->mu);
+  da->pollset->in_flight_cbs--;
+  if (da->pollset->shutting_down) {
+    /* We don't care about this pollset anymore. */
+    if (da->pollset->in_flight_cbs == 0 && !da->pollset->called_shutdown) {
+      da->pollset->called_shutdown = 1;
+      grpc_exec_ctx_enqueue(exec_ctx, da->pollset->shutdown_done, true, NULL);
+    }
+  }
+  gpr_mu_unlock(&da->pollset->mu);
+
+  GRPC_FD_UNREF(da->fd, "delayed_add");
+
+  gpr_free(da);
+}
+
+static void multipoll_with_epoll_pollset_add_fd(grpc_exec_ctx *exec_ctx,
+                                                grpc_pollset *pollset,
+                                                grpc_fd *fd,
+                                                int and_unlock_pollset) {
+  if (and_unlock_pollset) {
+    gpr_mu_unlock(&pollset->mu);
+    finally_add_fd(exec_ctx, pollset, fd);
+  } else {
+    delayed_add *da = gpr_malloc(sizeof(*da));
+    da->pollset = pollset;
+    da->fd = fd;
+    GRPC_FD_REF(fd, "delayed_add");
+    grpc_closure_init(&da->closure, perform_delayed_add, da);
+    pollset->in_flight_cbs++;
+    grpc_exec_ctx_enqueue(exec_ctx, &da->closure, true, NULL);
+  }
+}
+
+/* TODO(klempner): We probably want to turn this down a bit */
+#define GRPC_EPOLL_MAX_EVENTS 1000
+
+static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
+    grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
+    gpr_timespec deadline, gpr_timespec now) {
+  struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS];
+  int ep_rv;
+  int poll_rv;
+  pollset_hdr *h = pollset->data.ptr;
+  int timeout_ms;
+  struct pollfd pfds[2];
+
+  /* If you want to ignore epoll's ability to sanely handle parallel pollers,
+   * for a more apples-to-apples performance comparison with poll, add a
+   * if (pollset->counter != 0) { return 0; }
+   * here.
+   */
+
+  gpr_mu_unlock(&pollset->mu);
+
+  timeout_ms = grpc_poll_deadline_to_millis_timeout(deadline, now);
+
+  pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd);
+  pfds[0].events = POLLIN;
+  pfds[0].revents = 0;
+  pfds[1].fd = h->epoll_fd;
+  pfds[1].events = POLLIN;
+  pfds[1].revents = 0;
+
+  /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid
+     even going into the blocking annotation if possible */
+  GPR_TIMER_BEGIN("poll", 0);
+  GRPC_SCHEDULING_START_BLOCKING_REGION;
+  poll_rv = grpc_poll_function(pfds, 2, timeout_ms);
+  GRPC_SCHEDULING_END_BLOCKING_REGION;
+  GPR_TIMER_END("poll", 0);
+
+  if (poll_rv < 0) {
+    if (errno != EINTR) {
+      gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+    }
+  } else if (poll_rv == 0) {
+    /* do nothing */
+  } else {
+    if (pfds[0].revents) {
+      grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd);
+    }
+    if (pfds[1].revents) {
+      do {
+        /* The following epoll_wait never blocks; it has a timeout of 0 */
+        ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0);
+        if (ep_rv < 0) {
+          if (errno != EINTR) {
+            gpr_log(GPR_ERROR, "epoll_wait() failed: %s", strerror(errno));
+          }
+        } else {
+          int i;
+          for (i = 0; i < ep_rv; ++i) {
+            grpc_fd *fd = ep_ev[i].data.ptr;
+            /* TODO(klempner): We might want to consider making err and pri
+             * separate events */
+            int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP);
+            int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI);
+            int write_ev = ep_ev[i].events & EPOLLOUT;
+            if (fd == NULL) {
+              grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
+            } else {
+              if (read_ev || cancel) {
+                grpc_fd_become_readable(exec_ctx, fd);
+              }
+              if (write_ev || cancel) {
+                grpc_fd_become_writable(exec_ctx, fd);
+              }
+            }
+          }
+        }
+      } while (ep_rv == GRPC_EPOLL_MAX_EVENTS);
+    }
+  }
+}
+
+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;
+  close(h->epoll_fd);
+  remove_epoll_fd_from_global_list(h->epoll_fd);
+  gpr_free(h);
+}
+
+static const grpc_pollset_vtable multipoll_with_epoll_pollset = {
+    multipoll_with_epoll_pollset_add_fd,
+    multipoll_with_epoll_pollset_maybe_work_and_unlock,
+    multipoll_with_epoll_pollset_finish_shutdown,
+    multipoll_with_epoll_pollset_destroy};
+
+static void epoll_become_multipoller(grpc_exec_ctx *exec_ctx,
+                                     grpc_pollset *pollset, grpc_fd **fds,
+                                     size_t nfds) {
+  size_t i;
+  pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr));
+  struct epoll_event ev;
+  int err;
+
+  pollset->vtable = &multipoll_with_epoll_pollset;
+  pollset->data.ptr = h;
+  h->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+  if (h->epoll_fd < 0) {
+    /* TODO(klempner): Fall back to poll here, especially on ENOSYS */
+    gpr_log(GPR_ERROR, "epoll_create1 failed: %s", strerror(errno));
+    abort();
+  }
+  add_epoll_fd_to_global_list(h->epoll_fd);
+
+  ev.events = (uint32_t)(EPOLLIN | EPOLLET);
+  ev.data.ptr = NULL;
+  err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD,
+                  GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd), &ev);
+  if (err < 0) {
+    gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s",
+            GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd),
+            strerror(errno));
+  }
+
+  for (i = 0; i < nfds; i++) {
+    multipoll_with_epoll_pollset_add_fd(exec_ctx, pollset, fds[i], 0);
+  }
+}
+
+grpc_platform_become_multipoller_type grpc_platform_become_multipoller =
+    epoll_become_multipoller;
+
+#else /* GPR_LINUX_MULTIPOLL_WITH_EPOLL */
+
+void grpc_remove_fd_from_all_epoll_sets(int fd) {}
+
+#endif /* GPR_LINUX_MULTIPOLL_WITH_EPOLL */
diff --git a/src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c
new file mode 100644
index 0000000..9b33f6d
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c
@@ -0,0 +1,234 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/lib/iomgr/pollset_posix.h"
+
+#include <errno.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/iomgr/fd_posix.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
+#include "src/core/lib/support/block_annotate.h"
+
+typedef struct {
+  /* all polled fds */
+  size_t fd_count;
+  size_t fd_capacity;
+  grpc_fd **fds;
+  /* fds that have been removed from the pollset explicitly */
+  size_t del_count;
+  size_t del_capacity;
+  grpc_fd **dels;
+} pollset_hdr;
+
+static void multipoll_with_poll_pollset_add_fd(grpc_exec_ctx *exec_ctx,
+                                               grpc_pollset *pollset,
+                                               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) 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, "multipoller");
+exit:
+  if (and_unlock_pollset) {
+    gpr_mu_unlock(&pollset->mu);
+  }
+}
+
+static void multipoll_with_poll_pollset_maybe_work_and_unlock(
+    grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
+    gpr_timespec deadline, gpr_timespec now) {
+#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
+#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR)
+
+  int timeout;
+  int r;
+  size_t i, j, fd_count;
+  nfds_t pfd_count;
+  pollset_hdr *h;
+  /* TODO(ctiller): inline some elements to avoid an allocation */
+  grpc_fd_watcher *watchers;
+  struct pollfd *pfds;
+
+  h = pollset->data.ptr;
+  timeout = grpc_poll_deadline_to_millis_timeout(deadline, now);
+  /* TODO(ctiller): perform just one malloc here if we exceed the inline case */
+  pfds = gpr_malloc(sizeof(*pfds) * (h->fd_count + 2));
+  watchers = gpr_malloc(sizeof(*watchers) * (h->fd_count + 2));
+  fd_count = 0;
+  pfd_count = 2;
+  pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd);
+  pfds[0].events = POLLIN;
+  pfds[0].revents = 0;
+  pfds[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd);
+  pfds[1].events = POLLIN;
+  pfds[1].revents = 0;
+  for (i = 0; i < h->fd_count; i++) {
+    int remove = grpc_fd_is_orphaned(h->fds[i]);
+    for (j = 0; !remove && j < h->del_count; j++) {
+      if (h->fds[i] == h->dels[j]) remove = 1;
+    }
+    if (remove) {
+      GRPC_FD_UNREF(h->fds[i], "multipoller");
+    } else {
+      h->fds[fd_count++] = h->fds[i];
+      watchers[pfd_count].fd = h->fds[i];
+      GRPC_FD_REF(watchers[pfd_count].fd, "multipoller_start");
+      pfds[pfd_count].fd = h->fds[i]->fd;
+      pfds[pfd_count].revents = 0;
+      pfd_count++;
+    }
+  }
+  for (j = 0; j < h->del_count; j++) {
+    GRPC_FD_UNREF(h->dels[j], "multipoller_del");
+  }
+  h->del_count = 0;
+  h->fd_count = fd_count;
+  gpr_mu_unlock(&pollset->mu);
+
+  for (i = 2; i < pfd_count; i++) {
+    grpc_fd *fd = watchers[i].fd;
+    pfds[i].events = (short)grpc_fd_begin_poll(fd, pollset, worker, POLLIN,
+                                               POLLOUT, &watchers[i]);
+    GRPC_FD_UNREF(fd, "multipoller_start");
+  }
+
+  /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid
+     even going into the blocking annotation if possible */
+  GRPC_SCHEDULING_START_BLOCKING_REGION;
+  r = grpc_poll_function(pfds, pfd_count, timeout);
+  GRPC_SCHEDULING_END_BLOCKING_REGION;
+
+  if (r < 0) {
+    if (errno != EINTR) {
+      gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+    }
+    for (i = 2; i < pfd_count; i++) {
+      grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0);
+    }
+  } else if (r == 0) {
+    for (i = 2; i < pfd_count; i++) {
+      grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0);
+    }
+  } else {
+    if (pfds[0].revents & POLLIN_CHECK) {
+      grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
+    }
+    if (pfds[1].revents & POLLIN_CHECK) {
+      grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd);
+    }
+    for (i = 2; i < pfd_count; i++) {
+      if (watchers[i].fd == NULL) {
+        grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0);
+        continue;
+      }
+      grpc_fd_end_poll(exec_ctx, &watchers[i], pfds[i].revents & POLLIN_CHECK,
+                       pfds[i].revents & POLLOUT_CHECK);
+    }
+  }
+
+  gpr_free(pfds);
+  gpr_free(watchers);
+}
+
+static void multipoll_with_poll_pollset_finish_shutdown(grpc_pollset *pollset) {
+  size_t i;
+  pollset_hdr *h = pollset->data.ptr;
+  for (i = 0; i < h->fd_count; i++) {
+    GRPC_FD_UNREF(h->fds[i], "multipoller");
+  }
+  for (i = 0; i < h->del_count; 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->fds);
+  gpr_free(h->dels);
+  gpr_free(h);
+}
+
+static const grpc_pollset_vtable multipoll_with_poll_pollset = {
+    multipoll_with_poll_pollset_add_fd,
+    multipoll_with_poll_pollset_maybe_work_and_unlock,
+    multipoll_with_poll_pollset_finish_shutdown,
+    multipoll_with_poll_pollset_destroy};
+
+void grpc_poll_become_multipoller(grpc_exec_ctx *exec_ctx,
+                                  grpc_pollset *pollset, grpc_fd **fds,
+                                  size_t nfds) {
+  size_t i;
+  pollset_hdr *h = gpr_malloc(sizeof(pollset_hdr));
+  pollset->vtable = &multipoll_with_poll_pollset;
+  pollset->data.ptr = h;
+  h->fd_count = nfds;
+  h->fd_capacity = nfds;
+  h->fds = gpr_malloc(nfds * sizeof(grpc_fd *));
+  h->del_count = 0;
+  h->del_capacity = 0;
+  h->dels = NULL;
+  for (i = 0; i < nfds; i++) {
+    h->fds[i] = fds[i];
+    GRPC_FD_REF(fds[i], "multipoller");
+  }
+}
+
+#endif /* GPR_POSIX_SOCKET */
+
+#ifdef GPR_POSIX_MULTIPOLL_WITH_POLL
+grpc_platform_become_multipoller_type grpc_platform_become_multipoller =
+    grpc_poll_become_multipoller;
+#endif
diff --git a/src/core/lib/iomgr/pollset_posix.c b/src/core/lib/iomgr/pollset_posix.c
new file mode 100644
index 0000000..259c7bc
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_posix.c
@@ -0,0 +1,633 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/lib/iomgr/pollset_posix.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/tls.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/iomgr/fd_posix.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/block_annotate.h"
+
+GPR_TLS_DECL(g_current_thread_poller);
+GPR_TLS_DECL(g_current_thread_worker);
+
+/** Default poll() function - a pointer so that it can be overridden by some
+ *  tests */
+grpc_poll_function_type grpc_poll_function = poll;
+
+/** The alarm system needs to be able to wakeup 'some poller' sometimes
+ *  (specifically when a new alarm needs to be triggered earlier than the next
+ *  alarm 'epoch').
+ *  This wakeup_fd gives us something to alert on when such a case occurs. */
+grpc_wakeup_fd grpc_global_wakeup_fd;
+
+static void remove_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
+  worker->prev->next = worker->next;
+  worker->next->prev = worker->prev;
+}
+
+int grpc_pollset_has_workers(grpc_pollset *p) {
+  return p->root_worker.next != &p->root_worker;
+}
+
+static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) {
+  if (grpc_pollset_has_workers(p)) {
+    grpc_pollset_worker *w = p->root_worker.next;
+    remove_worker(p, w);
+    return w;
+  } else {
+    return NULL;
+  }
+}
+
+static void push_back_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
+  worker->next = &p->root_worker;
+  worker->prev = worker->next->prev;
+  worker->prev->next = worker->next->prev = worker;
+}
+
+static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
+  worker->prev = &p->root_worker;
+  worker->next = worker->prev->next;
+  worker->prev->next = worker->next->prev = worker;
+}
+
+size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); }
+
+void grpc_pollset_kick_ext(grpc_pollset *p,
+                           grpc_pollset_worker *specific_worker,
+                           uint32_t flags) {
+  GPR_TIMER_BEGIN("grpc_pollset_kick_ext", 0);
+
+  /* pollset->mu already held */
+  if (specific_worker != NULL) {
+    if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
+      GPR_TIMER_BEGIN("grpc_pollset_kick_ext.broadcast", 0);
+      GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0);
+      for (specific_worker = p->root_worker.next;
+           specific_worker != &p->root_worker;
+           specific_worker = specific_worker->next) {
+        grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
+      }
+      p->kicked_without_pollers = 1;
+      GPR_TIMER_END("grpc_pollset_kick_ext.broadcast", 0);
+    } else if (gpr_tls_get(&g_current_thread_worker) !=
+               (intptr_t)specific_worker) {
+      GPR_TIMER_MARK("different_thread_worker", 0);
+      if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
+        specific_worker->reevaluate_polling_on_wakeup = 1;
+      }
+      specific_worker->kicked_specifically = 1;
+      grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
+    } else if ((flags & GRPC_POLLSET_CAN_KICK_SELF) != 0) {
+      GPR_TIMER_MARK("kick_yoself", 0);
+      if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
+        specific_worker->reevaluate_polling_on_wakeup = 1;
+      }
+      specific_worker->kicked_specifically = 1;
+      grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
+    }
+  } else if (gpr_tls_get(&g_current_thread_poller) != (intptr_t)p) {
+    GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0);
+    GPR_TIMER_MARK("kick_anonymous", 0);
+    specific_worker = pop_front_worker(p);
+    if (specific_worker != NULL) {
+      if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) {
+        GPR_TIMER_MARK("kick_anonymous_not_self", 0);
+        push_back_worker(p, specific_worker);
+        specific_worker = pop_front_worker(p);
+        if ((flags & GRPC_POLLSET_CAN_KICK_SELF) == 0 &&
+            gpr_tls_get(&g_current_thread_worker) ==
+                (intptr_t)specific_worker) {
+          push_back_worker(p, specific_worker);
+          specific_worker = NULL;
+        }
+      }
+      if (specific_worker != NULL) {
+        GPR_TIMER_MARK("finally_kick", 0);
+        push_back_worker(p, specific_worker);
+        grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
+      }
+    } else {
+      GPR_TIMER_MARK("kicked_no_pollers", 0);
+      p->kicked_without_pollers = 1;
+    }
+  }
+
+  GPR_TIMER_END("grpc_pollset_kick_ext", 0);
+}
+
+void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) {
+  grpc_pollset_kick_ext(p, specific_worker, 0);
+}
+
+/* global state management */
+
+void grpc_pollset_global_init(void) {
+  gpr_tls_init(&g_current_thread_poller);
+  gpr_tls_init(&g_current_thread_worker);
+  grpc_wakeup_fd_global_init();
+  grpc_wakeup_fd_init(&grpc_global_wakeup_fd);
+}
+
+void grpc_pollset_global_shutdown(void) {
+  grpc_wakeup_fd_destroy(&grpc_global_wakeup_fd);
+  gpr_tls_destroy(&g_current_thread_poller);
+  gpr_tls_destroy(&g_current_thread_worker);
+  grpc_wakeup_fd_global_destroy();
+}
+
+void grpc_kick_poller(void) { grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd); }
+
+/* main interface */
+
+static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null);
+
+void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
+  gpr_mu_init(&pollset->mu);
+  *mu = &pollset->mu;
+  pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker;
+  pollset->in_flight_cbs = 0;
+  pollset->shutting_down = 0;
+  pollset->called_shutdown = 0;
+  pollset->kicked_without_pollers = 0;
+  pollset->idle_jobs.head = pollset->idle_jobs.tail = NULL;
+  pollset->local_wakeup_cache = NULL;
+  pollset->kicked_without_pollers = 0;
+  become_basic_pollset(pollset, NULL);
+}
+
+void grpc_pollset_destroy(grpc_pollset *pollset) {
+  GPR_ASSERT(pollset->in_flight_cbs == 0);
+  GPR_ASSERT(!grpc_pollset_has_workers(pollset));
+  GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail);
+  pollset->vtable->destroy(pollset);
+  while (pollset->local_wakeup_cache) {
+    grpc_cached_wakeup_fd *next = pollset->local_wakeup_cache->next;
+    grpc_wakeup_fd_destroy(&pollset->local_wakeup_cache->fd);
+    gpr_free(pollset->local_wakeup_cache);
+    pollset->local_wakeup_cache = next;
+  }
+}
+
+void grpc_pollset_reset(grpc_pollset *pollset) {
+  GPR_ASSERT(pollset->shutting_down);
+  GPR_ASSERT(pollset->in_flight_cbs == 0);
+  GPR_ASSERT(!grpc_pollset_has_workers(pollset));
+  GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail);
+  pollset->vtable->destroy(pollset);
+  pollset->shutting_down = 0;
+  pollset->called_shutdown = 0;
+  pollset->kicked_without_pollers = 0;
+  become_basic_pollset(pollset, NULL);
+}
+
+void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                         grpc_fd *fd) {
+  gpr_mu_lock(&pollset->mu);
+  pollset->vtable->add_fd(exec_ctx, pollset, fd, 1);
+/* the following (enabled only in debug) will reacquire and then release
+   our lock - meaning that if the unlocking flag passed to add_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_exec_ctx *exec_ctx, grpc_pollset *pollset) {
+  GPR_ASSERT(grpc_closure_list_empty(pollset->idle_jobs));
+  pollset->vtable->finish_shutdown(pollset);
+  grpc_exec_ctx_enqueue(exec_ctx, pollset->shutdown_done, true, NULL);
+}
+
+void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                       grpc_pollset_worker **worker_hdl, gpr_timespec now,
+                       gpr_timespec deadline) {
+  grpc_pollset_worker worker;
+  *worker_hdl = &worker;
+
+  /* pollset->mu already held */
+  int added_worker = 0;
+  int locked = 1;
+  int queued_work = 0;
+  int keep_polling = 0;
+  GPR_TIMER_BEGIN("grpc_pollset_work", 0);
+  /* this must happen before we (potentially) drop pollset->mu */
+  worker.next = worker.prev = NULL;
+  worker.reevaluate_polling_on_wakeup = 0;
+  if (pollset->local_wakeup_cache != NULL) {
+    worker.wakeup_fd = pollset->local_wakeup_cache;
+    pollset->local_wakeup_cache = worker.wakeup_fd->next;
+  } else {
+    worker.wakeup_fd = gpr_malloc(sizeof(*worker.wakeup_fd));
+    grpc_wakeup_fd_init(&worker.wakeup_fd->fd);
+  }
+  worker.kicked_specifically = 0;
+  /* If there's work waiting for the pollset to be idle, and the
+     pollset is idle, then do that work */
+  if (!grpc_pollset_has_workers(pollset) &&
+      !grpc_closure_list_empty(pollset->idle_jobs)) {
+    GPR_TIMER_MARK("grpc_pollset_work.idle_jobs", 0);
+    grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
+    goto done;
+  }
+  /* If we're shutting down then we don't execute any extended work */
+  if (pollset->shutting_down) {
+    GPR_TIMER_MARK("grpc_pollset_work.shutting_down", 0);
+    goto done;
+  }
+  /* Give do_promote priority so we don't starve it out */
+  if (pollset->in_flight_cbs) {
+    GPR_TIMER_MARK("grpc_pollset_work.in_flight_cbs", 0);
+    gpr_mu_unlock(&pollset->mu);
+    locked = 0;
+    goto done;
+  }
+  /* Start polling, and keep doing so while we're being asked to
+     re-evaluate our pollers (this allows poll() based pollers to
+     ensure they don't miss wakeups) */
+  keep_polling = 1;
+  while (keep_polling) {
+    keep_polling = 0;
+    if (!pollset->kicked_without_pollers) {
+      if (!added_worker) {
+        push_front_worker(pollset, &worker);
+        added_worker = 1;
+        gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
+      }
+      gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset);
+      GPR_TIMER_BEGIN("maybe_work_and_unlock", 0);
+      pollset->vtable->maybe_work_and_unlock(exec_ctx, pollset, &worker,
+                                             deadline, now);
+      GPR_TIMER_END("maybe_work_and_unlock", 0);
+      locked = 0;
+      gpr_tls_set(&g_current_thread_poller, 0);
+    } else {
+      GPR_TIMER_MARK("grpc_pollset_work.kicked_without_pollers", 0);
+      pollset->kicked_without_pollers = 0;
+    }
+  /* Finished execution - start cleaning up.
+     Note that we may arrive here from outside the enclosing while() loop.
+     In that case we won't loop though as we haven't added worker to the
+     worker list, which means nobody could ask us to re-evaluate polling). */
+  done:
+    if (!locked) {
+      queued_work |= grpc_exec_ctx_flush(exec_ctx);
+      gpr_mu_lock(&pollset->mu);
+      locked = 1;
+    }
+    /* If we're forced to re-evaluate polling (via grpc_pollset_kick with
+       GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) then we land here and force
+       a loop */
+    if (worker.reevaluate_polling_on_wakeup) {
+      worker.reevaluate_polling_on_wakeup = 0;
+      pollset->kicked_without_pollers = 0;
+      if (queued_work || worker.kicked_specifically) {
+        /* If there's queued work on the list, then set the deadline to be
+           immediate so we get back out of the polling loop quickly */
+        deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC);
+      }
+      keep_polling = 1;
+    }
+  }
+  if (added_worker) {
+    remove_worker(pollset, &worker);
+    gpr_tls_set(&g_current_thread_worker, 0);
+  }
+  /* release wakeup fd to the local pool */
+  worker.wakeup_fd->next = pollset->local_wakeup_cache;
+  pollset->local_wakeup_cache = worker.wakeup_fd;
+  /* check shutdown conditions */
+  if (pollset->shutting_down) {
+    if (grpc_pollset_has_workers(pollset)) {
+      grpc_pollset_kick(pollset, NULL);
+    } else if (!pollset->called_shutdown && pollset->in_flight_cbs == 0) {
+      pollset->called_shutdown = 1;
+      gpr_mu_unlock(&pollset->mu);
+      finish_shutdown(exec_ctx, pollset);
+      grpc_exec_ctx_flush(exec_ctx);
+      /* 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.
+       * TODO(dklempner): Can we refactor the shutdown logic to avoid this? */
+      gpr_mu_lock(&pollset->mu);
+    } else if (!grpc_closure_list_empty(pollset->idle_jobs)) {
+      grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
+      gpr_mu_unlock(&pollset->mu);
+      grpc_exec_ctx_flush(exec_ctx);
+      gpr_mu_lock(&pollset->mu);
+    }
+  }
+  *worker_hdl = NULL;
+  GPR_TIMER_END("grpc_pollset_work", 0);
+}
+
+void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                           grpc_closure *closure) {
+  GPR_ASSERT(!pollset->shutting_down);
+  pollset->shutting_down = 1;
+  pollset->shutdown_done = closure;
+  grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
+  if (!grpc_pollset_has_workers(pollset)) {
+    grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
+  }
+  if (!pollset->called_shutdown && pollset->in_flight_cbs == 0 &&
+      !grpc_pollset_has_workers(pollset)) {
+    pollset->called_shutdown = 1;
+    finish_shutdown(exec_ctx, pollset);
+  }
+}
+
+int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline,
+                                         gpr_timespec now) {
+  gpr_timespec timeout;
+  static const int64_t max_spin_polling_us = 10;
+  if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 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_MS - 1, GPR_TIMESPAN)));
+}
+
+/*
+ * basic_pollset - a vtable that provides polling for zero or one file
+ *                 descriptor via poll()
+ */
+
+typedef struct grpc_unary_promote_args {
+  const grpc_pollset_vtable *original_vtable;
+  grpc_pollset *pollset;
+  grpc_fd *fd;
+  grpc_closure promotion_closure;
+} grpc_unary_promote_args;
+
+static void basic_do_promote(grpc_exec_ctx *exec_ctx, void *args,
+                             bool success) {
+  grpc_unary_promote_args *up_args = args;
+  const grpc_pollset_vtable *original_vtable = up_args->original_vtable;
+  grpc_pollset *pollset = up_args->pollset;
+  grpc_fd *fd = up_args->fd;
+
+  /*
+   * This is quite tricky. There are a number of cases to keep in mind here:
+   * 1. fd may have been orphaned
+   * 2. The pollset may no longer be a unary poller (and we can't let case #1
+   * leak to other pollset types!)
+   * 3. pollset's fd (which may have changed) may have been orphaned
+   * 4. The pollset may be shutting down.
+   */
+
+  gpr_mu_lock(&pollset->mu);
+  /* First we need to ensure that nobody is polling concurrently */
+  GPR_ASSERT(!grpc_pollset_has_workers(pollset));
+
+  gpr_free(up_args);
+  /* At this point the pollset may no longer be a unary poller. In that case
+   * we should just call the right add function and be done. */
+  /* TODO(klempner): If we're not careful this could cause infinite recursion.
+   * That's not a problem for now because empty_pollset has a trivial poller
+   * and we don't have any mechanism to unbecome multipoller. */
+  pollset->in_flight_cbs--;
+  if (pollset->shutting_down) {
+    /* We don't care about this pollset anymore. */
+    if (pollset->in_flight_cbs == 0 && !pollset->called_shutdown) {
+      pollset->called_shutdown = 1;
+      finish_shutdown(exec_ctx, pollset);
+    }
+  } 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(exec_ctx, pollset, fd, 0);
+  } else if (fd != pollset->data.ptr) {
+    grpc_fd *fds[2];
+    fds[0] = pollset->data.ptr;
+    fds[1] = fd;
+
+    if (fds[0] && !grpc_fd_is_orphaned(fds[0])) {
+      grpc_platform_become_multipoller(exec_ctx, pollset, fds,
+                                       GPR_ARRAY_SIZE(fds));
+      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. */
+      if (fds[0]) GRPC_FD_UNREF(fds[0], "basicpoll");
+      pollset->data.ptr = fd;
+      GRPC_FD_REF(fd, "basicpoll");
+    }
+  }
+
+  gpr_mu_unlock(&pollset->mu);
+
+  /* Matching ref in basic_pollset_add_fd */
+  GRPC_FD_UNREF(fd, "basicpoll_add");
+}
+
+static void basic_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                                 grpc_fd *fd, int and_unlock_pollset) {
+  grpc_unary_promote_args *up_args;
+  GPR_ASSERT(fd);
+  if (fd == pollset->data.ptr) goto exit;
+
+  if (!grpc_pollset_has_workers(pollset)) {
+    /* Fast path -- no in flight cbs */
+    /* TODO(klempner): Comment this out and fix any test failures or establish
+     * they are due to timing issues */
+    grpc_fd *fds[2];
+    fds[0] = pollset->data.ptr;
+    fds[1] = fd;
+
+    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(exec_ctx, pollset, fds,
+                                       GPR_ARRAY_SIZE(fds));
+      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], "basicpoll");
+      pollset->data.ptr = fd;
+      GRPC_FD_REF(fd, "basicpoll");
+    }
+    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, "basicpoll_add");
+  pollset->in_flight_cbs++;
+  up_args = gpr_malloc(sizeof(*up_args));
+  up_args->fd = fd;
+  up_args->original_vtable = pollset->vtable;
+  up_args->pollset = pollset;
+  up_args->promotion_closure.cb = basic_do_promote;
+  up_args->promotion_closure.cb_arg = up_args;
+
+  grpc_closure_list_add(&pollset->idle_jobs, &up_args->promotion_closure, 1);
+  grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
+
+exit:
+  if (and_unlock_pollset) {
+    gpr_mu_unlock(&pollset->mu);
+  }
+}
+
+static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
+                                                grpc_pollset *pollset,
+                                                grpc_pollset_worker *worker,
+                                                gpr_timespec deadline,
+                                                gpr_timespec now) {
+#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
+#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR)
+
+  struct pollfd pfd[3];
+  grpc_fd *fd;
+  grpc_fd_watcher fd_watcher;
+  int timeout;
+  int r;
+  nfds_t nfds;
+
+  fd = pollset->data.ptr;
+  if (fd && grpc_fd_is_orphaned(fd)) {
+    GRPC_FD_UNREF(fd, "basicpoll");
+    fd = pollset->data.ptr = NULL;
+  }
+  timeout = grpc_poll_deadline_to_millis_timeout(deadline, now);
+  pfd[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd);
+  pfd[0].events = POLLIN;
+  pfd[0].revents = 0;
+  pfd[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd);
+  pfd[1].events = POLLIN;
+  pfd[1].revents = 0;
+  nfds = 2;
+  if (fd) {
+    pfd[2].fd = fd->fd;
+    pfd[2].revents = 0;
+    GRPC_FD_REF(fd, "basicpoll_begin");
+    gpr_mu_unlock(&pollset->mu);
+    pfd[2].events = (short)grpc_fd_begin_poll(fd, pollset, worker, POLLIN,
+                                              POLLOUT, &fd_watcher);
+    if (pfd[2].events != 0) {
+      nfds++;
+    }
+  } else {
+    gpr_mu_unlock(&pollset->mu);
+  }
+
+  /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid
+     even going into the blocking annotation if possible */
+  /* poll fd count (argument 2) is shortened by one if we have no events
+     to poll on - such that it only includes the kicker */
+  GPR_TIMER_BEGIN("poll", 0);
+  GRPC_SCHEDULING_START_BLOCKING_REGION;
+  r = grpc_poll_function(pfd, nfds, timeout);
+  GRPC_SCHEDULING_END_BLOCKING_REGION;
+  GPR_TIMER_END("poll", 0);
+
+  if (r < 0) {
+    if (errno != EINTR) {
+      gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+    }
+    if (fd) {
+      grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
+    }
+  } else if (r == 0) {
+    if (fd) {
+      grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
+    }
+  } else {
+    if (pfd[0].revents & POLLIN_CHECK) {
+      grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
+    }
+    if (pfd[1].revents & POLLIN_CHECK) {
+      grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd);
+    }
+    if (nfds > 2) {
+      grpc_fd_end_poll(exec_ctx, &fd_watcher, pfd[2].revents & POLLIN_CHECK,
+                       pfd[2].revents & POLLOUT_CHECK);
+    } else if (fd) {
+      grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
+    }
+  }
+
+  if (fd) {
+    GRPC_FD_UNREF(fd, "basicpoll_begin");
+  }
+}
+
+static void basic_pollset_destroy(grpc_pollset *pollset) {
+  if (pollset->data.ptr != NULL) {
+    GRPC_FD_UNREF(pollset->data.ptr, "basicpoll");
+    pollset->data.ptr = NULL;
+  }
+}
+
+static const grpc_pollset_vtable basic_pollset = {
+    basic_pollset_add_fd, basic_pollset_maybe_work_and_unlock,
+    basic_pollset_destroy, basic_pollset_destroy};
+
+static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null) {
+  pollset->vtable = &basic_pollset;
+  pollset->data.ptr = fd_or_null;
+  if (fd_or_null != NULL) {
+    GRPC_FD_REF(fd_or_null, "basicpoll");
+  }
+}
+
+#endif /* GPR_POSIX_POLLSET */
diff --git a/src/core/lib/iomgr/pollset_posix.h b/src/core/lib/iomgr/pollset_posix.h
new file mode 100644
index 0000000..7d8e9fc
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_posix.h
@@ -0,0 +1,153 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_POLLSET_POSIX_H
+#define GRPC_CORE_LIB_IOMGR_POLLSET_POSIX_H
+
+#include <poll.h>
+
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+
+typedef struct grpc_pollset_vtable grpc_pollset_vtable;
+
+/* forward declare only in this file to avoid leaking impl details via
+   pollset.h; real users of grpc_fd should always include 'fd_posix.h' and not
+   use the struct tag */
+struct grpc_fd;
+
+typedef struct grpc_cached_wakeup_fd {
+  grpc_wakeup_fd fd;
+  struct grpc_cached_wakeup_fd *next;
+} grpc_cached_wakeup_fd;
+
+struct grpc_pollset_worker {
+  grpc_cached_wakeup_fd *wakeup_fd;
+  int reevaluate_polling_on_wakeup;
+  int kicked_specifically;
+  struct grpc_pollset_worker *next;
+  struct grpc_pollset_worker *prev;
+};
+
+struct grpc_pollset {
+  /* pollsets under posix can mutate representation as fds are added and
+     removed.
+     For example, we may choose a poll() based implementation on linux for
+     few fds, and an epoll() based implementation for many fds */
+  const grpc_pollset_vtable *vtable;
+  gpr_mu mu;
+  grpc_pollset_worker root_worker;
+  int in_flight_cbs;
+  int shutting_down;
+  int called_shutdown;
+  int kicked_without_pollers;
+  grpc_closure *shutdown_done;
+  grpc_closure_list idle_jobs;
+  union {
+    int fd;
+    void *ptr;
+  } data;
+  /* Local cache of eventfds for workers */
+  grpc_cached_wakeup_fd *local_wakeup_cache;
+};
+
+struct grpc_pollset_vtable {
+  void (*add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                 struct grpc_fd *fd, int and_unlock_pollset);
+  void (*maybe_work_and_unlock)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                                grpc_pollset_worker *worker,
+                                gpr_timespec deadline, gpr_timespec now);
+  void (*finish_shutdown)(grpc_pollset *pollset);
+  void (*destroy)(grpc_pollset *pollset);
+};
+
+/* Add an fd to a pollset */
+void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                         struct grpc_fd *fd);
+
+/* Returns the fd to listen on for kicks */
+int grpc_kick_read_fd(grpc_pollset *p);
+/* Call after polling has been kicked to leave the kicked state */
+void grpc_kick_drain(grpc_pollset *p);
+
+/* 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);
+
+/* Allow kick to wakeup the currently polling worker */
+#define GRPC_POLLSET_CAN_KICK_SELF 1
+/* Force the wakee to repoll when awoken */
+#define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2
+/* As per grpc_pollset_kick, with an extended set of flags (defined above)
+   -- mostly for fd_posix's use. */
+void grpc_pollset_kick_ext(grpc_pollset *p,
+                           grpc_pollset_worker *specific_worker,
+                           uint32_t flags);
+
+/* turn a pollset into a multipoller: platform specific */
+typedef void (*grpc_platform_become_multipoller_type)(grpc_exec_ctx *exec_ctx,
+                                                      grpc_pollset *pollset,
+                                                      struct grpc_fd **fds,
+                                                      size_t fd_count);
+extern grpc_platform_become_multipoller_type grpc_platform_become_multipoller;
+
+void grpc_poll_become_multipoller(grpc_exec_ctx *exec_ctx,
+                                  grpc_pollset *pollset, struct grpc_fd **fds,
+                                  size_t fd_count);
+
+/* Return 1 if the pollset has active threads in grpc_pollset_work (pollset must
+ * be locked) */
+int grpc_pollset_has_workers(grpc_pollset *pollset);
+
+void grpc_remove_fd_from_all_epoll_sets(int fd);
+
+/* override to allow tests to hook poll() usage */
+/* NOTE: Any changes to grpc_poll_function must take place when the gRPC
+   is certainly not doing any polling anywhere.
+   Otherwise, there might be a race between changing the variable and actually
+   doing a polling operation */
+typedef int (*grpc_poll_function_type)(struct pollfd *, nfds_t, int);
+extern grpc_poll_function_type grpc_poll_function;
+extern grpc_wakeup_fd grpc_global_wakeup_fd;
+
+#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_POSIX_H */
diff --git a/src/core/lib/iomgr/pollset_set.h b/src/core/lib/iomgr/pollset_set.h
new file mode 100644
index 0000000..fb29d69
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_set.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_POLLSET_SET_H
+#define GRPC_CORE_LIB_IOMGR_POLLSET_SET_H
+
+#include "src/core/lib/iomgr/pollset.h"
+
+/* 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. */
+
+typedef struct grpc_pollset_set grpc_pollset_set;
+
+grpc_pollset_set *grpc_pollset_set_create(void);
+void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set);
+void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
+                                  grpc_pollset_set *pollset_set,
+                                  grpc_pollset *pollset);
+void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
+                                  grpc_pollset_set *pollset_set,
+                                  grpc_pollset *pollset);
+void grpc_pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx,
+                                      grpc_pollset_set *bag,
+                                      grpc_pollset_set *item);
+void grpc_pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
+                                      grpc_pollset_set *bag,
+                                      grpc_pollset_set *item);
+
+#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_SET_H */
diff --git a/src/core/lib/iomgr/pollset_set_posix.c b/src/core/lib/iomgr/pollset_set_posix.c
new file mode 100644
index 0000000..d6142f9
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_set_posix.c
@@ -0,0 +1,202 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <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/lib/iomgr/pollset_posix.h"
+#include "src/core/lib/iomgr/pollset_set_posix.h"
+
+struct grpc_pollset_set {
+  gpr_mu mu;
+
+  size_t pollset_count;
+  size_t pollset_capacity;
+  grpc_pollset **pollsets;
+
+  size_t pollset_set_count;
+  size_t pollset_set_capacity;
+  struct grpc_pollset_set **pollset_sets;
+
+  size_t fd_count;
+  size_t fd_capacity;
+  grpc_fd **fds;
+};
+
+grpc_pollset_set *grpc_pollset_set_create(void) {
+  grpc_pollset_set *pollset_set = gpr_malloc(sizeof(*pollset_set));
+  memset(pollset_set, 0, sizeof(*pollset_set));
+  gpr_mu_init(&pollset_set->mu);
+  return pollset_set;
+}
+
+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_set");
+  }
+  gpr_free(pollset_set->pollsets);
+  gpr_free(pollset_set->pollset_sets);
+  gpr_free(pollset_set->fds);
+  gpr_free(pollset_set);
+}
+
+void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
+                                  grpc_pollset_set *pollset_set,
+                                  grpc_pollset *pollset) {
+  size_t i, j;
+  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, j = 0; i < pollset_set->fd_count; i++) {
+    if (grpc_fd_is_orphaned(pollset_set->fds[i])) {
+      GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set");
+    } else {
+      grpc_pollset_add_fd(exec_ctx, pollset, pollset_set->fds[i]);
+      pollset_set->fds[j++] = pollset_set->fds[i];
+    }
+  }
+  pollset_set->fd_count = j;
+  gpr_mu_unlock(&pollset_set->mu);
+}
+
+void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
+                                  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_pollset_set(grpc_exec_ctx *exec_ctx,
+                                      grpc_pollset_set *bag,
+                                      grpc_pollset_set *item) {
+  size_t i, j;
+  gpr_mu_lock(&bag->mu);
+  if (bag->pollset_set_count == bag->pollset_set_capacity) {
+    bag->pollset_set_capacity = GPR_MAX(8, 2 * bag->pollset_set_capacity);
+    bag->pollset_sets =
+        gpr_realloc(bag->pollset_sets,
+                    bag->pollset_set_capacity * sizeof(*bag->pollset_sets));
+  }
+  bag->pollset_sets[bag->pollset_set_count++] = item;
+  for (i = 0, j = 0; i < bag->fd_count; i++) {
+    if (grpc_fd_is_orphaned(bag->fds[i])) {
+      GRPC_FD_UNREF(bag->fds[i], "pollset_set");
+    } else {
+      grpc_pollset_set_add_fd(exec_ctx, item, bag->fds[i]);
+      bag->fds[j++] = bag->fds[i];
+    }
+  }
+  bag->fd_count = j;
+  gpr_mu_unlock(&bag->mu);
+}
+
+void grpc_pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
+                                      grpc_pollset_set *bag,
+                                      grpc_pollset_set *item) {
+  size_t i;
+  gpr_mu_lock(&bag->mu);
+  for (i = 0; i < bag->pollset_set_count; i++) {
+    if (bag->pollset_sets[i] == item) {
+      bag->pollset_set_count--;
+      GPR_SWAP(grpc_pollset_set *, bag->pollset_sets[i],
+               bag->pollset_sets[bag->pollset_set_count]);
+      break;
+    }
+  }
+  gpr_mu_unlock(&bag->mu);
+}
+
+void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx,
+                             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(exec_ctx, pollset_set->pollsets[i], fd);
+  }
+  for (i = 0; i < pollset_set->pollset_set_count; i++) {
+    grpc_pollset_set_add_fd(exec_ctx, pollset_set->pollset_sets[i], fd);
+  }
+  gpr_mu_unlock(&pollset_set->mu);
+}
+
+void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
+                             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;
+    }
+  }
+  for (i = 0; i < pollset_set->pollset_set_count; i++) {
+    grpc_pollset_set_del_fd(exec_ctx, pollset_set->pollset_sets[i], fd);
+  }
+  gpr_mu_unlock(&pollset_set->mu);
+}
+
+#endif /* GPR_POSIX_SOCKET */
diff --git a/src/core/lib/iomgr/pollset_set_posix.h b/src/core/lib/iomgr/pollset_set_posix.h
new file mode 100644
index 0000000..4e6b063
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_set_posix.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_POLLSET_SET_POSIX_H
+#define GRPC_CORE_LIB_IOMGR_POLLSET_SET_POSIX_H
+
+#include "src/core/lib/iomgr/fd_posix.h"
+#include "src/core/lib/iomgr/pollset_set.h"
+
+void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx,
+                             grpc_pollset_set *pollset_set, grpc_fd *fd);
+void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
+                             grpc_pollset_set *pollset_set, grpc_fd *fd);
+
+#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_SET_POSIX_H */
diff --git a/src/core/lib/iomgr/pollset_set_windows.c b/src/core/lib/iomgr/pollset_set_windows.c
new file mode 100644
index 0000000..720fc33
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_set_windows.c
@@ -0,0 +1,60 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINSOCK_SOCKET
+
+#include "src/core/lib/iomgr/pollset_set_windows.h"
+
+grpc_pollset_set* grpc_pollset_set_create(void) { return NULL; }
+
+void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {}
+
+void grpc_pollset_set_add_pollset(grpc_exec_ctx* exec_ctx,
+                                  grpc_pollset_set* pollset_set,
+                                  grpc_pollset* pollset) {}
+
+void grpc_pollset_set_del_pollset(grpc_exec_ctx* exec_ctx,
+                                  grpc_pollset_set* pollset_set,
+                                  grpc_pollset* pollset) {}
+
+void grpc_pollset_set_add_pollset_set(grpc_exec_ctx* exec_ctx,
+                                      grpc_pollset_set* bag,
+                                      grpc_pollset_set* item) {}
+
+void grpc_pollset_set_del_pollset_set(grpc_exec_ctx* exec_ctx,
+                                      grpc_pollset_set* bag,
+                                      grpc_pollset_set* item) {}
+
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/pollset_set_windows.h b/src/core/lib/iomgr/pollset_set_windows.h
new file mode 100644
index 0000000..7c2cea2
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_set_windows.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_POLLSET_SET_WINDOWS_H
+#define GRPC_CORE_LIB_IOMGR_POLLSET_SET_WINDOWS_H
+
+#include "src/core/lib/iomgr/pollset_set.h"
+
+#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_SET_WINDOWS_H */
diff --git a/src/core/lib/iomgr/pollset_windows.c b/src/core/lib/iomgr/pollset_windows.c
new file mode 100644
index 0000000..6b33912
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_windows.c
@@ -0,0 +1,240 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINSOCK_SOCKET
+
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+
+#include "src/core/lib/iomgr/iocp_windows.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/pollset_windows.h"
+
+gpr_mu grpc_polling_mu;
+static grpc_pollset_worker *g_active_poller;
+static grpc_pollset_worker g_global_root_worker;
+
+void grpc_pollset_global_init() {
+  gpr_mu_init(&grpc_polling_mu);
+  g_active_poller = NULL;
+  g_global_root_worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next =
+      g_global_root_worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].prev =
+          &g_global_root_worker;
+}
+
+void grpc_pollset_global_shutdown() { gpr_mu_destroy(&grpc_polling_mu); }
+
+static void remove_worker(grpc_pollset_worker *worker,
+                          grpc_pollset_worker_link_type type) {
+  worker->links[type].prev->links[type].next = worker->links[type].next;
+  worker->links[type].next->links[type].prev = worker->links[type].prev;
+  worker->links[type].next = worker->links[type].prev = worker;
+}
+
+static int has_workers(grpc_pollset_worker *root,
+                       grpc_pollset_worker_link_type type) {
+  return root->links[type].next != root;
+}
+
+static grpc_pollset_worker *pop_front_worker(
+    grpc_pollset_worker *root, grpc_pollset_worker_link_type type) {
+  if (has_workers(root, type)) {
+    grpc_pollset_worker *w = root->links[type].next;
+    remove_worker(w, type);
+    return w;
+  } else {
+    return NULL;
+  }
+}
+
+static void push_front_worker(grpc_pollset_worker *root,
+                              grpc_pollset_worker_link_type type,
+                              grpc_pollset_worker *worker) {
+  worker->links[type].prev = root;
+  worker->links[type].next = worker->links[type].prev->links[type].next;
+  worker->links[type].prev->links[type].next =
+      worker->links[type].next->links[type].prev = worker;
+}
+
+size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); }
+
+/* There isn't really any such thing as a pollset under Windows, due to the
+   nature of the IO completion ports. We're still going to provide a minimal
+   set of features for the sake of the rest of grpc. But grpc_pollset_work
+   won't actually do any polling, and return as quickly as possible. */
+
+void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
+  *mu = &grpc_polling_mu;
+  memset(pollset, 0, sizeof(*pollset));
+  pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next =
+      pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev =
+          &pollset->root_worker;
+}
+
+void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                           grpc_closure *closure) {
+  pollset->shutting_down = 1;
+  grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
+  if (!pollset->is_iocp_worker) {
+    grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
+  } else {
+    pollset->on_shutdown = closure;
+  }
+}
+
+void grpc_pollset_destroy(grpc_pollset *pollset) {}
+
+void grpc_pollset_reset(grpc_pollset *pollset) {
+  GPR_ASSERT(pollset->shutting_down);
+  GPR_ASSERT(
+      !has_workers(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET));
+  pollset->shutting_down = 0;
+  pollset->is_iocp_worker = 0;
+  pollset->kicked_without_pollers = 0;
+  pollset->on_shutdown = NULL;
+}
+
+void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+                       grpc_pollset_worker **worker_hdl, gpr_timespec now,
+                       gpr_timespec deadline) {
+  grpc_pollset_worker worker;
+  *worker_hdl = &worker;
+
+  int added_worker = 0;
+  worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next =
+      worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev =
+          worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next =
+              worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].prev = NULL;
+  worker.kicked = 0;
+  worker.pollset = pollset;
+  gpr_cv_init(&worker.cv);
+  if (!pollset->kicked_without_pollers && !pollset->shutting_down) {
+    if (g_active_poller == NULL) {
+      grpc_pollset_worker *next_worker;
+      /* become poller */
+      pollset->is_iocp_worker = 1;
+      g_active_poller = &worker;
+      gpr_mu_unlock(&grpc_polling_mu);
+      grpc_iocp_work(exec_ctx, deadline);
+      grpc_exec_ctx_flush(exec_ctx);
+      gpr_mu_lock(&grpc_polling_mu);
+      pollset->is_iocp_worker = 0;
+      g_active_poller = NULL;
+      /* try to get a worker from this pollsets worker list */
+      next_worker = pop_front_worker(&pollset->root_worker,
+                                     GRPC_POLLSET_WORKER_LINK_POLLSET);
+      if (next_worker == NULL) {
+        /* try to get a worker from the global list */
+        next_worker = pop_front_worker(&g_global_root_worker,
+                                       GRPC_POLLSET_WORKER_LINK_GLOBAL);
+      }
+      if (next_worker != NULL) {
+        next_worker->kicked = 1;
+        gpr_cv_signal(&next_worker->cv);
+      }
+
+      if (pollset->shutting_down && pollset->on_shutdown != NULL) {
+        grpc_exec_ctx_enqueue(exec_ctx, pollset->on_shutdown, true, NULL);
+        pollset->on_shutdown = NULL;
+      }
+      goto done;
+    }
+    push_front_worker(&g_global_root_worker, GRPC_POLLSET_WORKER_LINK_GLOBAL,
+                      &worker);
+    push_front_worker(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET,
+                      &worker);
+    added_worker = 1;
+    while (!worker.kicked) {
+      if (gpr_cv_wait(&worker.cv, &grpc_polling_mu, deadline)) {
+        break;
+      }
+    }
+  } else {
+    pollset->kicked_without_pollers = 0;
+  }
+done:
+  if (!grpc_closure_list_empty(exec_ctx->closure_list)) {
+    gpr_mu_unlock(&grpc_polling_mu);
+    grpc_exec_ctx_flush(exec_ctx);
+    gpr_mu_lock(&grpc_polling_mu);
+  }
+  if (added_worker) {
+    remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_GLOBAL);
+    remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_POLLSET);
+  }
+  gpr_cv_destroy(&worker.cv);
+  *worker_hdl = NULL;
+}
+
+void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) {
+  if (specific_worker != NULL) {
+    if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
+      for (specific_worker =
+               p->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next;
+           specific_worker != &p->root_worker;
+           specific_worker =
+               specific_worker->links[GRPC_POLLSET_WORKER_LINK_POLLSET].next) {
+        specific_worker->kicked = 1;
+        gpr_cv_signal(&specific_worker->cv);
+      }
+      p->kicked_without_pollers = 1;
+      if (p->is_iocp_worker) {
+        grpc_iocp_kick();
+      }
+    } else {
+      if (p->is_iocp_worker && g_active_poller == specific_worker) {
+        grpc_iocp_kick();
+      } else {
+        specific_worker->kicked = 1;
+        gpr_cv_signal(&specific_worker->cv);
+      }
+    }
+  } else {
+    specific_worker =
+        pop_front_worker(&p->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET);
+    if (specific_worker != NULL) {
+      grpc_pollset_kick(p, specific_worker);
+    } else if (p->is_iocp_worker) {
+      grpc_iocp_kick();
+    } else {
+      p->kicked_without_pollers = 1;
+    }
+  }
+}
+
+void grpc_kick_poller(void) { grpc_iocp_kick(); }
+
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/pollset_windows.h b/src/core/lib/iomgr/pollset_windows.h
new file mode 100644
index 0000000..fa9553f
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_windows.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_POLLSET_WINDOWS_H
+#define GRPC_CORE_LIB_IOMGR_POLLSET_WINDOWS_H
+
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/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
+   used to synchronize with the IOCP, and workers are condition variables
+   used to block threads until work is ready. */
+
+typedef enum {
+  GRPC_POLLSET_WORKER_LINK_POLLSET = 0,
+  GRPC_POLLSET_WORKER_LINK_GLOBAL,
+  GRPC_POLLSET_WORKER_LINK_TYPES
+} grpc_pollset_worker_link_type;
+
+typedef struct grpc_pollset_worker_link {
+  struct grpc_pollset_worker *next;
+  struct grpc_pollset_worker *prev;
+} grpc_pollset_worker_link;
+
+struct grpc_pollset;
+typedef struct grpc_pollset grpc_pollset;
+
+typedef struct grpc_pollset_worker {
+  gpr_cv cv;
+  int kicked;
+  struct grpc_pollset *pollset;
+  grpc_pollset_worker_link links[GRPC_POLLSET_WORKER_LINK_TYPES];
+} grpc_pollset_worker;
+
+struct grpc_pollset {
+  int shutting_down;
+  int kicked_without_pollers;
+  int is_iocp_worker;
+  grpc_pollset_worker root_worker;
+  grpc_closure *on_shutdown;
+};
+
+#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_WINDOWS_H */
diff --git a/src/core/lib/iomgr/resolve_address.h b/src/core/lib/iomgr/resolve_address.h
new file mode 100644
index 0000000..f748288
--- /dev/null
+++ b/src/core/lib/iomgr/resolve_address.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_H
+#define GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_H
+
+#include <stddef.h>
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/iomgr.h"
+
+#define GRPC_MAX_SOCKADDR_SIZE 128
+
+typedef struct {
+  char addr[GRPC_MAX_SOCKADDR_SIZE];
+  size_t len;
+} grpc_resolved_address;
+
+typedef struct {
+  size_t naddrs;
+  grpc_resolved_address *addrs;
+} grpc_resolved_addresses;
+
+/* Async result callback:
+   On success: addresses is the result, and the callee must call
+   grpc_resolved_addresses_destroy when it's done with them
+   On failure: addresses is NULL */
+typedef void (*grpc_resolve_cb)(grpc_exec_ctx *exec_ctx, void *arg,
+                                grpc_resolved_addresses *addresses);
+/* Asynchronously resolve addr. Use default_port if a port isn't designated
+   in addr, otherwise use the port in addr. */
+/* TODO(ctiller): add a timeout here */
+void grpc_resolve_address(const char *addr, const char *default_port,
+                          grpc_resolve_cb cb, void *arg);
+/* Destroy resolved addresses */
+void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addresses);
+
+/* Resolve addr in a blocking fashion. Returns NULL on failure. On success,
+   result must be freed with grpc_resolved_addresses_destroy. */
+extern grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
+    const char *name, const char *default_port);
+
+#endif /* GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_H */
diff --git a/src/core/lib/iomgr/resolve_address_posix.c b/src/core/lib/iomgr/resolve_address_posix.c
new file mode 100644
index 0000000..ebecb39
--- /dev/null
+++ b/src/core/lib/iomgr/resolve_address_posix.c
@@ -0,0 +1,178 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+
+#include <string.h>
+#include <sys/types.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/unix_sockets_posix.h"
+#include "src/core/lib/support/block_annotate.h"
+#include "src/core/lib/support/string.h"
+
+typedef struct {
+  char *name;
+  char *default_port;
+  grpc_resolve_cb cb;
+  grpc_closure request_closure;
+  void *arg;
+} request;
+
+static grpc_resolved_addresses *blocking_resolve_address_impl(
+    const char *name, const char *default_port) {
+  struct addrinfo hints;
+  struct addrinfo *result = NULL, *resp;
+  char *host;
+  char *port;
+  int s;
+  size_t i;
+  grpc_resolved_addresses *addrs = NULL;
+
+  if (name[0] == 'u' && name[1] == 'n' && name[2] == 'i' && name[3] == 'x' &&
+      name[4] == ':' && name[5] != 0) {
+    return grpc_resolve_unix_domain_address(name + 5);
+  }
+
+  /* parse name, splitting it into host and port parts */
+  gpr_split_host_port(name, &host, &port);
+  if (host == NULL) {
+    gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name);
+    goto done;
+  }
+  if (port == NULL) {
+    if (default_port == NULL) {
+      gpr_log(GPR_ERROR, "no port in name '%s'", name);
+      goto done;
+    }
+    port = gpr_strdup(default_port);
+  }
+
+  /* Call getaddrinfo */
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_UNSPEC;     /* ipv4 or ipv6 */
+  hints.ai_socktype = SOCK_STREAM; /* stream socket */
+  hints.ai_flags = AI_PASSIVE;     /* for wildcard IP address */
+
+  GRPC_SCHEDULING_START_BLOCKING_REGION;
+  s = getaddrinfo(host, port, &hints, &result);
+  GRPC_SCHEDULING_END_BLOCKING_REGION;
+
+  if (s != 0) {
+    /* Retry if well-known service name is recognized */
+    char *svc[][2] = {{"http", "80"}, {"https", "443"}};
+    for (i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
+      if (strcmp(port, svc[i][0]) == 0) {
+        GRPC_SCHEDULING_START_BLOCKING_REGION;
+        s = getaddrinfo(host, svc[i][1], &hints, &result);
+        GRPC_SCHEDULING_END_BLOCKING_REGION;
+        break;
+      }
+    }
+  }
+
+  if (s != 0) {
+    gpr_log(GPR_ERROR, "getaddrinfo: %s", gai_strerror(s));
+    goto done;
+  }
+
+  /* Success path: set addrs non-NULL, fill it in */
+  addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
+  addrs->naddrs = 0;
+  for (resp = result; resp != NULL; resp = resp->ai_next) {
+    addrs->naddrs++;
+  }
+  addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs);
+  i = 0;
+  for (resp = result; resp != NULL; resp = resp->ai_next) {
+    memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
+    addrs->addrs[i].len = resp->ai_addrlen;
+    i++;
+  }
+
+done:
+  gpr_free(host);
+  gpr_free(port);
+  if (result) {
+    freeaddrinfo(result);
+  }
+  return addrs;
+}
+
+grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
+    const char *name, const char *default_port) = blocking_resolve_address_impl;
+
+/* Callback to be passed to grpc_executor to asynch-ify
+ * grpc_blocking_resolve_address */
+static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) {
+  request *r = rp;
+  grpc_resolved_addresses *resolved =
+      grpc_blocking_resolve_address(r->name, r->default_port);
+  void *arg = r->arg;
+  grpc_resolve_cb cb = r->cb;
+  gpr_free(r->name);
+  gpr_free(r->default_port);
+  cb(exec_ctx, arg, resolved);
+  gpr_free(r);
+}
+
+void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) {
+  gpr_free(addrs->addrs);
+  gpr_free(addrs);
+}
+
+void grpc_resolve_address(const char *name, const char *default_port,
+                          grpc_resolve_cb cb, void *arg) {
+  request *r = gpr_malloc(sizeof(request));
+  grpc_closure_init(&r->request_closure, do_request_thread, r);
+  r->name = gpr_strdup(name);
+  r->default_port = gpr_strdup(default_port);
+  r->cb = cb;
+  r->arg = arg;
+  grpc_executor_enqueue(&r->request_closure, 1);
+}
+
+#endif
diff --git a/src/core/lib/iomgr/resolve_address_windows.c b/src/core/lib/iomgr/resolve_address_windows.c
new file mode 100644
index 0000000..bde1f1b
--- /dev/null
+++ b/src/core/lib/iomgr/resolve_address_windows.c
@@ -0,0 +1,169 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+#ifdef GPR_WINSOCK_SOCKET
+
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+
+#include <string.h>
+#include <sys/types.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/log_win32.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/support/block_annotate.h"
+#include "src/core/lib/support/string.h"
+
+typedef struct {
+  char *name;
+  char *default_port;
+  grpc_resolve_cb cb;
+  grpc_closure request_closure;
+  void *arg;
+} request;
+
+static grpc_resolved_addresses *blocking_resolve_address_impl(
+    const char *name, const char *default_port) {
+  struct addrinfo hints;
+  struct addrinfo *result = NULL, *resp;
+  char *host;
+  char *port;
+  int s;
+  size_t i;
+  grpc_resolved_addresses *addrs = NULL;
+
+  /* parse name, splitting it into host and port parts */
+  gpr_split_host_port(name, &host, &port);
+  if (host == NULL) {
+    gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name);
+    goto done;
+  }
+  if (port == NULL) {
+    if (default_port == NULL) {
+      gpr_log(GPR_ERROR, "no port in name '%s'", name);
+      goto done;
+    }
+    port = gpr_strdup(default_port);
+  }
+
+  /* Call getaddrinfo */
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_UNSPEC;     /* ipv4 or ipv6 */
+  hints.ai_socktype = SOCK_STREAM; /* stream socket */
+  hints.ai_flags = AI_PASSIVE;     /* for wildcard IP address */
+
+  GRPC_SCHEDULING_START_BLOCKING_REGION;
+  s = getaddrinfo(host, port, &hints, &result);
+  GRPC_SCHEDULING_END_BLOCKING_REGION;
+  if (s != 0) {
+    char *error_message = gpr_format_message(s);
+    gpr_log(GPR_ERROR, "getaddrinfo: %s", error_message);
+    gpr_free(error_message);
+    goto done;
+  }
+
+  /* Success path: set addrs non-NULL, fill it in */
+  addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
+  addrs->naddrs = 0;
+  for (resp = result; resp != NULL; resp = resp->ai_next) {
+    addrs->naddrs++;
+  }
+  addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs);
+  i = 0;
+  for (resp = result; resp != NULL; resp = resp->ai_next) {
+    memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
+    addrs->addrs[i].len = resp->ai_addrlen;
+    i++;
+  }
+
+  {
+    for (i = 0; i < addrs->naddrs; i++) {
+      char *buf;
+      grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr,
+                              0);
+      gpr_free(buf);
+    }
+  }
+
+done:
+  gpr_free(host);
+  gpr_free(port);
+  if (result) {
+    freeaddrinfo(result);
+  }
+  return addrs;
+}
+
+grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
+    const char *name, const char *default_port) = blocking_resolve_address_impl;
+
+/* Callback to be passed to grpc_executor to asynch-ify
+ * grpc_blocking_resolve_address */
+static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) {
+  request *r = rp;
+  grpc_resolved_addresses *resolved =
+      grpc_blocking_resolve_address(r->name, r->default_port);
+  void *arg = r->arg;
+  grpc_resolve_cb cb = r->cb;
+  gpr_free(r->name);
+  gpr_free(r->default_port);
+  cb(exec_ctx, arg, resolved);
+  gpr_free(r);
+}
+
+void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) {
+  gpr_free(addrs->addrs);
+  gpr_free(addrs);
+}
+
+void grpc_resolve_address(const char *name, const char *default_port,
+                          grpc_resolve_cb cb, void *arg) {
+  request *r = gpr_malloc(sizeof(request));
+  grpc_closure_init(&r->request_closure, do_request_thread, r);
+  r->name = gpr_strdup(name);
+  r->default_port = gpr_strdup(default_port);
+  r->cb = cb;
+  r->arg = arg;
+  grpc_executor_enqueue(&r->request_closure, 1);
+}
+
+#endif
diff --git a/src/core/lib/iomgr/sockaddr.h b/src/core/lib/iomgr/sockaddr.h
new file mode 100644
index 0000000..66a930e
--- /dev/null
+++ b/src/core/lib/iomgr/sockaddr.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_SOCKADDR_H
+#define GRPC_CORE_LIB_IOMGR_SOCKADDR_H
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+#include "src/core/lib/iomgr/sockaddr_win32.h"
+#endif
+
+#ifdef GPR_POSIX_SOCKETADDR
+#include "src/core/lib/iomgr/sockaddr_posix.h"
+#endif
+
+#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_H */
diff --git a/src/core/lib/iomgr/sockaddr_posix.h b/src/core/lib/iomgr/sockaddr_posix.h
new file mode 100644
index 0000000..79a7467
--- /dev/null
+++ b/src/core/lib/iomgr/sockaddr_posix.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_SOCKADDR_POSIX_H
+#define GRPC_CORE_LIB_IOMGR_SOCKADDR_POSIX_H
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_POSIX_H */
diff --git a/src/core/lib/iomgr/sockaddr_utils.c b/src/core/lib/iomgr/sockaddr_utils.c
new file mode 100644
index 0000000..127d95c
--- /dev/null
+++ b/src/core/lib/iomgr/sockaddr_utils.c
@@ -0,0 +1,227 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/iomgr/unix_sockets_posix.h"
+#include "src/core/lib/support/string.h"
+
+static const uint8_t kV4MappedPrefix[] = {0, 0, 0, 0, 0,    0,
+                                          0, 0, 0, 0, 0xff, 0xff};
+
+int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr,
+                              struct sockaddr_in *addr4_out) {
+  GPR_ASSERT(addr != (struct sockaddr *)addr4_out);
+  if (addr->sa_family == AF_INET6) {
+    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
+    if (memcmp(addr6->sin6_addr.s6_addr, kV4MappedPrefix,
+               sizeof(kV4MappedPrefix)) == 0) {
+      if (addr4_out != NULL) {
+        /* Normalize ::ffff:0.0.0.0/96 to IPv4. */
+        memset(addr4_out, 0, sizeof(*addr4_out));
+        addr4_out->sin_family = AF_INET;
+        /* s6_addr32 would be nice, but it's non-standard. */
+        memcpy(&addr4_out->sin_addr, &addr6->sin6_addr.s6_addr[12], 4);
+        addr4_out->sin_port = addr6->sin6_port;
+      }
+      return 1;
+    }
+  }
+  return 0;
+}
+
+int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr,
+                              struct sockaddr_in6 *addr6_out) {
+  GPR_ASSERT(addr != (struct sockaddr *)addr6_out);
+  if (addr->sa_family == AF_INET) {
+    const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
+    memset(addr6_out, 0, sizeof(*addr6_out));
+    addr6_out->sin6_family = AF_INET6;
+    memcpy(&addr6_out->sin6_addr.s6_addr[0], kV4MappedPrefix, 12);
+    memcpy(&addr6_out->sin6_addr.s6_addr[12], &addr4->sin_addr, 4);
+    addr6_out->sin6_port = addr4->sin_port;
+    return 1;
+  }
+  return 0;
+}
+
+int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out) {
+  struct sockaddr_in addr4_normalized;
+  if (grpc_sockaddr_is_v4mapped(addr, &addr4_normalized)) {
+    addr = (struct sockaddr *)&addr4_normalized;
+  }
+  if (addr->sa_family == AF_INET) {
+    /* Check for 0.0.0.0 */
+    const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
+    if (addr4->sin_addr.s_addr != 0) {
+      return 0;
+    }
+    *port_out = ntohs(addr4->sin_port);
+    return 1;
+  } else if (addr->sa_family == AF_INET6) {
+    /* Check for :: */
+    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
+    int i;
+    for (i = 0; i < 16; i++) {
+      if (addr6->sin6_addr.s6_addr[i] != 0) {
+        return 0;
+      }
+    }
+    *port_out = ntohs(addr6->sin6_port);
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out,
+                                  struct sockaddr_in6 *wild6_out) {
+  grpc_sockaddr_make_wildcard4(port, wild4_out);
+  grpc_sockaddr_make_wildcard6(port, wild6_out);
+}
+
+void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out) {
+  GPR_ASSERT(port >= 0 && port < 65536);
+  memset(wild_out, 0, sizeof(*wild_out));
+  wild_out->sin_family = AF_INET;
+  wild_out->sin_port = htons((uint16_t)port);
+}
+
+void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out) {
+  GPR_ASSERT(port >= 0 && port < 65536);
+  memset(wild_out, 0, sizeof(*wild_out));
+  wild_out->sin6_family = AF_INET6;
+  wild_out->sin6_port = htons((uint16_t)port);
+}
+
+int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr,
+                            int normalize) {
+  const int save_errno = errno;
+  struct sockaddr_in addr_normalized;
+  char ntop_buf[INET6_ADDRSTRLEN];
+  const void *ip = NULL;
+  int port;
+  int ret;
+
+  *out = NULL;
+  if (normalize && grpc_sockaddr_is_v4mapped(addr, &addr_normalized)) {
+    addr = (const struct sockaddr *)&addr_normalized;
+  }
+  if (addr->sa_family == AF_INET) {
+    const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
+    ip = &addr4->sin_addr;
+    port = ntohs(addr4->sin_port);
+  } else if (addr->sa_family == AF_INET6) {
+    const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
+    ip = &addr6->sin6_addr;
+    port = ntohs(addr6->sin6_port);
+  }
+  /* Windows inet_ntop wants a mutable ip pointer */
+  if (ip != NULL &&
+      inet_ntop(addr->sa_family, (void *)ip, ntop_buf, sizeof(ntop_buf)) !=
+          NULL) {
+    ret = gpr_join_host_port(out, ntop_buf, port);
+  } else {
+    ret = gpr_asprintf(out, "(sockaddr family=%d)", addr->sa_family);
+  }
+  /* This is probably redundant, but we wouldn't want to log the wrong error. */
+  errno = save_errno;
+  return ret;
+}
+
+char *grpc_sockaddr_to_uri(const struct sockaddr *addr) {
+  char *temp;
+  char *result;
+  struct sockaddr_in addr_normalized;
+
+  if (grpc_sockaddr_is_v4mapped(addr, &addr_normalized)) {
+    addr = (const struct sockaddr *)&addr_normalized;
+  }
+
+  switch (addr->sa_family) {
+    case AF_INET:
+      grpc_sockaddr_to_string(&temp, addr, 0);
+      gpr_asprintf(&result, "ipv4:%s", temp);
+      gpr_free(temp);
+      return result;
+    case AF_INET6:
+      grpc_sockaddr_to_string(&temp, addr, 0);
+      gpr_asprintf(&result, "ipv6:%s", temp);
+      gpr_free(temp);
+      return result;
+    default:
+      return grpc_sockaddr_to_uri_unix_if_possible(addr);
+  }
+}
+
+int grpc_sockaddr_get_port(const struct sockaddr *addr) {
+  switch (addr->sa_family) {
+    case AF_INET:
+      return ntohs(((struct sockaddr_in *)addr)->sin_port);
+    case AF_INET6:
+      return ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
+    default:
+      if (grpc_is_unix_socket(addr)) {
+        return 1;
+      }
+      gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_get_port",
+              addr->sa_family);
+      return 0;
+  }
+}
+
+int grpc_sockaddr_set_port(const struct sockaddr *addr, int port) {
+  switch (addr->sa_family) {
+    case AF_INET:
+      GPR_ASSERT(port >= 0 && port < 65536);
+      ((struct sockaddr_in *)addr)->sin_port = htons((uint16_t)port);
+      return 1;
+    case AF_INET6:
+      GPR_ASSERT(port >= 0 && port < 65536);
+      ((struct sockaddr_in6 *)addr)->sin6_port = htons((uint16_t)port);
+      return 1;
+    default:
+      gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port",
+              addr->sa_family);
+      return 0;
+  }
+}
diff --git a/src/core/lib/iomgr/sockaddr_utils.h b/src/core/lib/iomgr/sockaddr_utils.h
new file mode 100644
index 0000000..20a3e3b
--- /dev/null
+++ b/src/core/lib/iomgr/sockaddr_utils.h
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H
+#define GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H
+
+#include "src/core/lib/iomgr/sockaddr.h"
+
+/* Returns true if addr is an IPv4-mapped IPv6 address within the
+   ::ffff:0.0.0.0/96 range, or false otherwise.
+
+   If addr4_out is non-NULL, the inner IPv4 address will be copied here when
+   returning true. */
+int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr,
+                              struct sockaddr_in *addr4_out);
+
+/* If addr is an AF_INET address, writes the corresponding ::ffff:0.0.0.0/96
+   address to addr6_out and returns true.  Otherwise returns false. */
+int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr,
+                              struct sockaddr_in6 *addr6_out);
+
+/* If addr is ::, 0.0.0.0, or ::ffff:0.0.0.0, writes the port number to
+   *port_out (if not NULL) and returns true, otherwise returns false. */
+int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out);
+
+/* Writes 0.0.0.0:port and [::]:port to separate sockaddrs. */
+void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out,
+                                  struct sockaddr_in6 *wild6_out);
+
+/* Writes 0.0.0.0:port. */
+void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out);
+
+/* Writes [::]:port. */
+void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out);
+
+/* Return the IP port number of a sockaddr */
+int grpc_sockaddr_get_port(const struct sockaddr *addr);
+
+/* Set IP port number of a sockaddr */
+int grpc_sockaddr_set_port(const struct sockaddr *addr, int port);
+
+/* Converts a sockaddr into a newly-allocated human-readable string.
+
+   Currently, only the AF_INET and AF_INET6 families are recognized.
+   If the normalize flag is enabled, ::ffff:0.0.0.0/96 IPv6 addresses are
+   displayed as plain IPv4.
+
+   Usage is similar to gpr_asprintf: returns the number of bytes written
+   (excluding the final '\0'), and *out points to a string which must later be
+   destroyed using gpr_free().
+
+   In the unlikely event of an error, returns -1 and sets *out to NULL.
+   The existing value of errno is always preserved. */
+int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr,
+                            int normalize);
+
+char *grpc_sockaddr_to_uri(const struct sockaddr *addr);
+
+#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H */
diff --git a/src/core/lib/iomgr/sockaddr_win32.h b/src/core/lib/iomgr/sockaddr_win32.h
new file mode 100644
index 0000000..2dd7111
--- /dev/null
+++ b/src/core/lib/iomgr/sockaddr_win32.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_SOCKADDR_WIN32_H
+#define GRPC_CORE_LIB_IOMGR_SOCKADDR_WIN32_H
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+// must be included after the above
+#include <mswsock.h>
+
+#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_WIN32_H */
diff --git a/src/core/lib/iomgr/socket_utils_common_posix.c b/src/core/lib/iomgr/socket_utils_common_posix.c
new file mode 100644
index 0000000..b433aee
--- /dev/null
+++ b/src/core/lib/iomgr/socket_utils_common_posix.c
@@ -0,0 +1,230 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/sync.h>
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/support/string.h"
+
+/* set a socket to non blocking mode */
+int grpc_set_socket_nonblocking(int fd, int non_blocking) {
+  int oldflags = fcntl(fd, F_GETFL, 0);
+  if (oldflags < 0) {
+    return 0;
+  }
+
+  if (non_blocking) {
+    oldflags |= O_NONBLOCK;
+  } else {
+    oldflags &= ~O_NONBLOCK;
+  }
+
+  if (fcntl(fd, F_SETFL, oldflags) != 0) {
+    return 0;
+  }
+
+  return 1;
+}
+
+int grpc_set_socket_no_sigpipe_if_possible(int fd) {
+#ifdef GPR_HAVE_SO_NOSIGPIPE
+  int val = 1;
+  int newval;
+  socklen_t intlen = sizeof(newval);
+  return 0 == setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)) &&
+         0 == getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &newval, &intlen) &&
+         (newval != 0) == val;
+#else
+  return 1;
+#endif
+}
+
+int grpc_set_socket_ip_pktinfo_if_possible(int fd) {
+#ifdef GPR_HAVE_IP_PKTINFO
+  int get_local_ip = 1;
+  return 0 == setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip,
+                         sizeof(get_local_ip));
+#else
+  (void)fd;
+  return 1;
+#endif
+}
+
+int grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd) {
+#ifdef GPR_HAVE_IPV6_RECVPKTINFO
+  int get_local_ip = 1;
+  return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip,
+                         sizeof(get_local_ip));
+#else
+  (void)fd;
+  return 1;
+#endif
+}
+
+/* set a socket to close on exec */
+int grpc_set_socket_cloexec(int fd, int close_on_exec) {
+  int oldflags = fcntl(fd, F_GETFD, 0);
+  if (oldflags < 0) {
+    return 0;
+  }
+
+  if (close_on_exec) {
+    oldflags |= FD_CLOEXEC;
+  } else {
+    oldflags &= ~FD_CLOEXEC;
+  }
+
+  if (fcntl(fd, F_SETFD, oldflags) != 0) {
+    return 0;
+  }
+
+  return 1;
+}
+
+/* set a socket to reuse old addresses */
+int grpc_set_socket_reuse_addr(int fd, int reuse) {
+  int val = (reuse != 0);
+  int newval;
+  socklen_t intlen = sizeof(newval);
+  return 0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) &&
+         0 == getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen) &&
+         (newval != 0) == val;
+}
+
+/* disable nagle */
+int grpc_set_socket_low_latency(int fd, int low_latency) {
+  int val = (low_latency != 0);
+  int newval;
+  socklen_t intlen = sizeof(newval);
+  return 0 == setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) &&
+         0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen) &&
+         (newval != 0) == val;
+}
+
+static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
+static int g_ipv6_loopback_available;
+
+static void probe_ipv6_once(void) {
+  int fd = socket(AF_INET6, SOCK_STREAM, 0);
+  g_ipv6_loopback_available = 0;
+  if (fd < 0) {
+    gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
+  } else {
+    struct sockaddr_in6 addr;
+    memset(&addr, 0, sizeof(addr));
+    addr.sin6_family = AF_INET6;
+    addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
+    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
+      g_ipv6_loopback_available = 1;
+    } else {
+      gpr_log(GPR_INFO,
+              "Disabling AF_INET6 sockets because ::1 is not available.");
+    }
+    close(fd);
+  }
+}
+
+int grpc_ipv6_loopback_available(void) {
+  gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once);
+  return g_ipv6_loopback_available;
+}
+
+/* This should be 0 in production, but it may be enabled for testing or
+   debugging purposes, to simulate an environment where IPv6 sockets can't
+   also speak IPv4. */
+int grpc_forbid_dualstack_sockets_for_testing = 0;
+
+static int set_socket_dualstack(int fd) {
+  if (!grpc_forbid_dualstack_sockets_for_testing) {
+    const int off = 0;
+    return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off));
+  } else {
+    /* Force an IPv6-only socket, for testing purposes. */
+    const int on = 1;
+    setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
+    return 0;
+  }
+}
+
+int grpc_create_dualstack_socket(const struct sockaddr *addr, int type,
+                                 int protocol, grpc_dualstack_mode *dsmode) {
+  int family = addr->sa_family;
+  if (family == AF_INET6) {
+    int fd;
+    if (grpc_ipv6_loopback_available()) {
+      fd = socket(family, type, protocol);
+    } else {
+      fd = -1;
+      errno = EAFNOSUPPORT;
+    }
+    /* Check if we've got a valid dualstack socket. */
+    if (fd >= 0 && set_socket_dualstack(fd)) {
+      *dsmode = GRPC_DSMODE_DUALSTACK;
+      return fd;
+    }
+    /* If this isn't an IPv4 address, then return whatever we've got. */
+    if (!grpc_sockaddr_is_v4mapped(addr, NULL)) {
+      *dsmode = GRPC_DSMODE_IPV6;
+      return fd;
+    }
+    /* Fall back to AF_INET. */
+    if (fd >= 0) {
+      close(fd);
+    }
+    family = AF_INET;
+  }
+  *dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE;
+  return socket(family, type, protocol);
+}
+
+#endif
diff --git a/src/core/lib/iomgr/socket_utils_linux.c b/src/core/lib/iomgr/socket_utils_linux.c
new file mode 100644
index 0000000..e7dfe89
--- /dev/null
+++ b/src/core/lib/iomgr/socket_utils_linux.c
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_LINUX_SOCKETUTILS
+
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
+                 int nonblock, int cloexec) {
+  int flags = 0;
+  flags |= nonblock ? SOCK_NONBLOCK : 0;
+  flags |= cloexec ? SOCK_CLOEXEC : 0;
+  return accept4(sockfd, addr, addrlen, flags);
+}
+
+#endif
diff --git a/src/core/lib/iomgr/socket_utils_posix.c b/src/core/lib/iomgr/socket_utils_posix.c
new file mode 100644
index 0000000..b2fa00c
--- /dev/null
+++ b/src/core/lib/iomgr/socket_utils_posix.c
@@ -0,0 +1,70 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKETUTILS
+
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <grpc/support/log.h>
+
+int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
+                 int nonblock, int cloexec) {
+  int fd, flags;
+
+  fd = accept(sockfd, addr, addrlen);
+  if (fd >= 0) {
+    if (nonblock) {
+      flags = fcntl(fd, F_GETFL, 0);
+      if (flags < 0) goto close_and_error;
+      if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) goto close_and_error;
+    }
+    if (cloexec) {
+      flags = fcntl(fd, F_GETFD, 0);
+      if (flags < 0) goto close_and_error;
+      if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != 0) goto close_and_error;
+    }
+  }
+  return fd;
+
+close_and_error:
+  close(fd);
+  return -1;
+}
+
+#endif /* GPR_POSIX_SOCKETUTILS */
diff --git a/src/core/lib/iomgr/socket_utils_posix.h b/src/core/lib/iomgr/socket_utils_posix.h
new file mode 100644
index 0000000..f73ad63
--- /dev/null
+++ b/src/core/lib/iomgr/socket_utils_posix.h
@@ -0,0 +1,123 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_POSIX_H
+#define GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_POSIX_H
+
+#include <sys/socket.h>
+#include <unistd.h>
+
+/* a wrapper for accept or accept4 */
+int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
+                 int nonblock, int cloexec);
+
+/* set a socket to non blocking mode */
+int grpc_set_socket_nonblocking(int fd, int non_blocking);
+
+/* set a socket to close on exec */
+int grpc_set_socket_cloexec(int fd, int close_on_exec);
+
+/* set a socket to reuse old addresses */
+int grpc_set_socket_reuse_addr(int fd, int reuse);
+
+/* disable nagle */
+int grpc_set_socket_low_latency(int fd, int low_latency);
+
+/* Returns true if this system can create AF_INET6 sockets bound to ::1.
+   The value is probed once, and cached for the life of the process.
+
+   This is more restrictive than checking for socket(AF_INET6) to succeed,
+   because Linux with "net.ipv6.conf.all.disable_ipv6 = 1" is able to create
+   and bind IPv6 sockets, but cannot connect to a getsockname() of [::]:port
+   without a valid loopback interface.  Rather than expose this half-broken
+   state to library users, we turn off IPv6 sockets. */
+int grpc_ipv6_loopback_available(void);
+
+/* Tries to set SO_NOSIGPIPE if available on this platform.
+   Returns 1 on success, 0 on failure.
+   If SO_NO_SIGPIPE is not available, returns 1. */
+int grpc_set_socket_no_sigpipe_if_possible(int fd);
+
+/* Tries to set IP_PKTINFO if available on this platform.
+   Returns 1 on success, 0 on failure.
+   If IP_PKTINFO is not available, returns 1. */
+int grpc_set_socket_ip_pktinfo_if_possible(int fd);
+
+/* Tries to set IPV6_RECVPKTINFO if available on this platform.
+   Returns 1 on success, 0 on failure.
+   If IPV6_RECVPKTINFO is not available, returns 1. */
+int grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd);
+
+/* An enum to keep track of IPv4/IPv6 socket modes.
+
+   Currently, this information is only used when a socket is first created, but
+   in the future we may wish to store it alongside the fd.  This would let calls
+   like sendto() know which family to use without asking the kernel first. */
+typedef enum grpc_dualstack_mode {
+  /* Uninitialized, or a non-IP socket. */
+  GRPC_DSMODE_NONE,
+  /* AF_INET only. */
+  GRPC_DSMODE_IPV4,
+  /* AF_INET6 only, because IPV6_V6ONLY could not be cleared. */
+  GRPC_DSMODE_IPV6,
+  /* AF_INET6, which also supports ::ffff-mapped IPv4 addresses. */
+  GRPC_DSMODE_DUALSTACK
+} grpc_dualstack_mode;
+
+/* Only tests should use this flag. */
+extern int grpc_forbid_dualstack_sockets_for_testing;
+
+/* Creates a new socket for connecting to (or listening on) an address.
+
+   If addr is AF_INET6, this creates an IPv6 socket first.  If that fails,
+   and addr is within ::ffff:0.0.0.0/96, then it automatically falls back to
+   an IPv4 socket.
+
+   If addr is AF_INET, AF_UNIX, or anything else, then this is similar to
+   calling socket() directly.
+
+   Returns an fd on success, otherwise returns -1 with errno set to the result
+   of a failed socket() call.
+
+   The *dsmode output indicates which address family was actually created.
+   The recommended way to use this is:
+   - First convert to IPv6 using grpc_sockaddr_to_v4mapped().
+   - Create the socket.
+   - If *dsmode is IPV4, use grpc_sockaddr_is_v4mapped() to convert back to
+     IPv4, so that bind() or connect() see the correct family.
+   Also, it's important to distinguish between DUALSTACK and IPV6 when
+   listening on the [::] wildcard address. */
+int grpc_create_dualstack_socket(const struct sockaddr *addr, int type,
+                                 int protocol, grpc_dualstack_mode *dsmode);
+
+#endif /* GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_POSIX_H */
diff --git a/src/core/lib/iomgr/socket_windows.c b/src/core/lib/iomgr/socket_windows.c
new file mode 100644
index 0000000..1023a6d
--- /dev/null
+++ b/src/core/lib/iomgr/socket_windows.c
@@ -0,0 +1,100 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINSOCK_SOCKET
+
+#include <winsock2.h>
+
+// must be included after winsock2.h
+#include <mswsock.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/log_win32.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/iomgr/iocp_windows.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/pollset_windows.h"
+#include "src/core/lib/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);
+  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;
+}
+
+/* Schedule a shutdown of the socket operations. Will call the pending
+   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. */
+void grpc_winsocket_shutdown(grpc_winsocket *winsocket) {
+  /* Grab the function pointer for DisconnectEx for that specific socket.
+     It may change depending on the interface. */
+  int status;
+  GUID guid = WSAID_DISCONNECTEX;
+  LPFN_DISCONNECTEX DisconnectEx;
+  DWORD ioctl_num_bytes;
+
+  status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
+                    &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx),
+                    &ioctl_num_bytes, NULL, NULL);
+
+  if (status == 0) {
+    DisconnectEx(winsocket->socket, NULL, 0, 0);
+  } else {
+    char *utf8_message = gpr_format_message(WSAGetLastError());
+    gpr_log(GPR_ERROR, "Unable to retrieve DisconnectEx pointer : %s",
+            utf8_message);
+    gpr_free(utf8_message);
+  }
+  closesocket(winsocket->socket);
+}
+
+void grpc_winsocket_destroy(grpc_winsocket *winsocket) {
+  grpc_iomgr_unregister_object(&winsocket->iomgr_object);
+  gpr_mu_destroy(&winsocket->state_mu);
+  gpr_free(winsocket);
+}
+
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/socket_windows.h b/src/core/lib/iomgr/socket_windows.h
new file mode 100644
index 0000000..7444789
--- /dev/null
+++ b/src/core/lib/iomgr/socket_windows.h
@@ -0,0 +1,111 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_SOCKET_WINDOWS_H
+#define GRPC_CORE_LIB_IOMGR_SOCKET_WINDOWS_H
+
+#include <grpc/support/port_platform.h>
+#include <winsock2.h>
+
+#include <grpc/support/atm.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+
+/* This holds the data for an outstanding read or write on a socket.
+   The mutex to protect the concurrent access to that data is the one
+   inside the winsocket wrapper. */
+typedef struct grpc_winsocket_callback_info {
+  /* This is supposed to be a WSAOVERLAPPED, but in order to get that
+     definition, we need to include ws2tcpip.h, which needs to be included
+     from the top, otherwise it'll clash with a previous inclusion of
+     windows.h that in turns includes winsock.h. If anyone knows a way
+     to do it properly, feel free to send a patch. */
+  OVERLAPPED overlapped;
+  /* The callback information for the pending operation. May be empty if the
+     caller hasn't registered a callback yet. */
+  grpc_closure *closure;
+  /* A boolean to describe if the IO Completion Port got a notification for
+     that operation. This will happen if the operation completed before the
+     called had time to register a callback. We could avoid that behavior
+     altogether by forcing the caller to always register its callback before
+     proceeding queue an operation, but it is frequent for an IO Completion
+     Port to trigger quickly. This way we avoid a context switch for calling
+     the callback. We also simplify the read / write operations to avoid having
+     to hold a mutex for a long amount of time. */
+  int has_pending_iocp;
+  /* The results of the overlapped operation. */
+  DWORD bytes_transfered;
+  int wsa_error;
+} grpc_winsocket_callback_info;
+
+/* This is a wrapper to a Windows socket. A socket can have one outstanding
+   read, and one outstanding write. Doing an asynchronous accept means waiting
+   for a read operation. Doing an asynchronous connect means waiting for a
+   write operation. These are completely arbitrary ties between the operation
+   and the kind of event, because we can have one overlapped per pending
+   operation, whichever its nature is. So we could have more dedicated pending
+   operation callbacks for connect and listen. But given the scope of listen
+   and accept, we don't need to go to that extent and waste memory. Also, this
+   is closer to what happens in posix world. */
+typedef struct grpc_winsocket {
+  SOCKET socket;
+
+  grpc_winsocket_callback_info write_info;
+  grpc_winsocket_callback_info read_info;
+
+  gpr_mu state_mu;
+
+  /* You can't add the same socket twice to the same IO Completion Port.
+     This prevents that. */
+  int added_to_iocp;
+
+  grpc_closure shutdown_closure;
+
+  /* A label for iomgr to track outstanding objects */
+  grpc_iomgr_object iomgr_object;
+} grpc_winsocket;
+
+/* Create a wrapped windows handle. This takes ownership of it, meaning that
+   it will be responsible for closing it. */
+grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name);
+
+/* Initiate an asynchronous shutdown of the socket. Will call off any pending
+   operation to cancel them. */
+void grpc_winsocket_shutdown(grpc_winsocket *socket);
+
+/* Destroy a socket. Should only be called if there's no pending operation. */
+void grpc_winsocket_destroy(grpc_winsocket *socket);
+
+#endif /* GRPC_CORE_LIB_IOMGR_SOCKET_WINDOWS_H */
diff --git a/src/core/lib/iomgr/tcp_client.h b/src/core/lib/iomgr/tcp_client.h
new file mode 100644
index 0000000..6bbe264
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_client.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_TCP_CLIENT_H
+#define GRPC_CORE_LIB_IOMGR_TCP_CLIENT_H
+
+#include <grpc/support/time.h>
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/pollset_set.h"
+#include "src/core/lib/iomgr/sockaddr.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).
+   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(grpc_exec_ctx *exec_ctx, grpc_closure *on_connect,
+                             grpc_endpoint **endpoint,
+                             grpc_pollset_set *interested_parties,
+                             const struct sockaddr *addr, size_t addr_len,
+                             gpr_timespec deadline);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TCP_CLIENT_H */
diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c
new file mode 100644
index 0000000..b8ef643
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_client_posix.c
@@ -0,0 +1,306 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/lib/iomgr/tcp_client.h"
+
+#include <errno.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/iomgr/iomgr_posix.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
+#include "src/core/lib/iomgr/pollset_set_posix.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+#include "src/core/lib/iomgr/tcp_posix.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/iomgr/unix_sockets_posix.h"
+#include "src/core/lib/support/string.h"
+
+extern int grpc_tcp_trace;
+
+typedef struct {
+  gpr_mu mu;
+  grpc_fd *fd;
+  gpr_timespec deadline;
+  grpc_timer alarm;
+  int refs;
+  grpc_closure write_closure;
+  grpc_pollset_set *interested_parties;
+  char *addr_str;
+  grpc_endpoint **ep;
+  grpc_closure *closure;
+} async_connect;
+
+static int prepare_socket(const struct sockaddr *addr, int fd) {
+  if (fd < 0) {
+    goto error;
+  }
+
+  if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
+      (!grpc_is_unix_socket(addr) && !grpc_set_socket_low_latency(fd, 1)) ||
+      !grpc_set_socket_no_sigpipe_if_possible(fd)) {
+    gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
+            strerror(errno));
+    goto error;
+  }
+  return 1;
+
+error:
+  if (fd >= 0) {
+    close(fd);
+  }
+  return 0;
+}
+
+static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
+  int done;
+  async_connect *ac = acp;
+  if (grpc_tcp_trace) {
+    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: success=%d", ac->addr_str,
+            success);
+  }
+  gpr_mu_lock(&ac->mu);
+  if (ac->fd != NULL) {
+    grpc_fd_shutdown(exec_ctx, ac->fd);
+  }
+  done = (--ac->refs == 0);
+  gpr_mu_unlock(&ac->mu);
+  if (done) {
+    gpr_mu_destroy(&ac->mu);
+    gpr_free(ac->addr_str);
+    gpr_free(ac);
+  }
+}
+
+static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
+  async_connect *ac = acp;
+  int so_error = 0;
+  socklen_t so_error_size;
+  int err;
+  int done;
+  grpc_endpoint **ep = ac->ep;
+  grpc_closure *closure = ac->closure;
+  grpc_fd *fd;
+
+  if (grpc_tcp_trace) {
+    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_writable: success=%d",
+            ac->addr_str, success);
+  }
+
+  gpr_mu_lock(&ac->mu);
+  GPR_ASSERT(ac->fd);
+  fd = ac->fd;
+  ac->fd = NULL;
+  gpr_mu_unlock(&ac->mu);
+
+  grpc_timer_cancel(exec_ctx, &ac->alarm);
+
+  gpr_mu_lock(&ac->mu);
+  if (success) {
+    do {
+      so_error_size = sizeof(so_error);
+      err = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size);
+    } while (err < 0 && errno == EINTR);
+    if (err < 0) {
+      gpr_log(GPR_ERROR, "failed to connect to '%s': getsockopt(ERROR): %s",
+              ac->addr_str, strerror(errno));
+      goto finish;
+    } else if (so_error != 0) {
+      if (so_error == ENOBUFS) {
+        /* We will get one of these errors if we have run out of
+           memory in the kernel for the data structures allocated
+           when you connect a socket.  If this happens it is very
+           likely that if we wait a little bit then try again the
+           connection will work (since other programs or this
+           program will close their network connections and free up
+           memory).  This does _not_ indicate that there is anything
+           wrong with the server we are connecting to, this is a
+           local problem.
+
+           If you are looking at this code, then chances are that
+           your program or another program on the same computer
+           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(exec_ctx, fd, &ac->write_closure);
+        return;
+      } else {
+        switch (so_error) {
+          case ECONNREFUSED:
+            gpr_log(
+                GPR_ERROR,
+                "failed to connect to '%s': socket error: connection refused",
+                ac->addr_str);
+            break;
+          default:
+            gpr_log(GPR_ERROR, "failed to connect to '%s': socket error: %d",
+                    ac->addr_str, so_error);
+            break;
+        }
+        goto finish;
+      }
+    } else {
+      grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd);
+      *ep = grpc_tcp_create(fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, ac->addr_str);
+      fd = NULL;
+      goto finish;
+    }
+  } else {
+    gpr_log(GPR_ERROR, "failed to connect to '%s': timeout occurred",
+            ac->addr_str);
+    goto finish;
+  }
+
+  GPR_UNREACHABLE_CODE(return );
+
+finish:
+  if (fd != NULL) {
+    grpc_pollset_set_del_fd(exec_ctx, ac->interested_parties, fd);
+    grpc_fd_orphan(exec_ctx, fd, NULL, NULL, "tcp_client_orphan");
+    fd = NULL;
+  }
+  done = (--ac->refs == 0);
+  gpr_mu_unlock(&ac->mu);
+  if (done) {
+    gpr_mu_destroy(&ac->mu);
+    gpr_free(ac->addr_str);
+    gpr_free(ac);
+  }
+  grpc_exec_ctx_enqueue(exec_ctx, closure, *ep != NULL, NULL);
+}
+
+void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+                             grpc_endpoint **ep,
+                             grpc_pollset_set *interested_parties,
+                             const struct sockaddr *addr, size_t 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;
+
+  *ep = NULL;
+
+  /* Use dualstack sockets where available. */
+  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
+    addr = (const struct sockaddr *)&addr6_v4mapped;
+    addr_len = sizeof(addr6_v4mapped);
+  }
+
+  fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
+  if (fd < 0) {
+    gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
+  }
+  if (dsmode == GRPC_DSMODE_IPV4) {
+    /* If we got an AF_INET socket, map the address back to IPv4. */
+    GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy));
+    addr = (struct sockaddr *)&addr4_copy;
+    addr_len = sizeof(addr4_copy);
+  }
+  if (!prepare_socket(addr, fd)) {
+    grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
+    return;
+  }
+
+  do {
+    GPR_ASSERT(addr_len < ~(socklen_t)0);
+    err = connect(fd, addr, (socklen_t)addr_len);
+  } while (err < 0 && errno == EINTR);
+
+  addr_str = grpc_sockaddr_to_uri(addr);
+  gpr_asprintf(&name, "tcp-client:%s", addr_str);
+
+  fdobj = grpc_fd_create(fd, name);
+
+  if (err >= 0) {
+    *ep = grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str);
+    grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
+    goto done;
+  }
+
+  if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
+    gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno));
+    grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error");
+    grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
+    goto done;
+  }
+
+  grpc_pollset_set_add_fd(exec_ctx, interested_parties, fdobj);
+
+  ac = gpr_malloc(sizeof(async_connect));
+  ac->closure = closure;
+  ac->ep = ep;
+  ac->fd = fdobj;
+  ac->interested_parties = interested_parties;
+  ac->addr_str = addr_str;
+  addr_str = NULL;
+  gpr_mu_init(&ac->mu);
+  ac->refs = 2;
+  ac->write_closure.cb = on_writable;
+  ac->write_closure.cb_arg = ac;
+
+  if (grpc_tcp_trace) {
+    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting",
+            ac->addr_str);
+  }
+
+  gpr_mu_lock(&ac->mu);
+  grpc_timer_init(exec_ctx, &ac->alarm,
+                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
+                  tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure);
+  gpr_mu_unlock(&ac->mu);
+
+done:
+  gpr_free(name);
+  gpr_free(addr_str);
+}
+
+#endif
diff --git a/src/core/lib/iomgr/tcp_client_windows.c b/src/core/lib/iomgr/tcp_client_windows.c
new file mode 100644
index 0000000..86b8d58
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_client_windows.c
@@ -0,0 +1,221 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINSOCK_SOCKET
+
+#include "src/core/lib/iomgr/sockaddr_win32.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/log_win32.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/iomgr/iocp_windows.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/socket_windows.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/iomgr/tcp_windows.h"
+#include "src/core/lib/iomgr/timer.h"
+
+typedef struct {
+  grpc_closure *on_done;
+  gpr_mu mu;
+  grpc_winsocket *socket;
+  gpr_timespec deadline;
+  grpc_timer alarm;
+  char *addr_name;
+  int refs;
+  grpc_closure on_connect;
+  grpc_endpoint **endpoint;
+} async_connect;
+
+static void async_connect_unlock_and_cleanup(async_connect *ac) {
+  int done = (--ac->refs == 0);
+  gpr_mu_unlock(&ac->mu);
+  if (done) {
+    if (ac->socket != NULL) grpc_winsocket_destroy(ac->socket);
+    gpr_mu_destroy(&ac->mu);
+    gpr_free(ac->addr_name);
+    gpr_free(ac);
+  }
+}
+
+static void on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool occured) {
+  async_connect *ac = acp;
+  gpr_mu_lock(&ac->mu);
+  /* If the alarm didn't occur, it got cancelled. */
+  if (ac->socket != NULL && occured) {
+    grpc_winsocket_shutdown(ac->socket);
+  }
+  async_connect_unlock_and_cleanup(ac);
+}
+
+static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, bool from_iocp) {
+  async_connect *ac = acp;
+  SOCKET sock = ac->socket->socket;
+  grpc_endpoint **ep = ac->endpoint;
+  grpc_winsocket_callback_info *info = &ac->socket->write_info;
+  grpc_closure *on_done = ac->on_done;
+
+  grpc_timer_cancel(exec_ctx, &ac->alarm);
+
+  gpr_mu_lock(&ac->mu);
+
+  if (from_iocp) {
+    DWORD transfered_bytes = 0;
+    DWORD flags;
+    BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
+                                              &transfered_bytes, FALSE, &flags);
+    GPR_ASSERT(transfered_bytes == 0);
+    if (!wsa_success) {
+      char *utf8_message = gpr_format_message(WSAGetLastError());
+      gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
+      gpr_free(utf8_message);
+    } else {
+      *ep = grpc_tcp_create(ac->socket, ac->addr_name);
+      ac->socket = NULL;
+    }
+  }
+
+  async_connect_unlock_and_cleanup(ac);
+  /* If the connection was aborted, the callback was already called when
+     the deadline was met. */
+  on_done->cb(exec_ctx, on_done->cb_arg, *ep != NULL);
+}
+
+/* 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(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
+                             grpc_endpoint **endpoint,
+                             grpc_pollset_set *interested_parties,
+                             const struct sockaddr *addr, size_t addr_len,
+                             gpr_timespec deadline) {
+  SOCKET sock = INVALID_SOCKET;
+  BOOL success;
+  int status;
+  struct sockaddr_in6 addr6_v4mapped;
+  struct sockaddr_in6 local_address;
+  async_connect *ac;
+  grpc_winsocket *socket = NULL;
+  LPFN_CONNECTEX ConnectEx;
+  GUID guid = WSAID_CONNECTEX;
+  DWORD ioctl_num_bytes;
+  const char *message = NULL;
+  char *utf8_message;
+  grpc_winsocket_callback_info *info;
+
+  *endpoint = NULL;
+
+  /* Use dualstack sockets where available. */
+  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
+    addr = (const struct sockaddr *)&addr6_v4mapped;
+    addr_len = sizeof(addr6_v4mapped);
+  }
+
+  sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
+                   WSA_FLAG_OVERLAPPED);
+  if (sock == INVALID_SOCKET) {
+    message = "Unable to create socket: %s";
+    goto failure;
+  }
+
+  if (!grpc_tcp_prepare_socket(sock)) {
+    message = "Unable to set socket options: %s";
+    goto failure;
+  }
+
+  /* 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);
+
+  if (status != 0) {
+    message = "Unable to retrieve ConnectEx pointer: %s";
+    goto failure;
+  }
+
+  grpc_sockaddr_make_wildcard6(0, &local_address);
+
+  status = bind(sock, (struct sockaddr *)&local_address, sizeof(local_address));
+  if (status != 0) {
+    message = "Unable to bind socket: %s";
+    goto failure;
+  }
+
+  socket = grpc_winsocket_create(sock, "client");
+  info = &socket->write_info;
+  success =
+      ConnectEx(sock, addr, (int)addr_len, NULL, 0, NULL, &info->overlapped);
+
+  /* It wouldn't be unusual to get a success immediately. But we'll still get
+     an IOCP notification, so let's ignore it. */
+  if (!success) {
+    int error = WSAGetLastError();
+    if (error != ERROR_IO_PENDING) {
+      message = "ConnectEx failed: %s";
+      goto failure;
+    }
+  }
+
+  ac = gpr_malloc(sizeof(async_connect));
+  ac->on_done = on_done;
+  ac->socket = socket;
+  gpr_mu_init(&ac->mu);
+  ac->refs = 2;
+  ac->addr_name = grpc_sockaddr_to_uri(addr);
+  ac->endpoint = endpoint;
+  grpc_closure_init(&ac->on_connect, on_connect, ac);
+
+  grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac,
+                  gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect);
+  return;
+
+failure:
+  utf8_message = gpr_format_message(WSAGetLastError());
+  gpr_log(GPR_ERROR, message, utf8_message);
+  gpr_free(utf8_message);
+  if (socket != NULL) {
+    grpc_winsocket_destroy(socket);
+  } else if (sock != INVALID_SOCKET) {
+    closesocket(sock);
+  }
+  grpc_exec_ctx_enqueue(exec_ctx, on_done, false, NULL);
+}
+
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
new file mode 100644
index 0000000..1898d96
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -0,0 +1,493 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/lib/iomgr/tcp_posix.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
+#include "src/core/lib/iomgr/pollset_set_posix.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/string.h"
+
+#ifdef GPR_HAVE_MSG_NOSIGNAL
+#define SENDMSG_FLAGS MSG_NOSIGNAL
+#else
+#define SENDMSG_FLAGS 0
+#endif
+
+#ifdef GPR_MSG_IOVLEN_TYPE
+typedef GPR_MSG_IOVLEN_TYPE msg_iovlen_type;
+#else
+typedef size_t msg_iovlen_type;
+#endif
+
+int grpc_tcp_trace = 0;
+
+typedef struct {
+  grpc_endpoint base;
+  grpc_fd *em_fd;
+  int fd;
+  int finished_edge;
+  msg_iovlen_type iov_size; /* Number of slices to allocate per read attempt */
+  size_t slice_size;
+  gpr_refcount refcount;
+
+  /* garbage after the last read */
+  gpr_slice_buffer last_read_buffer;
+
+  gpr_slice_buffer *incoming_buffer;
+  gpr_slice_buffer *outgoing_buffer;
+  /** slice within outgoing_buffer to write next */
+  size_t outgoing_slice_idx;
+  /** byte within outgoing_buffer->slices[outgoing_slice_idx] to write next */
+  size_t outgoing_byte_idx;
+
+  grpc_closure *read_cb;
+  grpc_closure *write_cb;
+  grpc_closure *release_fd_cb;
+  int *release_fd;
+
+  grpc_closure read_closure;
+  grpc_closure write_closure;
+
+  char *peer_string;
+} grpc_tcp;
+
+static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
+                            bool success);
+static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
+                             bool success);
+
+static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  grpc_fd_shutdown(exec_ctx, tcp->em_fd);
+}
+
+static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
+  grpc_fd_orphan(exec_ctx, tcp->em_fd, tcp->release_fd_cb, tcp->release_fd,
+                 "tcp_unref_orphan");
+  gpr_slice_buffer_destroy(&tcp->last_read_buffer);
+  gpr_free(tcp->peer_string);
+  gpr_free(tcp);
+}
+
+/*#define GRPC_TCP_REFCOUNT_DEBUG*/
+#ifdef GRPC_TCP_REFCOUNT_DEBUG
+#define TCP_UNREF(cl, tcp, reason) \
+  tcp_unref((cl), (tcp), (reason), __FILE__, __LINE__)
+#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
+static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp,
+                      const char *reason, const char *file, int line) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
+          reason, tcp->refcount.count, tcp->refcount.count - 1);
+  if (gpr_unref(&tcp->refcount)) {
+    tcp_free(exec_ctx, tcp);
+  }
+}
+
+static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
+                    int line) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP   ref %p : %s %d -> %d", tcp,
+          reason, tcp->refcount.count, tcp->refcount.count + 1);
+  gpr_ref(&tcp->refcount);
+}
+#else
+#define TCP_UNREF(cl, tcp, reason) tcp_unref((cl), (tcp))
+#define TCP_REF(tcp, reason) tcp_ref((tcp))
+static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
+  if (gpr_unref(&tcp->refcount)) {
+    tcp_free(exec_ctx, tcp);
+  }
+}
+
+static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
+#endif
+
+static void tcp_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  TCP_UNREF(exec_ctx, tcp, "destroy");
+}
+
+static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, int success) {
+  grpc_closure *cb = tcp->read_cb;
+
+  if (grpc_tcp_trace) {
+    size_t i;
+    gpr_log(GPR_DEBUG, "read: success=%d", success);
+    for (i = 0; i < tcp->incoming_buffer->count; i++) {
+      char *dump = gpr_dump_slice(tcp->incoming_buffer->slices[i],
+                                  GPR_DUMP_HEX | GPR_DUMP_ASCII);
+      gpr_log(GPR_DEBUG, "READ %p: %s", tcp, dump);
+      gpr_free(dump);
+    }
+  }
+
+  tcp->read_cb = NULL;
+  tcp->incoming_buffer = NULL;
+  cb->cb(exec_ctx, cb->cb_arg, success);
+}
+
+#define MAX_READ_IOVEC 4
+static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
+  struct msghdr msg;
+  struct iovec iov[MAX_READ_IOVEC];
+  ssize_t read_bytes;
+  size_t i;
+
+  GPR_ASSERT(!tcp->finished_edge);
+  GPR_ASSERT(tcp->iov_size <= MAX_READ_IOVEC);
+  GPR_ASSERT(tcp->incoming_buffer->count <= MAX_READ_IOVEC);
+  GPR_TIMER_BEGIN("tcp_continue_read", 0);
+
+  while (tcp->incoming_buffer->count < (size_t)tcp->iov_size) {
+    gpr_slice_buffer_add_indexed(tcp->incoming_buffer,
+                                 gpr_slice_malloc(tcp->slice_size));
+  }
+  for (i = 0; i < tcp->incoming_buffer->count; i++) {
+    iov[i].iov_base = GPR_SLICE_START_PTR(tcp->incoming_buffer->slices[i]);
+    iov[i].iov_len = GPR_SLICE_LENGTH(tcp->incoming_buffer->slices[i]);
+  }
+
+  msg.msg_name = NULL;
+  msg.msg_namelen = 0;
+  msg.msg_iov = iov;
+  msg.msg_iovlen = tcp->iov_size;
+  msg.msg_control = NULL;
+  msg.msg_controllen = 0;
+  msg.msg_flags = 0;
+
+  GPR_TIMER_BEGIN("recvmsg", 1);
+  do {
+    read_bytes = recvmsg(tcp->fd, &msg, 0);
+  } while (read_bytes < 0 && errno == EINTR);
+  GPR_TIMER_END("recvmsg", 0);
+
+  if (read_bytes < 0) {
+    /* NB: After calling call_read_cb a parallel call of the read handler may
+     * be running. */
+    if (errno == EAGAIN) {
+      if (tcp->iov_size > 1) {
+        tcp->iov_size /= 2;
+      }
+      /* We've consumed the edge, request a new one */
+      grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
+    } else {
+      /* TODO(klempner): Log interesting errors */
+      gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+      call_read_cb(exec_ctx, tcp, 0);
+      TCP_UNREF(exec_ctx, tcp, "read");
+    }
+  } else if (read_bytes == 0) {
+    /* 0 read size ==> end of stream */
+    gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+    call_read_cb(exec_ctx, tcp, 0);
+    TCP_UNREF(exec_ctx, tcp, "read");
+  } else {
+    GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
+    if ((size_t)read_bytes < tcp->incoming_buffer->length) {
+      gpr_slice_buffer_trim_end(
+          tcp->incoming_buffer,
+          tcp->incoming_buffer->length - (size_t)read_bytes,
+          &tcp->last_read_buffer);
+    } else if (tcp->iov_size < MAX_READ_IOVEC) {
+      ++tcp->iov_size;
+    }
+    GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length);
+    call_read_cb(exec_ctx, tcp, 1);
+    TCP_UNREF(exec_ctx, tcp, "read");
+  }
+
+  GPR_TIMER_END("tcp_continue_read", 0);
+}
+
+static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
+                            bool success) {
+  grpc_tcp *tcp = (grpc_tcp *)arg;
+  GPR_ASSERT(!tcp->finished_edge);
+
+  if (!success) {
+    gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+    call_read_cb(exec_ctx, tcp, 0);
+    TCP_UNREF(exec_ctx, tcp, "read");
+  } else {
+    tcp_continue_read(exec_ctx, tcp);
+  }
+}
+
+static void tcp_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                     gpr_slice_buffer *incoming_buffer, grpc_closure *cb) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  GPR_ASSERT(tcp->read_cb == NULL);
+  tcp->read_cb = cb;
+  tcp->incoming_buffer = incoming_buffer;
+  gpr_slice_buffer_reset_and_unref(incoming_buffer);
+  gpr_slice_buffer_swap(incoming_buffer, &tcp->last_read_buffer);
+  TCP_REF(tcp, "read");
+  if (tcp->finished_edge) {
+    tcp->finished_edge = 0;
+    grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
+  } else {
+    grpc_exec_ctx_enqueue(exec_ctx, &tcp->read_closure, true, NULL);
+  }
+}
+
+typedef enum { FLUSH_DONE, FLUSH_PENDING, FLUSH_ERROR } flush_result;
+
+#define MAX_WRITE_IOVEC 16
+static flush_result tcp_flush(grpc_tcp *tcp) {
+  struct msghdr msg;
+  struct iovec iov[MAX_WRITE_IOVEC];
+  msg_iovlen_type iov_size;
+  ssize_t sent_length;
+  size_t sending_length;
+  size_t trailing;
+  size_t unwind_slice_idx;
+  size_t unwind_byte_idx;
+
+  for (;;) {
+    sending_length = 0;
+    unwind_slice_idx = tcp->outgoing_slice_idx;
+    unwind_byte_idx = tcp->outgoing_byte_idx;
+    for (iov_size = 0; tcp->outgoing_slice_idx != tcp->outgoing_buffer->count &&
+                       iov_size != MAX_WRITE_IOVEC;
+         iov_size++) {
+      iov[iov_size].iov_base =
+          GPR_SLICE_START_PTR(
+              tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) +
+          tcp->outgoing_byte_idx;
+      iov[iov_size].iov_len =
+          GPR_SLICE_LENGTH(
+              tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) -
+          tcp->outgoing_byte_idx;
+      sending_length += iov[iov_size].iov_len;
+      tcp->outgoing_slice_idx++;
+      tcp->outgoing_byte_idx = 0;
+    }
+    GPR_ASSERT(iov_size > 0);
+
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+    msg.msg_iov = iov;
+    msg.msg_iovlen = iov_size;
+    msg.msg_control = NULL;
+    msg.msg_controllen = 0;
+    msg.msg_flags = 0;
+
+    GPR_TIMER_BEGIN("sendmsg", 1);
+    do {
+      /* TODO(klempner): Cork if this is a partial write */
+      sent_length = sendmsg(tcp->fd, &msg, SENDMSG_FLAGS);
+    } while (sent_length < 0 && errno == EINTR);
+    GPR_TIMER_END("sendmsg", 0);
+
+    if (sent_length < 0) {
+      if (errno == EAGAIN) {
+        tcp->outgoing_slice_idx = unwind_slice_idx;
+        tcp->outgoing_byte_idx = unwind_byte_idx;
+        return FLUSH_PENDING;
+      } else {
+        /* TODO(klempner): Log some of these */
+        return FLUSH_ERROR;
+      }
+    }
+
+    GPR_ASSERT(tcp->outgoing_byte_idx == 0);
+    trailing = sending_length - (size_t)sent_length;
+    while (trailing > 0) {
+      size_t slice_length;
+
+      tcp->outgoing_slice_idx--;
+      slice_length = GPR_SLICE_LENGTH(
+          tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]);
+      if (slice_length > trailing) {
+        tcp->outgoing_byte_idx = slice_length - trailing;
+        break;
+      } else {
+        trailing -= slice_length;
+      }
+    }
+
+    if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) {
+      return FLUSH_DONE;
+    }
+  };
+}
+
+static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
+                             bool success) {
+  grpc_tcp *tcp = (grpc_tcp *)arg;
+  flush_result status;
+  grpc_closure *cb;
+
+  if (!success) {
+    cb = tcp->write_cb;
+    tcp->write_cb = NULL;
+    cb->cb(exec_ctx, cb->cb_arg, 0);
+    TCP_UNREF(exec_ctx, tcp, "write");
+    return;
+  }
+
+  status = tcp_flush(tcp);
+  if (status == FLUSH_PENDING) {
+    grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
+  } else {
+    cb = tcp->write_cb;
+    tcp->write_cb = NULL;
+    GPR_TIMER_BEGIN("tcp_handle_write.cb", 0);
+    cb->cb(exec_ctx, cb->cb_arg, status == FLUSH_DONE);
+    GPR_TIMER_END("tcp_handle_write.cb", 0);
+    TCP_UNREF(exec_ctx, tcp, "write");
+  }
+}
+
+static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                      gpr_slice_buffer *buf, grpc_closure *cb) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  flush_result status;
+
+  if (grpc_tcp_trace) {
+    size_t i;
+
+    for (i = 0; i < buf->count; i++) {
+      char *data =
+          gpr_dump_slice(buf->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
+      gpr_log(GPR_DEBUG, "WRITE %p: %s", tcp, data);
+      gpr_free(data);
+    }
+  }
+
+  GPR_TIMER_BEGIN("tcp_write", 0);
+  GPR_ASSERT(tcp->write_cb == NULL);
+
+  if (buf->length == 0) {
+    GPR_TIMER_END("tcp_write", 0);
+    grpc_exec_ctx_enqueue(exec_ctx, cb, true, NULL);
+    return;
+  }
+  tcp->outgoing_buffer = buf;
+  tcp->outgoing_slice_idx = 0;
+  tcp->outgoing_byte_idx = 0;
+
+  status = tcp_flush(tcp);
+  if (status == FLUSH_PENDING) {
+    TCP_REF(tcp, "write");
+    tcp->write_cb = cb;
+    grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
+  } else {
+    grpc_exec_ctx_enqueue(exec_ctx, cb, status == FLUSH_DONE, NULL);
+  }
+
+  GPR_TIMER_END("tcp_write", 0);
+}
+
+static void tcp_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                               grpc_pollset *pollset) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  grpc_pollset_add_fd(exec_ctx, pollset, tcp->em_fd);
+}
+
+static void tcp_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                                   grpc_pollset_set *pollset_set) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  grpc_pollset_set_add_fd(exec_ctx, pollset_set, tcp->em_fd);
+}
+
+static char *tcp_get_peer(grpc_endpoint *ep) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  return gpr_strdup(tcp->peer_string);
+}
+
+static const grpc_endpoint_vtable vtable = {
+    tcp_read,     tcp_write,   tcp_add_to_pollset, tcp_add_to_pollset_set,
+    tcp_shutdown, tcp_destroy, tcp_get_peer};
+
+grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
+                               const char *peer_string) {
+  grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
+  tcp->base.vtable = &vtable;
+  tcp->peer_string = gpr_strdup(peer_string);
+  tcp->fd = em_fd->fd;
+  tcp->read_cb = NULL;
+  tcp->write_cb = NULL;
+  tcp->release_fd_cb = NULL;
+  tcp->release_fd = NULL;
+  tcp->incoming_buffer = NULL;
+  tcp->slice_size = slice_size;
+  tcp->iov_size = 1;
+  tcp->finished_edge = 1;
+  /* paired with unref in grpc_tcp_destroy */
+  gpr_ref_init(&tcp->refcount, 1);
+  tcp->em_fd = em_fd;
+  tcp->read_closure.cb = tcp_handle_read;
+  tcp->read_closure.cb_arg = tcp;
+  tcp->write_closure.cb = tcp_handle_write;
+  tcp->write_closure.cb_arg = tcp;
+  gpr_slice_buffer_init(&tcp->last_read_buffer);
+
+  return &tcp->base;
+}
+
+int grpc_tcp_fd(grpc_endpoint *ep) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  GPR_ASSERT(ep->vtable == &vtable);
+  return grpc_fd_wrapped_fd(tcp->em_fd);
+}
+
+void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                                     int *fd, grpc_closure *done) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  GPR_ASSERT(ep->vtable == &vtable);
+  tcp->release_fd = fd;
+  tcp->release_fd_cb = done;
+  TCP_UNREF(exec_ctx, tcp, "destroy");
+}
+
+#endif
diff --git a/src/core/lib/iomgr/tcp_posix.h b/src/core/lib/iomgr/tcp_posix.h
new file mode 100644
index 0000000..09c4436
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_posix.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_TCP_POSIX_H
+#define GRPC_CORE_LIB_IOMGR_TCP_POSIX_H
+/*
+   Low level TCP "bottom half" implementation, for use by transports built on
+   top of a TCP connection.
+
+   Note that this file does not (yet) include APIs for creating the socket in
+   the first place.
+
+   All calls passing slice transfer ownership of a slice refcount unless
+   otherwise specified.
+*/
+
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/fd_posix.h"
+
+#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
+
+extern int grpc_tcp_trace;
+
+/* Create a tcp endpoint given a file desciptor and a read slice size.
+   Takes ownership of fd. */
+grpc_endpoint *grpc_tcp_create(grpc_fd *fd, size_t read_slice_size,
+                               const char *peer_string);
+
+/* Return the tcp endpoint's fd, or -1 if this is not available. Does not
+   release the fd.
+   Requires: ep must be a tcp endpoint.
+ */
+int grpc_tcp_fd(grpc_endpoint *ep);
+
+/* Destroy the tcp endpoint without closing its fd. *fd will be set and done
+ * will be called when the endpoint is destroyed.
+ * Requires: ep must be a tcp endpoint and fd must not be NULL. */
+void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                                     int *fd, grpc_closure *done);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TCP_POSIX_H */
diff --git a/src/core/lib/iomgr/tcp_server.h b/src/core/lib/iomgr/tcp_server.h
new file mode 100644
index 0000000..81edb61
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_server.h
@@ -0,0 +1,103 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_TCP_SERVER_H
+#define GRPC_CORE_LIB_IOMGR_TCP_SERVER_H
+
+#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/iomgr/endpoint.h"
+
+/* Forward decl of grpc_tcp_server */
+typedef struct grpc_tcp_server grpc_tcp_server;
+
+typedef struct grpc_tcp_server_acceptor {
+  /* grpc_tcp_server_cb functions share a ref on from_server that is valid
+     until the function returns. */
+  grpc_tcp_server *from_server;
+  /* Indices that may be passed to grpc_tcp_server_port_fd(). */
+  unsigned port_index;
+  unsigned fd_index;
+} grpc_tcp_server_acceptor;
+
+/* Called for newly connected TCP connections. */
+typedef void (*grpc_tcp_server_cb)(grpc_exec_ctx *exec_ctx, void *arg,
+                                   grpc_endpoint *ep,
+                                   grpc_tcp_server_acceptor *acceptor);
+
+/* Create a server, initially not bound to any ports. The caller owns one ref.
+   If shutdown_complete is not NULL, it will be used by
+   grpc_tcp_server_unref() when the ref count reaches zero. */
+grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete);
+
+/* Start listening to bound ports */
+void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server,
+                           grpc_pollset **pollsets, size_t pollset_count,
+                           grpc_tcp_server_cb on_accept_cb, void *cb_arg);
+
+/* Add a port to the server, returning the newly allocated port on success, or
+   -1 on failure.
+
+   The :: and 0.0.0.0 wildcard addresses are treated identically, accepting
+   both IPv4 and IPv6 connections, but :: is the preferred style.  This usually
+   creates one socket, but possibly two on systems which support IPv6,
+   but not dualstack sockets. */
+/* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle
+                  all of the multiple socket port matching logic in one place */
+int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
+                             size_t addr_len);
+
+/* Number of fds at the given port_index, or 0 if port_index is out of
+   bounds. */
+unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s, unsigned port_index);
+
+/* Returns the file descriptor of the Mth (fd_index) listening socket of the Nth
+   (port_index) call to add_port() on this server, or -1 if the indices are out
+   of bounds. The file descriptor remains owned by the server, and will be
+   cleaned up when the ref count reaches zero. */
+int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index,
+                            unsigned fd_index);
+
+/* Ref s and return s. */
+grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s);
+
+/* shutdown_starting is called when ref count has reached zero and the server is
+   about to be destroyed. The server will be deleted after it returns. Calling
+   grpc_tcp_server_ref() from it has no effect. */
+void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
+                                           grpc_closure *shutdown_starting);
+
+/* If the refcount drops to zero, delete s, and call (exec_ctx==NULL) or enqueue
+   a call (exec_ctx!=NULL) to shutdown_complete. */
+void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TCP_SERVER_H */
diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c
new file mode 100644
index 0000000..ef1bf9a
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_server_posix.c
@@ -0,0 +1,607 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/lib/iomgr/tcp_server.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.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/time.h>
+#include "src/core/lib/iomgr/pollset_posix.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+#include "src/core/lib/iomgr/tcp_posix.h"
+#include "src/core/lib/iomgr/unix_sockets_posix.h"
+#include "src/core/lib/support/string.h"
+
+#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
+
+static gpr_once s_init_max_accept_queue_size;
+static int s_max_accept_queue_size;
+
+/* one listening port */
+typedef struct grpc_tcp_listener grpc_tcp_listener;
+struct grpc_tcp_listener {
+  int fd;
+  grpc_fd *emfd;
+  grpc_tcp_server *server;
+  union {
+    uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE];
+    struct sockaddr sockaddr;
+  } addr;
+  size_t addr_len;
+  int port;
+  unsigned port_index;
+  unsigned fd_index;
+  grpc_closure read_closure;
+  grpc_closure destroyed_closure;
+  struct grpc_tcp_listener *next;
+  /* When we add a listener, more than one can be created, mainly because of
+     IPv6. A sibling will still be in the normal list, but will be flagged
+     as such. Any action, such as ref or unref, will affect all of the
+     siblings in the list. */
+  struct grpc_tcp_listener *sibling;
+  int is_sibling;
+};
+
+/* the overall server */
+struct grpc_tcp_server {
+  gpr_refcount refs;
+  /* Called whenever accept() succeeds on a server port. */
+  grpc_tcp_server_cb on_accept_cb;
+  void *on_accept_cb_arg;
+
+  gpr_mu mu;
+
+  /* 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;
+
+  /* linked list of server ports */
+  grpc_tcp_listener *head;
+  grpc_tcp_listener *tail;
+  unsigned nports;
+
+  /* List of closures passed to shutdown_starting_add(). */
+  grpc_closure_list shutdown_starting;
+
+  /* shutdown callback */
+  grpc_closure *shutdown_complete;
+
+  /* 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(grpc_closure *shutdown_complete) {
+  grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
+  gpr_ref_init(&s->refs, 1);
+  gpr_mu_init(&s->mu);
+  s->active_ports = 0;
+  s->destroyed_ports = 0;
+  s->shutdown = 0;
+  s->shutdown_starting.head = NULL;
+  s->shutdown_starting.tail = NULL;
+  s->shutdown_complete = shutdown_complete;
+  s->on_accept_cb = NULL;
+  s->on_accept_cb_arg = NULL;
+  s->head = NULL;
+  s->tail = NULL;
+  s->nports = 0;
+  return s;
+}
+
+static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
+  if (s->shutdown_complete != NULL) {
+    grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, true, NULL);
+  }
+
+  gpr_mu_destroy(&s->mu);
+
+  while (s->head) {
+    grpc_tcp_listener *sp = s->head;
+    s->head = sp->next;
+    gpr_free(sp);
+  }
+
+  gpr_free(s);
+}
+
+static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server,
+                           bool success) {
+  grpc_tcp_server *s = server;
+  gpr_mu_lock(&s->mu);
+  s->destroyed_ports++;
+  if (s->destroyed_ports == s->nports) {
+    gpr_mu_unlock(&s->mu);
+    finish_shutdown(exec_ctx, s);
+  } else {
+    GPR_ASSERT(s->destroyed_ports < s->nports);
+    gpr_mu_unlock(&s->mu);
+  }
+}
+
+/* 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_exec_ctx *exec_ctx, grpc_tcp_server *s) {
+  /* delete ALL the things */
+  gpr_mu_lock(&s->mu);
+
+  if (!s->shutdown) {
+    gpr_mu_unlock(&s->mu);
+    return;
+  }
+
+  if (s->head) {
+    grpc_tcp_listener *sp;
+    for (sp = s->head; sp; sp = sp->next) {
+      grpc_unlink_if_unix_domain_socket(&sp->addr.sockaddr);
+      sp->destroyed_closure.cb = destroyed_port;
+      sp->destroyed_closure.cb_arg = s;
+      grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
+                     "tcp_listener_shutdown");
+    }
+    gpr_mu_unlock(&s->mu);
+  } else {
+    gpr_mu_unlock(&s->mu);
+    finish_shutdown(exec_ctx, s);
+  }
+}
+
+static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
+  gpr_mu_lock(&s->mu);
+
+  GPR_ASSERT(!s->shutdown);
+  s->shutdown = 1;
+
+  /* shutdown all fd's */
+  if (s->active_ports) {
+    grpc_tcp_listener *sp;
+    for (sp = s->head; sp; sp = sp->next) {
+      grpc_fd_shutdown(exec_ctx, sp->emfd);
+    }
+    gpr_mu_unlock(&s->mu);
+  } else {
+    gpr_mu_unlock(&s->mu);
+    deactivated_all_ports(exec_ctx, s);
+  }
+}
+
+/* get max listen queue size on linux */
+static void init_max_accept_queue_size(void) {
+  int n = SOMAXCONN;
+  char buf[64];
+  FILE *fp = fopen("/proc/sys/net/core/somaxconn", "r");
+  if (fp == NULL) {
+    /* 2.4 kernel. */
+    s_max_accept_queue_size = SOMAXCONN;
+    return;
+  }
+  if (fgets(buf, sizeof buf, fp)) {
+    char *end;
+    long i = strtol(buf, &end, 10);
+    if (i > 0 && i <= INT_MAX && end && *end == 0) {
+      n = (int)i;
+    }
+  }
+  fclose(fp);
+  s_max_accept_queue_size = n;
+
+  if (s_max_accept_queue_size < MIN_SAFE_ACCEPT_QUEUE_SIZE) {
+    gpr_log(GPR_INFO,
+            "Suspiciously small accept queue (%d) will probably lead to "
+            "connection drops",
+            s_max_accept_queue_size);
+  }
+}
+
+static int get_max_accept_queue_size(void) {
+  gpr_once_init(&s_init_max_accept_queue_size, init_max_accept_queue_size);
+  return s_max_accept_queue_size;
+}
+
+/* Prepare a recently-created socket for listening. */
+static int prepare_socket(int fd, const struct sockaddr *addr,
+                          size_t addr_len) {
+  struct sockaddr_storage sockname_temp;
+  socklen_t sockname_len;
+
+  if (fd < 0) {
+    goto error;
+  }
+
+  if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
+      (!grpc_is_unix_socket(addr) && (!grpc_set_socket_low_latency(fd, 1) ||
+                                      !grpc_set_socket_reuse_addr(fd, 1))) ||
+      !grpc_set_socket_no_sigpipe_if_possible(fd)) {
+    gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
+            strerror(errno));
+    goto error;
+  }
+
+  GPR_ASSERT(addr_len < ~(socklen_t)0);
+  if (bind(fd, addr, (socklen_t)addr_len) < 0) {
+    char *addr_str;
+    grpc_sockaddr_to_string(&addr_str, addr, 0);
+    gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno));
+    gpr_free(addr_str);
+    goto error;
+  }
+
+  if (listen(fd, get_max_accept_queue_size()) < 0) {
+    gpr_log(GPR_ERROR, "listen: %s", strerror(errno));
+    goto error;
+  }
+
+  sockname_len = sizeof(sockname_temp);
+  if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) {
+    goto error;
+  }
+
+  return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+
+error:
+  if (fd >= 0) {
+    close(fd);
+  }
+  return -1;
+}
+
+/* event manager callback when reads are ready */
+static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  grpc_tcp_listener *sp = arg;
+  grpc_tcp_server_acceptor acceptor = {sp->server, sp->port_index,
+                                       sp->fd_index};
+  grpc_fd *fdobj;
+  size_t i;
+
+  if (!success) {
+    goto error;
+  }
+
+  /* loop until accept4 returns EAGAIN, and then re-arm notification */
+  for (;;) {
+    struct sockaddr_storage addr;
+    socklen_t addrlen = sizeof(addr);
+    char *addr_str;
+    char *name;
+    /* Note: If we ever decide to return this address to the user, remember to
+       strip off the ::ffff:0.0.0.0/96 prefix first. */
+    int fd = grpc_accept4(sp->fd, (struct sockaddr *)&addr, &addrlen, 1, 1);
+    if (fd < 0) {
+      switch (errno) {
+        case EINTR:
+          continue;
+        case EAGAIN:
+          grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
+          return;
+        default:
+          gpr_log(GPR_ERROR, "Failed accept4: %s", strerror(errno));
+          goto error;
+      }
+    }
+
+    grpc_set_socket_no_sigpipe_if_possible(fd);
+
+    addr_str = grpc_sockaddr_to_uri((struct sockaddr *)&addr);
+    gpr_asprintf(&name, "tcp-server-connection:%s", addr_str);
+
+    if (grpc_tcp_trace) {
+      gpr_log(GPR_DEBUG, "SERVER_CONNECT: incoming 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(exec_ctx, sp->server->pollsets[i], fdobj);
+    }
+    sp->server->on_accept_cb(
+        exec_ctx, sp->server->on_accept_cb_arg,
+        grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str),
+        &acceptor);
+
+    gpr_free(name);
+    gpr_free(addr_str);
+  }
+
+  GPR_UNREACHABLE_CODE(return );
+
+error:
+  gpr_mu_lock(&sp->server->mu);
+  if (0 == --sp->server->active_ports) {
+    gpr_mu_unlock(&sp->server->mu);
+    deactivated_all_ports(exec_ctx, sp->server);
+  } else {
+    gpr_mu_unlock(&sp->server->mu);
+  }
+}
+
+static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, int fd,
+                                               const struct sockaddr *addr,
+                                               size_t addr_len,
+                                               unsigned port_index,
+                                               unsigned fd_index) {
+  grpc_tcp_listener *sp = NULL;
+  int port;
+  char *addr_str;
+  char *name;
+
+  port = prepare_socket(fd, addr, addr_len);
+  if (port >= 0) {
+    grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
+    gpr_asprintf(&name, "tcp-server-listener:%s", addr_str);
+    gpr_mu_lock(&s->mu);
+    s->nports++;
+    GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
+    sp = gpr_malloc(sizeof(grpc_tcp_listener));
+    sp->next = NULL;
+    if (s->head == NULL) {
+      s->head = sp;
+    } else {
+      s->tail->next = sp;
+    }
+    s->tail = sp;
+    sp->server = s;
+    sp->fd = fd;
+    sp->emfd = grpc_fd_create(fd, name);
+    memcpy(sp->addr.untyped, addr, addr_len);
+    sp->addr_len = addr_len;
+    sp->port = port;
+    sp->port_index = port_index;
+    sp->fd_index = fd_index;
+    sp->is_sibling = 0;
+    sp->sibling = NULL;
+    GPR_ASSERT(sp->emfd);
+    gpr_mu_unlock(&s->mu);
+    gpr_free(addr_str);
+    gpr_free(name);
+  }
+
+  return sp;
+}
+
+int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
+                             size_t addr_len) {
+  grpc_tcp_listener *sp;
+  grpc_tcp_listener *sp2 = NULL;
+  int fd;
+  grpc_dualstack_mode dsmode;
+  struct sockaddr_in6 addr6_v4mapped;
+  struct sockaddr_in wild4;
+  struct sockaddr_in6 wild6;
+  struct sockaddr_in addr4_copy;
+  struct sockaddr *allocated_addr = NULL;
+  struct sockaddr_storage sockname_temp;
+  socklen_t sockname_len;
+  int port;
+  unsigned port_index = 0;
+  unsigned fd_index = 0;
+  if (s->tail != NULL) {
+    port_index = s->tail->port_index + 1;
+  }
+  grpc_unlink_if_unix_domain_socket((struct sockaddr *)addr);
+
+  /* Check if this is a wildcard port, and if so, try to keep the port the same
+     as some previously created listener. */
+  if (grpc_sockaddr_get_port(addr) == 0) {
+    for (sp = s->head; sp; sp = sp->next) {
+      sockname_len = sizeof(sockname_temp);
+      if (0 == getsockname(sp->fd, (struct sockaddr *)&sockname_temp,
+                           &sockname_len)) {
+        port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+        if (port > 0) {
+          allocated_addr = malloc(addr_len);
+          memcpy(allocated_addr, addr, addr_len);
+          grpc_sockaddr_set_port(allocated_addr, port);
+          addr = allocated_addr;
+          break;
+        }
+      }
+    }
+  }
+
+  sp = NULL;
+
+  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
+    addr = (const struct sockaddr *)&addr6_v4mapped;
+    addr_len = sizeof(addr6_v4mapped);
+  }
+
+  /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
+  if (grpc_sockaddr_is_wildcard(addr, &port)) {
+    grpc_sockaddr_make_wildcards(port, &wild4, &wild6);
+
+    /* Try listening on IPv6 first. */
+    addr = (struct sockaddr *)&wild6;
+    addr_len = sizeof(wild6);
+    fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
+    sp = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index);
+    if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
+      goto done;
+    }
+    if (sp != NULL) {
+      ++fd_index;
+    }
+    /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
+    if (port == 0 && sp != NULL) {
+      grpc_sockaddr_set_port((struct sockaddr *)&wild4, sp->port);
+    }
+    addr = (struct sockaddr *)&wild4;
+    addr_len = sizeof(wild4);
+  }
+
+  fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
+  if (fd < 0) {
+    gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
+  } else {
+    if (dsmode == GRPC_DSMODE_IPV4 &&
+        grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
+      addr = (struct sockaddr *)&addr4_copy;
+      addr_len = sizeof(addr4_copy);
+    }
+    sp2 = sp;
+    sp = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index);
+    if (sp2 != NULL && sp != NULL) {
+      sp2->sibling = sp;
+      sp->is_sibling = 1;
+    }
+  }
+
+done:
+  gpr_free(allocated_addr);
+  if (sp != NULL) {
+    return sp->port;
+  } else {
+    return -1;
+  }
+}
+
+unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s,
+                                       unsigned port_index) {
+  unsigned num_fds = 0;
+  grpc_tcp_listener *sp;
+  for (sp = s->head; sp && port_index != 0; sp = sp->next) {
+    if (!sp->is_sibling) {
+      --port_index;
+    }
+  }
+  for (; sp; sp = sp->sibling, ++num_fds)
+    ;
+  return num_fds;
+}
+
+int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index,
+                            unsigned fd_index) {
+  grpc_tcp_listener *sp;
+  for (sp = s->head; sp && port_index != 0; sp = sp->next) {
+    if (!sp->is_sibling) {
+      --port_index;
+    }
+  }
+  for (; sp && fd_index != 0; sp = sp->sibling, --fd_index)
+    ;
+  if (sp) {
+    return sp->fd;
+  } else {
+    return -1;
+  }
+}
+
+void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
+                           grpc_pollset **pollsets, size_t pollset_count,
+                           grpc_tcp_server_cb on_accept_cb,
+                           void *on_accept_cb_arg) {
+  size_t i;
+  grpc_tcp_listener *sp;
+  GPR_ASSERT(on_accept_cb);
+  gpr_mu_lock(&s->mu);
+  GPR_ASSERT(!s->on_accept_cb);
+  GPR_ASSERT(s->active_ports == 0);
+  s->on_accept_cb = on_accept_cb;
+  s->on_accept_cb_arg = on_accept_cb_arg;
+  s->pollsets = pollsets;
+  s->pollset_count = pollset_count;
+  for (sp = s->head; sp; sp = sp->next) {
+    for (i = 0; i < pollset_count; i++) {
+      grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd);
+    }
+    sp->read_closure.cb = on_read;
+    sp->read_closure.cb_arg = sp;
+    grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
+    s->active_ports++;
+  }
+  gpr_mu_unlock(&s->mu);
+}
+
+grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) {
+  gpr_ref(&s->refs);
+  return s;
+}
+
+void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
+                                           grpc_closure *shutdown_starting) {
+  gpr_mu_lock(&s->mu);
+  grpc_closure_list_add(&s->shutdown_starting, shutdown_starting, 1);
+  gpr_mu_unlock(&s->mu);
+}
+
+void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
+  if (gpr_unref(&s->refs)) {
+    /* Complete shutdown_starting work before destroying. */
+    grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT;
+    gpr_mu_lock(&s->mu);
+    grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL);
+    gpr_mu_unlock(&s->mu);
+    if (exec_ctx == NULL) {
+      grpc_exec_ctx_flush(&local_exec_ctx);
+      tcp_server_destroy(&local_exec_ctx, s);
+      grpc_exec_ctx_finish(&local_exec_ctx);
+    } else {
+      grpc_exec_ctx_finish(&local_exec_ctx);
+      tcp_server_destroy(exec_ctx, s);
+    }
+  }
+}
+
+#endif
diff --git a/src/core/lib/iomgr/tcp_server_windows.c b/src/core/lib/iomgr/tcp_server_windows.c
new file mode 100644
index 0000000..3d6a29b
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_server_windows.c
@@ -0,0 +1,557 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINSOCK_SOCKET
+
+#include <io.h>
+
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/log_win32.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/iomgr/iocp_windows.h"
+#include "src/core/lib/iomgr/pollset_windows.h"
+#include "src/core/lib/iomgr/socket_windows.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/iomgr/tcp_windows.h"
+
+#define MIN_SAFE_ACCEPT_QUEUE_SIZE 100
+
+/* one listening port */
+typedef struct grpc_tcp_listener grpc_tcp_listener;
+struct grpc_tcp_listener {
+  /* This seemingly magic number comes from AcceptEx's documentation. each
+     address buffer needs to have at least 16 more bytes at their end. */
+  uint8_t addresses[(sizeof(struct sockaddr_in6) + 16) * 2];
+  /* This will hold the socket for the next accept. */
+  SOCKET new_socket;
+  /* The listener winsocket. */
+  grpc_winsocket *socket;
+  /* The actual TCP port number. */
+  int port;
+  unsigned port_index;
+  grpc_tcp_server *server;
+  /* The cached AcceptEx for that port. */
+  LPFN_ACCEPTEX AcceptEx;
+  int shutting_down;
+  /* closure for socket notification of accept being ready */
+  grpc_closure on_accept;
+  /* linked list */
+  struct grpc_tcp_listener *next;
+};
+
+/* the overall server */
+struct grpc_tcp_server {
+  gpr_refcount refs;
+  /* Called whenever accept() succeeds on a server port. */
+  grpc_tcp_server_cb on_accept_cb;
+  void *on_accept_cb_arg;
+
+  gpr_mu mu;
+
+  /* active port count: how many ports are actually still listening */
+  int active_ports;
+
+  /* linked list of server ports */
+  grpc_tcp_listener *head;
+  grpc_tcp_listener *tail;
+
+  /* List of closures passed to shutdown_starting_add(). */
+  grpc_closure_list shutdown_starting;
+
+  /* shutdown callback */
+  grpc_closure *shutdown_complete;
+};
+
+/* Public function. Allocates the proper data structures to hold a
+   grpc_tcp_server. */
+grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete) {
+  grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
+  gpr_ref_init(&s->refs, 1);
+  gpr_mu_init(&s->mu);
+  s->active_ports = 0;
+  s->on_accept_cb = NULL;
+  s->on_accept_cb_arg = NULL;
+  s->head = NULL;
+  s->tail = NULL;
+  s->shutdown_starting.head = NULL;
+  s->shutdown_starting.tail = NULL;
+  s->shutdown_complete = shutdown_complete;
+  return s;
+}
+
+static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
+  if (s->shutdown_complete != NULL) {
+    grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, true, NULL);
+  }
+
+  /* Now that the accepts have been aborted, we can destroy the sockets.
+     The IOCP won't get notified on these, so we can flag them as already
+     closed by the system. */
+  while (s->head) {
+    grpc_tcp_listener *sp = s->head;
+    s->head = sp->next;
+    sp->next = NULL;
+    grpc_winsocket_destroy(sp->socket);
+    gpr_free(sp);
+  }
+  gpr_free(s);
+}
+
+grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) {
+  gpr_ref(&s->refs);
+  return s;
+}
+
+void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
+                                           grpc_closure *shutdown_starting) {
+  gpr_mu_lock(&s->mu);
+  grpc_closure_list_add(&s->shutdown_starting, shutdown_starting, 1);
+  gpr_mu_unlock(&s->mu);
+}
+
+static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
+  int immediately_done = 0;
+  grpc_tcp_listener *sp;
+  gpr_mu_lock(&s->mu);
+
+  /* First, shutdown all fd's. This will queue abortion calls for all
+     of the pending accepts due to the normal operation mechanism. */
+  if (s->active_ports == 0) {
+    immediately_done = 1;
+  }
+  for (sp = s->head; sp; sp = sp->next) {
+    sp->shutting_down = 1;
+    grpc_winsocket_shutdown(sp->socket);
+  }
+  gpr_mu_unlock(&s->mu);
+
+  if (immediately_done) {
+    finish_shutdown(exec_ctx, s);
+  }
+}
+
+void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
+  if (gpr_unref(&s->refs)) {
+    /* Complete shutdown_starting work before destroying. */
+    grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT;
+    gpr_mu_lock(&s->mu);
+    grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL);
+    gpr_mu_unlock(&s->mu);
+    if (exec_ctx == NULL) {
+      grpc_exec_ctx_flush(&local_exec_ctx);
+      tcp_server_destroy(&local_exec_ctx, s);
+      grpc_exec_ctx_finish(&local_exec_ctx);
+    } else {
+      grpc_exec_ctx_finish(&local_exec_ctx);
+      tcp_server_destroy(exec_ctx, s);
+    }
+  }
+}
+
+/* Prepare (bind) a recently-created socket for listening. */
+static int prepare_socket(SOCKET sock, const struct sockaddr *addr,
+                          size_t addr_len) {
+  struct sockaddr_storage sockname_temp;
+  socklen_t sockname_len;
+
+  if (sock == INVALID_SOCKET) goto error;
+
+  if (!grpc_tcp_prepare_socket(sock)) {
+    char *utf8_message = gpr_format_message(WSAGetLastError());
+    gpr_log(GPR_ERROR, "Unable to prepare socket: %s", utf8_message);
+    gpr_free(utf8_message);
+    goto error;
+  }
+
+  if (bind(sock, addr, (int)addr_len) == SOCKET_ERROR) {
+    char *addr_str;
+    char *utf8_message = gpr_format_message(WSAGetLastError());
+    grpc_sockaddr_to_string(&addr_str, addr, 0);
+    gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, utf8_message);
+    gpr_free(utf8_message);
+    gpr_free(addr_str);
+    goto error;
+  }
+
+  if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
+    char *utf8_message = gpr_format_message(WSAGetLastError());
+    gpr_log(GPR_ERROR, "listen: %s", utf8_message);
+    gpr_free(utf8_message);
+    goto error;
+  }
+
+  sockname_len = sizeof(sockname_temp);
+  if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) ==
+      SOCKET_ERROR) {
+    char *utf8_message = gpr_format_message(WSAGetLastError());
+    gpr_log(GPR_ERROR, "getsockname: %s", utf8_message);
+    gpr_free(utf8_message);
+    goto error;
+  }
+
+  return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+
+error:
+  if (sock != INVALID_SOCKET) closesocket(sock);
+  return -1;
+}
+
+static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
+                                              grpc_tcp_listener *sp) {
+  int notify = 0;
+  sp->shutting_down = 0;
+  gpr_mu_lock(&sp->server->mu);
+  GPR_ASSERT(sp->server->active_ports > 0);
+  if (0 == --sp->server->active_ports) {
+    notify = 1;
+  }
+  gpr_mu_unlock(&sp->server->mu);
+  if (notify) {
+    finish_shutdown(exec_ctx, sp->server);
+  }
+}
+
+/* In order to do an async accept, we need to create a socket first which
+   will be the one assigned to the new incoming connection. */
+static void start_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *port) {
+  SOCKET sock = INVALID_SOCKET;
+  char *message;
+  char *utf8_message;
+  BOOL success;
+  DWORD addrlen = sizeof(struct sockaddr_in6) + 16;
+  DWORD bytes_received = 0;
+
+  sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
+                   WSA_FLAG_OVERLAPPED);
+
+  if (sock == INVALID_SOCKET) {
+    message = "Unable to create socket: %s";
+    goto failure;
+  }
+
+  if (!grpc_tcp_prepare_socket(sock)) {
+    message = "Unable to prepare socket: %s";
+    goto failure;
+  }
+
+  /* Start the "accept" asynchronously. */
+  success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0,
+                           addrlen, addrlen, &bytes_received,
+                           &port->socket->read_info.overlapped);
+
+  /* It is possible to get an accept immediately without delay. However, we
+     will still get an IOCP notification for it. So let's just ignore it. */
+  if (!success) {
+    int error = WSAGetLastError();
+    if (error != ERROR_IO_PENDING) {
+      message = "AcceptEx failed: %s";
+      goto failure;
+    }
+  }
+
+  /* We're ready to do the accept. Calling grpc_socket_notify_on_read may
+     immediately process an accept that happened in the meantime. */
+  port->new_socket = sock;
+  grpc_socket_notify_on_read(exec_ctx, port->socket, &port->on_accept);
+  return;
+
+failure:
+  if (port->shutting_down) {
+    /* We are abandoning the listener port, take that into account to prevent
+       occasional hangs on shutdown. The hang happens when sp->shutting_down
+       change is not seen by on_accept and we proceed to trying new accept,
+       but we fail there because the listening port has been closed in the
+       meantime. */
+    decrement_active_ports_and_notify(exec_ctx, port);
+    return;
+  }
+  utf8_message = gpr_format_message(WSAGetLastError());
+  gpr_log(GPR_ERROR, message, utf8_message);
+  gpr_free(utf8_message);
+  if (sock != INVALID_SOCKET) closesocket(sock);
+}
+
+/* Event manager callback when reads are ready. */
+static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, bool from_iocp) {
+  grpc_tcp_listener *sp = arg;
+  grpc_tcp_server_acceptor acceptor = {sp->server, sp->port_index, 0};
+  SOCKET sock = sp->new_socket;
+  grpc_winsocket_callback_info *info = &sp->socket->read_info;
+  grpc_endpoint *ep = NULL;
+  struct sockaddr_storage peer_name;
+  char *peer_name_string;
+  char *fd_name;
+  int peer_name_len = sizeof(peer_name);
+  DWORD transfered_bytes;
+  DWORD flags;
+  BOOL wsa_success;
+  int err;
+
+  /* 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. We only need to adjust the pending callback count */
+  if (!from_iocp) {
+    return;
+  }
+
+  /* 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 well,
+         and we can wake up the shutdown thread. */
+      decrement_active_ports_and_notify(exec_ctx, sp);
+      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 {
+    if (!sp->shutting_down) {
+      peer_name_string = NULL;
+      err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+                       (char *)&sp->socket->socket, sizeof(sp->socket->socket));
+      if (err) {
+        char *utf8_message = gpr_format_message(WSAGetLastError());
+        gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message);
+        gpr_free(utf8_message);
+      }
+      err = getpeername(sock, (struct sockaddr *)&peer_name, &peer_name_len);
+      if (!err) {
+        peer_name_string = grpc_sockaddr_to_uri((struct sockaddr *)&peer_name);
+      } else {
+        char *utf8_message = gpr_format_message(WSAGetLastError());
+        gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message);
+        gpr_free(utf8_message);
+      }
+      gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string);
+      ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name),
+                           peer_name_string);
+      gpr_free(fd_name);
+      gpr_free(peer_name_string);
+    } else {
+      closesocket(sock);
+    }
+  }
+
+  /* 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->on_accept_cb(exec_ctx, sp->server->on_accept_cb_arg, ep,
+                             &acceptor);
+  /* 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. */
+  start_accept(exec_ctx, sp);
+}
+
+static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
+                                               const struct sockaddr *addr,
+                                               size_t addr_len,
+                                               unsigned port_index) {
+  grpc_tcp_listener *sp = NULL;
+  int port;
+  int status;
+  GUID guid = WSAID_ACCEPTEX;
+  DWORD ioctl_num_bytes;
+  LPFN_ACCEPTEX AcceptEx;
+
+  if (sock == INVALID_SOCKET) return NULL;
+
+  /* We need to grab the AcceptEx pointer for that port, as it may be
+     interface-dependent. We'll cache it to avoid doing that again. */
+  status =
+      WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+               &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL);
+
+  if (status != 0) {
+    char *utf8_message = gpr_format_message(WSAGetLastError());
+    gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
+    gpr_free(utf8_message);
+    closesocket(sock);
+    return NULL;
+  }
+
+  port = prepare_socket(sock, addr, addr_len);
+  if (port >= 0) {
+    gpr_mu_lock(&s->mu);
+    GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
+    sp = gpr_malloc(sizeof(grpc_tcp_listener));
+    sp->next = NULL;
+    if (s->head == NULL) {
+      s->head = sp;
+    } else {
+      s->tail->next = sp;
+    }
+    s->tail = sp;
+    sp->server = s;
+    sp->socket = grpc_winsocket_create(sock, "listener");
+    sp->shutting_down = 0;
+    sp->AcceptEx = AcceptEx;
+    sp->new_socket = INVALID_SOCKET;
+    sp->port = port;
+    sp->port_index = port_index;
+    grpc_closure_init(&sp->on_accept, on_accept, sp);
+    GPR_ASSERT(sp->socket);
+    gpr_mu_unlock(&s->mu);
+  }
+
+  return sp;
+}
+
+int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
+                             size_t addr_len) {
+  grpc_tcp_listener *sp;
+  SOCKET sock;
+  struct sockaddr_in6 addr6_v4mapped;
+  struct sockaddr_in6 wildcard;
+  struct sockaddr *allocated_addr = NULL;
+  struct sockaddr_storage sockname_temp;
+  socklen_t sockname_len;
+  int port;
+  unsigned port_index = 0;
+  if (s->tail != NULL) {
+    port_index = s->tail->port_index + 1;
+  }
+
+  /* Check if this is a wildcard port, and if so, try to keep the port the same
+     as some previously created listener. */
+  if (grpc_sockaddr_get_port(addr) == 0) {
+    for (sp = s->head; sp; sp = sp->next) {
+      sockname_len = sizeof(sockname_temp);
+      if (0 == getsockname(sp->socket->socket,
+                           (struct sockaddr *)&sockname_temp, &sockname_len)) {
+        port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+        if (port > 0) {
+          allocated_addr = malloc(addr_len);
+          memcpy(allocated_addr, addr, addr_len);
+          grpc_sockaddr_set_port(allocated_addr, port);
+          addr = allocated_addr;
+          break;
+        }
+      }
+    }
+  }
+
+  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
+    addr = (const struct sockaddr *)&addr6_v4mapped;
+    addr_len = sizeof(addr6_v4mapped);
+  }
+
+  /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
+  if (grpc_sockaddr_is_wildcard(addr, &port)) {
+    grpc_sockaddr_make_wildcard6(port, &wildcard);
+
+    addr = (struct sockaddr *)&wildcard;
+    addr_len = sizeof(wildcard);
+  }
+
+  sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
+                   WSA_FLAG_OVERLAPPED);
+  if (sock == INVALID_SOCKET) {
+    char *utf8_message = gpr_format_message(WSAGetLastError());
+    gpr_log(GPR_ERROR, "unable to create socket: %s", utf8_message);
+    gpr_free(utf8_message);
+  }
+
+  sp = add_socket_to_server(s, sock, addr, addr_len, port_index);
+  gpr_free(allocated_addr);
+
+  if (sp) {
+    return sp->port;
+  } else {
+    return -1;
+  }
+}
+
+unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s,
+                                       unsigned port_index) {
+  grpc_tcp_listener *sp;
+  for (sp = s->head; sp && port_index != 0; sp = sp->next, --port_index)
+    ;
+  if (sp) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index,
+                            unsigned fd_index) {
+  grpc_tcp_listener *sp;
+  if (fd_index != 0) {
+    /* Windows implementation has only one fd per port_index. */
+    return -1;
+  }
+  for (sp = s->head; sp && port_index != 0; sp = sp->next, --port_index)
+    ;
+  if (sp) {
+    return _open_osfhandle((intptr_t)sp->socket->socket, 0);
+  } else {
+    return -1;
+  }
+}
+
+void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
+                           grpc_pollset **pollset, size_t pollset_count,
+                           grpc_tcp_server_cb on_accept_cb,
+                           void *on_accept_cb_arg) {
+  grpc_tcp_listener *sp;
+  GPR_ASSERT(on_accept_cb);
+  gpr_mu_lock(&s->mu);
+  GPR_ASSERT(!s->on_accept_cb);
+  GPR_ASSERT(s->active_ports == 0);
+  s->on_accept_cb = on_accept_cb;
+  s->on_accept_cb_arg = on_accept_cb_arg;
+  for (sp = s->head; sp; sp = sp->next) {
+    start_accept(exec_ctx, sp);
+    s->active_ports++;
+  }
+  gpr_mu_unlock(&s->mu);
+}
+
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/tcp_windows.c b/src/core/lib/iomgr/tcp_windows.c
new file mode 100644
index 0000000..c1ce725
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_windows.c
@@ -0,0 +1,402 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINSOCK_SOCKET
+
+#include "src/core/lib/iomgr/sockaddr_win32.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/log_win32.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/iomgr/iocp_windows.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/socket_windows.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/iomgr/timer.h"
+
+static int set_non_block(SOCKET sock) {
+  int status;
+  unsigned long param = 1;
+  DWORD ret;
+  status =
+      WSAIoctl(sock, FIONBIO, &param, sizeof(param), NULL, 0, &ret, NULL, NULL);
+  return status == 0;
+}
+
+static int set_dualstack(SOCKET sock) {
+  int status;
+  unsigned long param = 0;
+  status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&param,
+                      sizeof(param));
+  return status == 0;
+}
+
+int grpc_tcp_prepare_socket(SOCKET sock) {
+  if (!set_non_block(sock)) return 0;
+  if (!set_dualstack(sock)) return 0;
+  return 1;
+}
+
+typedef struct grpc_tcp {
+  /* This is our C++ class derivation emulation. */
+  grpc_endpoint base;
+  /* The one socket this endpoint is using. */
+  grpc_winsocket *socket;
+  /* Refcounting how many operations are in progress. */
+  gpr_refcount refcount;
+
+  grpc_closure on_read;
+  grpc_closure on_write;
+
+  grpc_closure *read_cb;
+  grpc_closure *write_cb;
+  gpr_slice read_slice;
+  gpr_slice_buffer *write_slices;
+  gpr_slice_buffer *read_slices;
+
+  /* The IO Completion Port runs from another thread. We need some mechanism
+     to protect ourselves when requesting a shutdown. */
+  gpr_mu mu;
+  int shutting_down;
+
+  char *peer_string;
+} grpc_tcp;
+
+static void tcp_free(grpc_tcp *tcp) {
+  grpc_winsocket_destroy(tcp->socket);
+  gpr_mu_destroy(&tcp->mu);
+  gpr_free(tcp->peer_string);
+  gpr_free(tcp);
+}
+
+/*#define GRPC_TCP_REFCOUNT_DEBUG*/
+#ifdef GRPC_TCP_REFCOUNT_DEBUG
+#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
+#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
+static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file,
+                      int line) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
+          reason, tcp->refcount.count, tcp->refcount.count - 1);
+  if (gpr_unref(&tcp->refcount)) {
+    tcp_free(tcp);
+  }
+}
+
+static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
+                    int line) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP   ref %p : %s %d -> %d", tcp,
+          reason, tcp->refcount.count, tcp->refcount.count + 1);
+  gpr_ref(&tcp->refcount);
+}
+#else
+#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
+#define TCP_REF(tcp, reason) tcp_ref((tcp))
+static void tcp_unref(grpc_tcp *tcp) {
+  if (gpr_unref(&tcp->refcount)) {
+    tcp_free(tcp);
+  }
+}
+
+static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
+#endif
+
+/* Asynchronous callback from the IOCP, or the background thread. */
+static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) {
+  grpc_tcp *tcp = tcpp;
+  grpc_closure *cb = tcp->read_cb;
+  grpc_winsocket *socket = tcp->socket;
+  gpr_slice sub;
+  grpc_winsocket_callback_info *info = &socket->read_info;
+
+  if (success) {
+    if (info->wsa_error != 0 && !tcp->shutting_down) {
+      if (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);
+      }
+      success = 0;
+      gpr_slice_unref(tcp->read_slice);
+    } else {
+      if (info->bytes_transfered != 0 && !tcp->shutting_down) {
+        sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
+        gpr_slice_buffer_add(tcp->read_slices, sub);
+        success = 1;
+      } else {
+        gpr_slice_unref(tcp->read_slice);
+        success = 0;
+      }
+    }
+  }
+
+  tcp->read_cb = NULL;
+  TCP_UNREF(tcp, "read");
+  if (cb) {
+    cb->cb(exec_ctx, cb->cb_arg, success);
+  }
+}
+
+static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                     gpr_slice_buffer *read_slices, grpc_closure *cb) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  grpc_winsocket *handle = tcp->socket;
+  grpc_winsocket_callback_info *info = &handle->read_info;
+  int status;
+  DWORD bytes_read = 0;
+  DWORD flags = 0;
+  WSABUF buffer;
+
+  if (tcp->shutting_down) {
+    grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
+    return;
+  }
+
+  tcp->read_cb = cb;
+  tcp->read_slices = read_slices;
+  gpr_slice_buffer_reset_and_unref(read_slices);
+
+  tcp->read_slice = gpr_slice_malloc(8192);
+
+  buffer.len = (ULONG)GPR_SLICE_LENGTH(
+      tcp->read_slice);  // we know slice size fits in 32bit.
+  buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
+
+  TCP_REF(tcp, "read");
+
+  /* First let's try a synchronous, non-blocking read. */
+  status =
+      WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, NULL, NULL);
+  info->wsa_error = status == 0 ? 0 : WSAGetLastError();
+
+  /* Did we get data immediately ? Yay. */
+  if (info->wsa_error != WSAEWOULDBLOCK) {
+    info->bytes_transfered = bytes_read;
+    grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, true, NULL);
+    return;
+  }
+
+  /* Otherwise, let's retry, by queuing a read. */
+  memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
+  status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
+                   &info->overlapped, NULL);
+
+  if (status != 0) {
+    int wsa_error = WSAGetLastError();
+    if (wsa_error != WSA_IO_PENDING) {
+      info->wsa_error = wsa_error;
+      grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, false, NULL);
+      return;
+    }
+  }
+
+  grpc_socket_notify_on_read(exec_ctx, tcp->socket, &tcp->on_read);
+}
+
+/* Asynchronous callback from the IOCP, or the background thread. */
+static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) {
+  grpc_tcp *tcp = (grpc_tcp *)tcpp;
+  grpc_winsocket *handle = tcp->socket;
+  grpc_winsocket_callback_info *info = &handle->write_info;
+  grpc_closure *cb;
+
+  gpr_mu_lock(&tcp->mu);
+  cb = tcp->write_cb;
+  tcp->write_cb = NULL;
+  gpr_mu_unlock(&tcp->mu);
+
+  if (success) {
+    if (info->wsa_error != 0) {
+      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);
+      }
+      success = 0;
+    } else {
+      GPR_ASSERT(info->bytes_transfered == tcp->write_slices->length);
+    }
+  }
+
+  TCP_UNREF(tcp, "write");
+  cb->cb(exec_ctx, cb->cb_arg, success);
+}
+
+/* Initiates a write. */
+static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                      gpr_slice_buffer *slices, grpc_closure *cb) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  grpc_winsocket *socket = tcp->socket;
+  grpc_winsocket_callback_info *info = &socket->write_info;
+  unsigned i;
+  DWORD bytes_sent;
+  int status;
+  WSABUF local_buffers[16];
+  WSABUF *allocated = NULL;
+  WSABUF *buffers = local_buffers;
+  size_t len;
+
+  if (tcp->shutting_down) {
+    grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
+    return;
+  }
+
+  tcp->write_cb = cb;
+  tcp->write_slices = slices;
+  GPR_ASSERT(tcp->write_slices->count <= UINT_MAX);
+  if (tcp->write_slices->count > GPR_ARRAY_SIZE(local_buffers)) {
+    buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices->count);
+    allocated = buffers;
+  }
+
+  for (i = 0; i < tcp->write_slices->count; i++) {
+    len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]);
+    GPR_ASSERT(len <= ULONG_MAX);
+    buffers[i].len = (ULONG)len;
+    buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices->slices[i]);
+  }
+
+  /* First, let's try a synchronous, non-blocking write. */
+  status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
+                   &bytes_sent, 0, NULL, NULL);
+  info->wsa_error = status == 0 ? 0 : WSAGetLastError();
+
+  /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
+     connection that has its send queue filled up. But if we don't, then we can
+     avoid doing an async write operation at all. */
+  if (info->wsa_error != WSAEWOULDBLOCK) {
+    bool ok = false;
+    if (status == 0) {
+      ok = true;
+      GPR_ASSERT(bytes_sent == tcp->write_slices->length);
+    } else {
+      if (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);
+    grpc_exec_ctx_enqueue(exec_ctx, cb, ok, NULL);
+    return;
+  }
+
+  TCP_REF(tcp, "write");
+
+  /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
+     operation, this time asynchronously. */
+  memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
+  status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
+                   &bytes_sent, 0, &socket->write_info.overlapped, NULL);
+  if (allocated) gpr_free(allocated);
+
+  if (status != 0) {
+    int wsa_error = WSAGetLastError();
+    if (wsa_error != WSA_IO_PENDING) {
+      TCP_UNREF(tcp, "write");
+      grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
+      return;
+    }
+  }
+
+  /* As all is now setup, we can now ask for the IOCP notification. It may
+     trigger the callback immediately however, but no matter. */
+  grpc_socket_notify_on_write(exec_ctx, socket, &tcp->on_write);
+}
+
+static void win_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                               grpc_pollset *ps) {
+  grpc_tcp *tcp;
+  (void)ps;
+  tcp = (grpc_tcp *)ep;
+  grpc_iocp_add_socket(tcp->socket);
+}
+
+static void win_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
+                                   grpc_pollset_set *pss) {
+  grpc_tcp *tcp;
+  (void)pss;
+  tcp = (grpc_tcp *)ep;
+  grpc_iocp_add_socket(tcp->socket);
+}
+
+/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks
+   for the potential read and write operations. It is up to the caller to
+   guarantee this isn't called in parallel to a read or write request, so
+   we're not going to protect against these. However the IO Completion Port
+   callback will happen from another thread, so we need to protect against
+   concurrent access of the data structure in that regard. */
+static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  gpr_mu_lock(&tcp->mu);
+  /* At that point, what may happen is that we're already inside the IOCP
+     callback. See the comments in on_read and on_write. */
+  tcp->shutting_down = 1;
+  grpc_winsocket_shutdown(tcp->socket);
+  gpr_mu_unlock(&tcp->mu);
+}
+
+static void win_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  TCP_UNREF(tcp, "destroy");
+}
+
+static char *win_get_peer(grpc_endpoint *ep) {
+  grpc_tcp *tcp = (grpc_tcp *)ep;
+  return gpr_strdup(tcp->peer_string);
+}
+
+static grpc_endpoint_vtable vtable = {
+    win_read,     win_write,   win_add_to_pollset, win_add_to_pollset_set,
+    win_shutdown, win_destroy, win_get_peer};
+
+grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
+  grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
+  memset(tcp, 0, sizeof(grpc_tcp));
+  tcp->base.vtable = &vtable;
+  tcp->socket = socket;
+  gpr_mu_init(&tcp->mu);
+  gpr_ref_init(&tcp->refcount, 1);
+  grpc_closure_init(&tcp->on_read, on_read, tcp);
+  grpc_closure_init(&tcp->on_write, on_write, tcp);
+  tcp->peer_string = gpr_strdup(peer_string);
+  return &tcp->base;
+}
+
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/tcp_windows.h b/src/core/lib/iomgr/tcp_windows.h
new file mode 100644
index 0000000..7a9ebd8
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_windows.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_TCP_WINDOWS_H
+#define GRPC_CORE_LIB_IOMGR_TCP_WINDOWS_H
+/*
+   Low level TCP "bottom half" implementation, for use by transports built on
+   top of a TCP connection.
+
+   Note that this file does not (yet) include APIs for creating the socket in
+   the first place.
+
+   All calls passing slice transfer ownership of a slice refcount unless
+   otherwise specified.
+*/
+
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/socket_windows.h"
+
+/* Create a tcp endpoint given a winsock handle.
+ * Takes ownership of the handle.
+ */
+grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string);
+
+int grpc_tcp_prepare_socket(SOCKET sock);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TCP_WINDOWS_H */
diff --git a/src/core/lib/iomgr/time_averaged_stats.c b/src/core/lib/iomgr/time_averaged_stats.c
new file mode 100644
index 0000000..f24d680
--- /dev/null
+++ b/src/core/lib/iomgr/time_averaged_stats.c
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/time_averaged_stats.h"
+
+void grpc_time_averaged_stats_init(grpc_time_averaged_stats* stats,
+                                   double init_avg, double regress_weight,
+                                   double persistence_factor) {
+  stats->init_avg = init_avg;
+  stats->regress_weight = regress_weight;
+  stats->persistence_factor = persistence_factor;
+  stats->batch_total_value = 0;
+  stats->batch_num_samples = 0;
+  stats->aggregate_total_weight = 0;
+  stats->aggregate_weighted_avg = init_avg;
+}
+
+void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats* stats,
+                                         double value) {
+  stats->batch_total_value += value;
+  ++stats->batch_num_samples;
+}
+
+double grpc_time_averaged_stats_update_average(
+    grpc_time_averaged_stats* stats) {
+  /* Start with the current batch: */
+  double weighted_sum = stats->batch_total_value;
+  double total_weight = stats->batch_num_samples;
+  if (stats->regress_weight > 0) {
+    /* Add in the regression towards init_avg_: */
+    weighted_sum += stats->regress_weight * stats->init_avg;
+    total_weight += stats->regress_weight;
+  }
+  if (stats->persistence_factor > 0) {
+    /* Add in the persistence: */
+    const double prev_sample_weight =
+        stats->persistence_factor * stats->aggregate_total_weight;
+    weighted_sum += prev_sample_weight * stats->aggregate_weighted_avg;
+    total_weight += prev_sample_weight;
+  }
+  stats->aggregate_weighted_avg =
+      (total_weight > 0) ? (weighted_sum / total_weight) : stats->init_avg;
+  stats->aggregate_total_weight = total_weight;
+  stats->batch_num_samples = 0;
+  stats->batch_total_value = 0;
+  return stats->aggregate_weighted_avg;
+}
diff --git a/src/core/lib/iomgr/time_averaged_stats.h b/src/core/lib/iomgr/time_averaged_stats.h
new file mode 100644
index 0000000..4a662e1
--- /dev/null
+++ b/src/core/lib/iomgr/time_averaged_stats.h
@@ -0,0 +1,88 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_TIME_AVERAGED_STATS_H
+#define GRPC_CORE_LIB_IOMGR_TIME_AVERAGED_STATS_H
+
+/* This tracks a time-decaying weighted average.  It works by collecting
+   batches of samples and then mixing their average into a time-decaying
+   weighted mean.  It is designed for batch operations where we do many adds
+   before updating the average. */
+
+typedef struct {
+  /* The initial average value.  This is the reported average until the first
+     grpc_time_averaged_stats_update_average call.  If a positive regress_weight
+     is used, we also regress towards this value on each update. */
+  double init_avg;
+  /* The sample weight of "init_avg" that is mixed in with each call to
+     grpc_time_averaged_stats_update_average.  If the calls to
+     grpc_time_averaged_stats_add_sample stop, this will cause the average to
+     regress back to the mean.  This should be non-negative.  Set it to 0 to
+     disable the bias.  A value of 1 has the effect of adding in 1 bonus sample
+     with value init_avg to each sample period. */
+  double regress_weight;
+  /* This determines the rate of decay of the time-averaging from one period
+     to the next by scaling the aggregate_total_weight of samples from prior
+     periods when combining with the latest period.  It should be in the range
+     [0,1].  A higher value adapts more slowly.  With a value of 0.5, if the
+     batches each have k samples, the samples_in_avg_ will grow to 2 k, so the
+     weighting of the time average will eventually be 1/3 new batch and 2/3
+     old average. */
+  double persistence_factor;
+
+  /* The total value of samples since the last UpdateAverage(). */
+  double batch_total_value;
+  /* The number of samples since the last UpdateAverage(). */
+  double batch_num_samples;
+  /* The time-decayed sum of batch_num_samples_ over previous batches.  This is
+     the "weight" of the old aggregate_weighted_avg_ when updating the
+     average. */
+  double aggregate_total_weight;
+  /* A time-decayed average of the (batch_total_value_ / batch_num_samples_),
+     computed by decaying the samples_in_avg_ weight in the weighted average. */
+  double aggregate_weighted_avg;
+} grpc_time_averaged_stats;
+
+/* See the comments on the members above for an explanation of init_avg,
+   regress_weight, and persistence_factor. */
+void grpc_time_averaged_stats_init(grpc_time_averaged_stats* stats,
+                                   double init_avg, double regress_weight,
+                                   double persistence_factor);
+/* Add a sample to the current batch. */
+void grpc_time_averaged_stats_add_sample(grpc_time_averaged_stats* stats,
+                                         double value);
+/* Complete a batch and compute the new estimate of the average sample
+   value. */
+double grpc_time_averaged_stats_update_average(grpc_time_averaged_stats* stats);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TIME_AVERAGED_STATS_H */
diff --git a/src/core/lib/iomgr/timer.c b/src/core/lib/iomgr/timer.c
new file mode 100644
index 0000000..4748f9b
--- /dev/null
+++ b/src/core/lib/iomgr/timer.c
@@ -0,0 +1,356 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/timer.h"
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/iomgr/time_averaged_stats.h"
+#include "src/core/lib/iomgr/timer_heap.h"
+
+#define INVALID_HEAP_INDEX 0xffffffffu
+
+#define LOG2_NUM_SHARDS 5
+#define NUM_SHARDS (1 << LOG2_NUM_SHARDS)
+#define ADD_DEADLINE_SCALE 0.33
+#define MIN_QUEUE_WINDOW_DURATION 0.01
+#define MAX_QUEUE_WINDOW_DURATION 1
+
+typedef struct {
+  gpr_mu mu;
+  grpc_time_averaged_stats stats;
+  /* All and only timers with deadlines <= this will be in the heap. */
+  gpr_timespec queue_deadline_cap;
+  gpr_timespec min_deadline;
+  /* Index in the g_shard_queue */
+  uint32_t shard_queue_index;
+  /* This holds all timers with deadlines < queue_deadline_cap. Timers in this
+     list have the top bit of their deadline set to 0. */
+  grpc_timer_heap heap;
+  /* This holds timers whose deadline is >= queue_deadline_cap. */
+  grpc_timer list;
+} shard_type;
+
+/* Protects g_shard_queue */
+static gpr_mu g_mu;
+/* Allow only one run_some_expired_timers at once */
+static gpr_mu g_checker_mu;
+static gpr_clock_type g_clock_type;
+static shard_type g_shards[NUM_SHARDS];
+/* Protected by g_mu */
+static shard_type *g_shard_queue[NUM_SHARDS];
+
+static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
+                                   gpr_timespec *next, int success);
+
+static gpr_timespec compute_min_deadline(shard_type *shard) {
+  return grpc_timer_heap_is_empty(&shard->heap)
+             ? shard->queue_deadline_cap
+             : grpc_timer_heap_top(&shard->heap)->deadline;
+}
+
+void grpc_timer_list_init(gpr_timespec now) {
+  uint32_t i;
+
+  gpr_mu_init(&g_mu);
+  gpr_mu_init(&g_checker_mu);
+  g_clock_type = now.clock_type;
+
+  for (i = 0; i < NUM_SHARDS; i++) {
+    shard_type *shard = &g_shards[i];
+    gpr_mu_init(&shard->mu);
+    grpc_time_averaged_stats_init(&shard->stats, 1.0 / ADD_DEADLINE_SCALE, 0.1,
+                                  0.5);
+    shard->queue_deadline_cap = now;
+    shard->shard_queue_index = i;
+    grpc_timer_heap_init(&shard->heap);
+    shard->list.next = shard->list.prev = &shard->list;
+    shard->min_deadline = compute_min_deadline(shard);
+    g_shard_queue[i] = shard;
+  }
+}
+
+void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx) {
+  int i;
+  run_some_expired_timers(exec_ctx, gpr_inf_future(g_clock_type), NULL, 0);
+  for (i = 0; i < NUM_SHARDS; i++) {
+    shard_type *shard = &g_shards[i];
+    gpr_mu_destroy(&shard->mu);
+    grpc_timer_heap_destroy(&shard->heap);
+  }
+  gpr_mu_destroy(&g_mu);
+  gpr_mu_destroy(&g_checker_mu);
+}
+
+/* This is a cheap, but good enough, pointer hash for sharding the tasks: */
+static size_t shard_idx(const grpc_timer *info) {
+  size_t x = (size_t)info;
+  return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) & (NUM_SHARDS - 1);
+}
+
+static double ts_to_dbl(gpr_timespec ts) {
+  return (double)ts.tv_sec + 1e-9 * ts.tv_nsec;
+}
+
+static gpr_timespec dbl_to_ts(double d) {
+  gpr_timespec ts;
+  ts.tv_sec = (int64_t)d;
+  ts.tv_nsec = (int32_t)(1e9 * (d - (double)ts.tv_sec));
+  ts.clock_type = GPR_TIMESPAN;
+  return ts;
+}
+
+static void list_join(grpc_timer *head, grpc_timer *timer) {
+  timer->next = head;
+  timer->prev = head->prev;
+  timer->next->prev = timer->prev->next = timer;
+}
+
+static void list_remove(grpc_timer *timer) {
+  timer->next->prev = timer->prev;
+  timer->prev->next = timer->next;
+}
+
+static void swap_adjacent_shards_in_queue(uint32_t first_shard_queue_index) {
+  shard_type *temp;
+  temp = g_shard_queue[first_shard_queue_index];
+  g_shard_queue[first_shard_queue_index] =
+      g_shard_queue[first_shard_queue_index + 1];
+  g_shard_queue[first_shard_queue_index + 1] = temp;
+  g_shard_queue[first_shard_queue_index]->shard_queue_index =
+      first_shard_queue_index;
+  g_shard_queue[first_shard_queue_index + 1]->shard_queue_index =
+      first_shard_queue_index + 1;
+}
+
+static void note_deadline_change(shard_type *shard) {
+  while (shard->shard_queue_index > 0 &&
+         gpr_time_cmp(
+             shard->min_deadline,
+             g_shard_queue[shard->shard_queue_index - 1]->min_deadline) < 0) {
+    swap_adjacent_shards_in_queue(shard->shard_queue_index - 1);
+  }
+  while (shard->shard_queue_index < NUM_SHARDS - 1 &&
+         gpr_time_cmp(
+             shard->min_deadline,
+             g_shard_queue[shard->shard_queue_index + 1]->min_deadline) > 0) {
+    swap_adjacent_shards_in_queue(shard->shard_queue_index);
+  }
+}
+
+void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
+                     gpr_timespec deadline, grpc_iomgr_cb_func timer_cb,
+                     void *timer_cb_arg, gpr_timespec now) {
+  int is_first_timer = 0;
+  shard_type *shard = &g_shards[shard_idx(timer)];
+  GPR_ASSERT(deadline.clock_type == g_clock_type);
+  GPR_ASSERT(now.clock_type == g_clock_type);
+  grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg);
+  timer->deadline = deadline;
+  timer->triggered = 0;
+
+  /* TODO(ctiller): check deadline expired */
+
+  gpr_mu_lock(&shard->mu);
+  grpc_time_averaged_stats_add_sample(&shard->stats,
+                                      ts_to_dbl(gpr_time_sub(deadline, now)));
+  if (gpr_time_cmp(deadline, shard->queue_deadline_cap) < 0) {
+    is_first_timer = grpc_timer_heap_add(&shard->heap, timer);
+  } else {
+    timer->heap_index = INVALID_HEAP_INDEX;
+    list_join(&shard->list, timer);
+  }
+  gpr_mu_unlock(&shard->mu);
+
+  /* Deadline may have decreased, we need to adjust the master queue.  Note
+     that there is a potential racy unlocked region here.  There could be a
+     reordering of multiple grpc_timer_init calls, at this point, but the < test
+     below should ensure that we err on the side of caution.  There could
+     also be a race with grpc_timer_check, which might beat us to the lock.  In
+     that case, it is possible that the timer that we added will have already
+     run by the time we hold the lock, but that too is a safe error.
+     Finally, it's possible that the grpc_timer_check that intervened failed to
+     trigger the new timer because the min_deadline hadn't yet been reduced.
+     In that case, the timer will simply have to wait for the next
+     grpc_timer_check. */
+  if (is_first_timer) {
+    gpr_mu_lock(&g_mu);
+    if (gpr_time_cmp(deadline, shard->min_deadline) < 0) {
+      gpr_timespec old_min_deadline = g_shard_queue[0]->min_deadline;
+      shard->min_deadline = deadline;
+      note_deadline_change(shard);
+      if (shard->shard_queue_index == 0 &&
+          gpr_time_cmp(deadline, old_min_deadline) < 0) {
+        grpc_kick_poller();
+      }
+    }
+    gpr_mu_unlock(&g_mu);
+  }
+}
+
+void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) {
+  shard_type *shard = &g_shards[shard_idx(timer)];
+  gpr_mu_lock(&shard->mu);
+  if (!timer->triggered) {
+    grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, false, NULL);
+    timer->triggered = 1;
+    if (timer->heap_index == INVALID_HEAP_INDEX) {
+      list_remove(timer);
+    } else {
+      grpc_timer_heap_remove(&shard->heap, timer);
+    }
+  }
+  gpr_mu_unlock(&shard->mu);
+}
+
+/* This is called when the queue is empty and "now" has reached the
+   queue_deadline_cap.  We compute a new queue deadline and then scan the map
+   for timers that fall at or under it.  Returns true if the queue is no
+   longer empty.
+   REQUIRES: shard->mu locked */
+static int refill_queue(shard_type *shard, gpr_timespec now) {
+  /* Compute the new queue window width and bound by the limits: */
+  double computed_deadline_delta =
+      grpc_time_averaged_stats_update_average(&shard->stats) *
+      ADD_DEADLINE_SCALE;
+  double deadline_delta =
+      GPR_CLAMP(computed_deadline_delta, MIN_QUEUE_WINDOW_DURATION,
+                MAX_QUEUE_WINDOW_DURATION);
+  grpc_timer *timer, *next;
+
+  /* Compute the new cap and put all timers under it into the queue: */
+  shard->queue_deadline_cap = gpr_time_add(
+      gpr_time_max(now, shard->queue_deadline_cap), dbl_to_ts(deadline_delta));
+  for (timer = shard->list.next; timer != &shard->list; timer = next) {
+    next = timer->next;
+
+    if (gpr_time_cmp(timer->deadline, shard->queue_deadline_cap) < 0) {
+      list_remove(timer);
+      grpc_timer_heap_add(&shard->heap, timer);
+    }
+  }
+  return !grpc_timer_heap_is_empty(&shard->heap);
+}
+
+/* This pops the next non-cancelled timer with deadline <= now from the queue,
+   or returns NULL if there isn't one.
+   REQUIRES: shard->mu locked */
+static grpc_timer *pop_one(shard_type *shard, gpr_timespec now) {
+  grpc_timer *timer;
+  for (;;) {
+    if (grpc_timer_heap_is_empty(&shard->heap)) {
+      if (gpr_time_cmp(now, shard->queue_deadline_cap) < 0) return NULL;
+      if (!refill_queue(shard, now)) return NULL;
+    }
+    timer = grpc_timer_heap_top(&shard->heap);
+    if (gpr_time_cmp(timer->deadline, now) > 0) return NULL;
+    timer->triggered = 1;
+    grpc_timer_heap_pop(&shard->heap);
+    return timer;
+  }
+}
+
+/* REQUIRES: shard->mu unlocked */
+static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard,
+                         gpr_timespec now, gpr_timespec *new_min_deadline,
+                         int success) {
+  size_t n = 0;
+  grpc_timer *timer;
+  gpr_mu_lock(&shard->mu);
+  while ((timer = pop_one(shard, now))) {
+    grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, success, NULL);
+    n++;
+  }
+  *new_min_deadline = compute_min_deadline(shard);
+  gpr_mu_unlock(&shard->mu);
+  return n;
+}
+
+static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
+                                   gpr_timespec *next, int success) {
+  size_t n = 0;
+
+  /* TODO(ctiller): verify that there are any timers (atomically) here */
+
+  if (gpr_mu_trylock(&g_checker_mu)) {
+    gpr_mu_lock(&g_mu);
+
+    while (gpr_time_cmp(g_shard_queue[0]->min_deadline, now) < 0) {
+      gpr_timespec new_min_deadline;
+
+      /* For efficiency, we pop as many available timers as we can from the
+         shard.  This may violate perfect timer deadline ordering, but that
+         shouldn't be a big deal because we don't make ordering guarantees. */
+      n += pop_timers(exec_ctx, g_shard_queue[0], now, &new_min_deadline,
+                      success);
+
+      /* An grpc_timer_init() on the shard could intervene here, adding a new
+         timer that is earlier than new_min_deadline.  However,
+         grpc_timer_init() will block on the master_lock before it can call
+         set_min_deadline, so this one will complete first and then the Addtimer
+         will reduce the min_deadline (perhaps unnecessarily). */
+      g_shard_queue[0]->min_deadline = new_min_deadline;
+      note_deadline_change(g_shard_queue[0]);
+    }
+
+    if (next) {
+      *next = gpr_time_min(*next, g_shard_queue[0]->min_deadline);
+    }
+
+    gpr_mu_unlock(&g_mu);
+    gpr_mu_unlock(&g_checker_mu);
+  } else if (next != NULL) {
+    /* TODO(ctiller): this forces calling code to do an short poll, and
+       then retry the timer check (because this time through the timer list was
+       contended).
+
+       We could reduce the cost here dramatically by keeping a count of how many
+       currently active pollers got through the uncontended case above
+       successfully, and waking up other pollers IFF that count drops to zero.
+
+       Once that count is in place, this entire else branch could disappear. */
+    *next = gpr_time_min(
+        *next, gpr_time_add(now, gpr_time_from_millis(1, GPR_TIMESPAN)));
+  }
+
+  return (int)n;
+}
+
+bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now,
+                      gpr_timespec *next) {
+  GPR_ASSERT(now.clock_type == g_clock_type);
+  return run_some_expired_timers(
+      exec_ctx, now, next,
+      gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0);
+}
diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h
new file mode 100644
index 0000000..54f301c
--- /dev/null
+++ b/src/core/lib/iomgr/timer.h
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_TIMER_H
+#define GRPC_CORE_LIB_IOMGR_TIMER_H
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/time.h>
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/iomgr.h"
+
+typedef struct grpc_timer {
+  gpr_timespec deadline;
+  uint32_t heap_index; /* INVALID_HEAP_INDEX if not in heap */
+  int triggered;
+  struct grpc_timer *next;
+  struct grpc_timer *prev;
+  grpc_closure closure;
+} grpc_timer;
+
+/* Initialize *timer. When expired or canceled, timer_cb will be called with
+   *timer_cb_arg and status to indicate if it expired (SUCCESS) or was
+   canceled (CANCELLED). timer_cb is guaranteed to be called exactly once,
+   and application code should check the status to determine how it was
+   invoked. The application callback is also responsible for maintaining
+   information about when to free up any user-level state. */
+void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
+                     gpr_timespec deadline, grpc_iomgr_cb_func timer_cb,
+                     void *timer_cb_arg, gpr_timespec now);
+
+/* Note that there is no timer destroy function. This is because the
+   timer is a one-time occurrence with a guarantee that the callback will
+   be called exactly once, either at expiration or cancellation. Thus, all
+   the internal timer event management state is destroyed just before
+   that callback is invoked. If the user has additional state associated with
+   the timer, the user is responsible for determining when it is safe to
+   destroy that state. */
+
+/* Cancel an *timer.
+   There are three cases:
+   1. We normally cancel the timer
+   2. The timer has already run
+   3. We can't cancel the timer because it is "in flight".
+
+   In all of these cases, the cancellation is still considered successful.
+   They are essentially distinguished in that the timer_cb will be run
+   exactly once from either the cancellation (with status CANCELLED)
+   or from the activation (with status SUCCESS)
+
+   Note carefully that the callback function MAY occur in the same callstack
+   as grpc_timer_cancel. It's expected that most timers will be cancelled (their
+   primary use is to implement deadlines), and so this code is optimized such
+   that cancellation costs as little as possible. Making callbacks run inline
+   matches this aim.
+
+   Requires:  cancel() must happen after add() on a given timer */
+void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer);
+
+/* iomgr internal api for dealing with timers */
+
+/* Check for timers to be run, and run them.
+   Return true if timer callbacks were executed.
+   Drops drop_mu if it is non-null before executing callbacks.
+   If next is non-null, TRY to update *next with the next running timer
+   IF that timer occurs before *next current value.
+   *next is never guaranteed to be updated on any given execution; however,
+   with high probability at least one thread in the system will see an update
+   at any time slice. */
+bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now,
+                      gpr_timespec *next);
+void grpc_timer_list_init(gpr_timespec now);
+void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx);
+
+/* the following must be implemented by each iomgr implementation */
+
+void grpc_kick_poller(void);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TIMER_H */
diff --git a/src/core/lib/iomgr/timer_heap.c b/src/core/lib/iomgr/timer_heap.c
new file mode 100644
index 0000000..d43b6cc
--- /dev/null
+++ b/src/core/lib/iomgr/timer_heap.c
@@ -0,0 +1,146 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/timer_heap.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/useful.h>
+
+/* Adjusts a heap so as to move a hole at position i closer to the root,
+   until a suitable position is found for element t. Then, copies t into that
+   position. This functor is called each time immediately after modifying a
+   value in the underlying container, with the offset of the modified element as
+   its argument. */
+static void adjust_upwards(grpc_timer **first, uint32_t i, grpc_timer *t) {
+  while (i > 0) {
+    uint32_t parent = (uint32_t)(((int)i - 1) / 2);
+    if (gpr_time_cmp(first[parent]->deadline, t->deadline) <= 0) break;
+    first[i] = first[parent];
+    first[i]->heap_index = i;
+    i = parent;
+  }
+  first[i] = t;
+  t->heap_index = i;
+}
+
+/* Adjusts a heap so as to move a hole at position i farther away from the root,
+   until a suitable position is found for element t.  Then, copies t into that
+   position. */
+static void adjust_downwards(grpc_timer **first, uint32_t i, uint32_t length,
+                             grpc_timer *t) {
+  for (;;) {
+    uint32_t left_child = 1u + 2u * i;
+    if (left_child >= length) break;
+    uint32_t right_child = left_child + 1;
+    uint32_t next_i = right_child < length &&
+                              gpr_time_cmp(first[left_child]->deadline,
+                                           first[right_child]->deadline) > 0
+                          ? right_child
+                          : left_child;
+    if (gpr_time_cmp(t->deadline, first[next_i]->deadline) <= 0) break;
+    first[i] = first[next_i];
+    first[i]->heap_index = i;
+    i = next_i;
+  }
+  first[i] = t;
+  t->heap_index = i;
+}
+
+#define SHRINK_MIN_ELEMS 8
+#define SHRINK_FULLNESS_FACTOR 2
+
+static void maybe_shrink(grpc_timer_heap *heap) {
+  if (heap->timer_count >= 8 &&
+      heap->timer_count <= heap->timer_capacity / SHRINK_FULLNESS_FACTOR / 2) {
+    heap->timer_capacity = heap->timer_count * SHRINK_FULLNESS_FACTOR;
+    heap->timers =
+        gpr_realloc(heap->timers, heap->timer_capacity * sizeof(grpc_timer *));
+  }
+}
+
+static void note_changed_priority(grpc_timer_heap *heap, grpc_timer *timer) {
+  uint32_t i = timer->heap_index;
+  uint32_t parent = (uint32_t)(((int)i - 1) / 2);
+  if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) > 0) {
+    adjust_upwards(heap->timers, i, timer);
+  } else {
+    adjust_downwards(heap->timers, i, heap->timer_count, timer);
+  }
+}
+
+void grpc_timer_heap_init(grpc_timer_heap *heap) {
+  memset(heap, 0, sizeof(*heap));
+}
+
+void grpc_timer_heap_destroy(grpc_timer_heap *heap) { gpr_free(heap->timers); }
+
+int grpc_timer_heap_add(grpc_timer_heap *heap, grpc_timer *timer) {
+  if (heap->timer_count == heap->timer_capacity) {
+    heap->timer_capacity =
+        GPR_MAX(heap->timer_capacity + 1, heap->timer_capacity * 3 / 2);
+    heap->timers =
+        gpr_realloc(heap->timers, heap->timer_capacity * sizeof(grpc_timer *));
+  }
+  timer->heap_index = heap->timer_count;
+  adjust_upwards(heap->timers, heap->timer_count, timer);
+  heap->timer_count++;
+  return timer->heap_index == 0;
+}
+
+void grpc_timer_heap_remove(grpc_timer_heap *heap, grpc_timer *timer) {
+  uint32_t i = timer->heap_index;
+  if (i == heap->timer_count - 1) {
+    heap->timer_count--;
+    maybe_shrink(heap);
+    return;
+  }
+  heap->timers[i] = heap->timers[heap->timer_count - 1];
+  heap->timers[i]->heap_index = i;
+  heap->timer_count--;
+  maybe_shrink(heap);
+  note_changed_priority(heap, heap->timers[i]);
+}
+
+int grpc_timer_heap_is_empty(grpc_timer_heap *heap) {
+  return heap->timer_count == 0;
+}
+
+grpc_timer *grpc_timer_heap_top(grpc_timer_heap *heap) {
+  return heap->timers[0];
+}
+
+void grpc_timer_heap_pop(grpc_timer_heap *heap) {
+  grpc_timer_heap_remove(heap, grpc_timer_heap_top(heap));
+}
diff --git a/src/core/lib/iomgr/timer_heap.h b/src/core/lib/iomgr/timer_heap.h
new file mode 100644
index 0000000..d5112cf
--- /dev/null
+++ b/src/core/lib/iomgr/timer_heap.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_TIMER_HEAP_H
+#define GRPC_CORE_LIB_IOMGR_TIMER_HEAP_H
+
+#include "src/core/lib/iomgr/timer.h"
+
+typedef struct {
+  grpc_timer **timers;
+  uint32_t timer_count;
+  uint32_t timer_capacity;
+} grpc_timer_heap;
+
+/* return 1 if the new timer is the first timer in the heap */
+int grpc_timer_heap_add(grpc_timer_heap *heap, grpc_timer *timer);
+
+void grpc_timer_heap_init(grpc_timer_heap *heap);
+void grpc_timer_heap_destroy(grpc_timer_heap *heap);
+
+void grpc_timer_heap_remove(grpc_timer_heap *heap, grpc_timer *timer);
+grpc_timer *grpc_timer_heap_top(grpc_timer_heap *heap);
+void grpc_timer_heap_pop(grpc_timer_heap *heap);
+
+int grpc_timer_heap_is_empty(grpc_timer_heap *heap);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TIMER_HEAP_H */
diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c
new file mode 100644
index 0000000..9068109
--- /dev/null
+++ b/src/core/lib/iomgr/udp_server.c
@@ -0,0 +1,411 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* FIXME: "posix" files shouldn't be depending on _GNU_SOURCE */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GRPC_NEED_UDP
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/lib/iomgr/udp_server.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <grpc/grpc.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/time.h>
+#include "src/core/lib/iomgr/fd_posix.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+#include "src/core/lib/iomgr/unix_sockets_posix.h"
+#include "src/core/lib/support/string.h"
+
+#define INIT_PORT_CAP 2
+
+/* one listening port */
+typedef struct {
+  int fd;
+  grpc_fd *emfd;
+  grpc_udp_server *server;
+  union {
+    uint8_t untyped[GRPC_MAX_SOCKADDR_SIZE];
+    struct sockaddr sockaddr;
+  } addr;
+  size_t addr_len;
+  grpc_closure read_closure;
+  grpc_closure destroyed_closure;
+  grpc_udp_server_read_cb read_cb;
+} server_port;
+
+/* the overall server */
+struct grpc_udp_server {
+  gpr_mu mu;
+  gpr_cv cv;
+
+  /* active port count: how many ports are actually still listening */
+  size_t active_ports;
+  /* destroyed port count: how many ports are completely destroyed */
+  size_t destroyed_ports;
+
+  /* is this server shutting down? (boolean) */
+  int shutdown;
+
+  /* all listening ports */
+  server_port *ports;
+  size_t nports;
+  size_t port_capacity;
+
+  /* shutdown callback */
+  grpc_closure *shutdown_complete;
+
+  /* all pollsets interested in new connections */
+  grpc_pollset **pollsets;
+  /* number of pollsets in the pollsets array */
+  size_t pollset_count;
+  /* The parent grpc server */
+  grpc_server *grpc_server;
+};
+
+grpc_udp_server *grpc_udp_server_create(void) {
+  grpc_udp_server *s = gpr_malloc(sizeof(grpc_udp_server));
+  gpr_mu_init(&s->mu);
+  gpr_cv_init(&s->cv);
+  s->active_ports = 0;
+  s->destroyed_ports = 0;
+  s->shutdown = 0;
+  s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
+  s->nports = 0;
+  s->port_capacity = INIT_PORT_CAP;
+
+  return s;
+}
+
+static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
+  grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1, NULL);
+
+  gpr_mu_destroy(&s->mu);
+  gpr_cv_destroy(&s->cv);
+
+  gpr_free(s->ports);
+  gpr_free(s);
+}
+
+static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server,
+                           bool success) {
+  grpc_udp_server *s = server;
+  gpr_mu_lock(&s->mu);
+  s->destroyed_ports++;
+  if (s->destroyed_ports == s->nports) {
+    gpr_mu_unlock(&s->mu);
+    finish_shutdown(exec_ctx, s);
+  } else {
+    gpr_mu_unlock(&s->mu);
+  }
+}
+
+/* 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_exec_ctx *exec_ctx, grpc_udp_server *s) {
+  size_t i;
+
+  /* delete ALL the things */
+  gpr_mu_lock(&s->mu);
+
+  if (!s->shutdown) {
+    gpr_mu_unlock(&s->mu);
+    return;
+  }
+
+  if (s->nports) {
+    for (i = 0; i < s->nports; i++) {
+      server_port *sp = &s->ports[i];
+      grpc_unlink_if_unix_domain_socket(&sp->addr.sockaddr);
+      sp->destroyed_closure.cb = destroyed_port;
+      sp->destroyed_closure.cb_arg = s;
+      grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
+                     "udp_listener_shutdown");
+    }
+    gpr_mu_unlock(&s->mu);
+  } else {
+    gpr_mu_unlock(&s->mu);
+    finish_shutdown(exec_ctx, s);
+  }
+}
+
+void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
+                             grpc_closure *on_done) {
+  size_t i;
+  gpr_mu_lock(&s->mu);
+
+  GPR_ASSERT(!s->shutdown);
+  s->shutdown = 1;
+
+  s->shutdown_complete = on_done;
+
+  /* shutdown all fd's */
+  if (s->active_ports) {
+    for (i = 0; i < s->nports; i++) {
+      grpc_fd_shutdown(exec_ctx, s->ports[i].emfd);
+    }
+    gpr_mu_unlock(&s->mu);
+  } else {
+    gpr_mu_unlock(&s->mu);
+    deactivated_all_ports(exec_ctx, s);
+  }
+}
+
+/* Prepare a recently-created socket for listening. */
+static int prepare_socket(int fd, const struct sockaddr *addr,
+                          size_t addr_len) {
+  struct sockaddr_storage sockname_temp;
+  socklen_t sockname_len;
+
+  if (fd < 0) {
+    goto error;
+  }
+
+  if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1)) {
+    gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
+            strerror(errno));
+  }
+
+  if (grpc_set_socket_ip_pktinfo_if_possible(fd) &&
+      addr->sa_family == AF_INET6) {
+    grpc_set_socket_ipv6_recvpktinfo_if_possible(fd);
+  }
+
+  GPR_ASSERT(addr_len < ~(socklen_t)0);
+  if (bind(fd, addr, (socklen_t)addr_len) < 0) {
+    char *addr_str;
+    grpc_sockaddr_to_string(&addr_str, addr, 0);
+    gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno));
+    gpr_free(addr_str);
+    goto error;
+  }
+
+  sockname_len = sizeof(sockname_temp);
+  if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) {
+    goto error;
+  }
+
+  return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+
+error:
+  if (fd >= 0) {
+    close(fd);
+  }
+  return -1;
+}
+
+/* event manager callback when reads are ready */
+static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  server_port *sp = arg;
+
+  if (!success) {
+    gpr_mu_lock(&sp->server->mu);
+    if (0 == --sp->server->active_ports) {
+      gpr_mu_unlock(&sp->server->mu);
+      deactivated_all_ports(exec_ctx, sp->server);
+    } else {
+      gpr_mu_unlock(&sp->server->mu);
+    }
+    return;
+  }
+
+  /* Tell the registered callback that data is available to read. */
+  GPR_ASSERT(sp->read_cb);
+  sp->read_cb(exec_ctx, sp->emfd, sp->server->grpc_server);
+
+  /* Re-arm the notification event so we get another chance to read. */
+  grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
+}
+
+static int add_socket_to_server(grpc_udp_server *s, int fd,
+                                const struct sockaddr *addr, size_t addr_len,
+                                grpc_udp_server_read_cb read_cb) {
+  server_port *sp;
+  int port;
+  char *addr_str;
+  char *name;
+
+  port = prepare_socket(fd, addr, addr_len);
+  if (port >= 0) {
+    grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
+    gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
+    gpr_free(addr_str);
+    gpr_mu_lock(&s->mu);
+    /* append it to the list under a lock */
+    if (s->nports == s->port_capacity) {
+      s->port_capacity *= 2;
+      s->ports = gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
+    }
+    sp = &s->ports[s->nports++];
+    sp->server = s;
+    sp->fd = fd;
+    sp->emfd = grpc_fd_create(fd, name);
+    memcpy(sp->addr.untyped, addr, addr_len);
+    sp->addr_len = addr_len;
+    sp->read_cb = read_cb;
+    GPR_ASSERT(sp->emfd);
+    gpr_mu_unlock(&s->mu);
+    gpr_free(name);
+  }
+
+  return port;
+}
+
+int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr,
+                             size_t addr_len, grpc_udp_server_read_cb read_cb) {
+  int allocated_port1 = -1;
+  int allocated_port2 = -1;
+  unsigned i;
+  int fd;
+  grpc_dualstack_mode dsmode;
+  struct sockaddr_in6 addr6_v4mapped;
+  struct sockaddr_in wild4;
+  struct sockaddr_in6 wild6;
+  struct sockaddr_in addr4_copy;
+  struct sockaddr *allocated_addr = NULL;
+  struct sockaddr_storage sockname_temp;
+  socklen_t sockname_len;
+  int port;
+
+  grpc_unlink_if_unix_domain_socket((struct sockaddr *)addr);
+
+  /* Check if this is a wildcard port, and if so, try to keep the port the same
+     as some previously created listener. */
+  if (grpc_sockaddr_get_port(addr) == 0) {
+    for (i = 0; i < s->nports; i++) {
+      sockname_len = sizeof(sockname_temp);
+      if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp,
+                           &sockname_len)) {
+        port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+        if (port > 0) {
+          allocated_addr = malloc(addr_len);
+          memcpy(allocated_addr, addr, addr_len);
+          grpc_sockaddr_set_port(allocated_addr, port);
+          addr = allocated_addr;
+          break;
+        }
+      }
+    }
+  }
+
+  if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
+    addr = (const struct sockaddr *)&addr6_v4mapped;
+    addr_len = sizeof(addr6_v4mapped);
+  }
+
+  /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
+  if (grpc_sockaddr_is_wildcard(addr, &port)) {
+    grpc_sockaddr_make_wildcards(port, &wild4, &wild6);
+
+    /* Try listening on IPv6 first. */
+    addr = (struct sockaddr *)&wild6;
+    addr_len = sizeof(wild6);
+    fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode);
+    allocated_port1 = add_socket_to_server(s, fd, addr, addr_len, read_cb);
+    if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
+      goto done;
+    }
+
+    /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
+    if (port == 0 && allocated_port1 > 0) {
+      grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1);
+    }
+    addr = (struct sockaddr *)&wild4;
+    addr_len = sizeof(wild4);
+  }
+
+  fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode);
+  if (fd < 0) {
+    gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
+  }
+  if (dsmode == GRPC_DSMODE_IPV4 &&
+      grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
+    addr = (struct sockaddr *)&addr4_copy;
+    addr_len = sizeof(addr4_copy);
+  }
+  allocated_port2 = add_socket_to_server(s, fd, addr, addr_len, read_cb);
+
+done:
+  gpr_free(allocated_addr);
+  return allocated_port1 >= 0 ? allocated_port1 : allocated_port2;
+}
+
+int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned port_index) {
+  return (port_index < s->nports) ? s->ports[port_index].fd : -1;
+}
+
+void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
+                           grpc_pollset **pollsets, size_t pollset_count,
+                           grpc_server *server) {
+  size_t i, j;
+  gpr_mu_lock(&s->mu);
+  GPR_ASSERT(s->active_ports == 0);
+  s->pollsets = pollsets;
+  s->grpc_server = server;
+  for (i = 0; i < s->nports; i++) {
+    for (j = 0; j < pollset_count; j++) {
+      grpc_pollset_add_fd(exec_ctx, pollsets[j], s->ports[i].emfd);
+    }
+    s->ports[i].read_closure.cb = on_read;
+    s->ports[i].read_closure.cb_arg = &s->ports[i];
+    grpc_fd_notify_on_read(exec_ctx, s->ports[i].emfd,
+                           &s->ports[i].read_closure);
+    s->active_ports++;
+  }
+  gpr_mu_unlock(&s->mu);
+}
+
+#endif
+#endif
diff --git a/src/core/lib/iomgr/udp_server.h b/src/core/lib/iomgr/udp_server.h
new file mode 100644
index 0000000..316845a
--- /dev/null
+++ b/src/core/lib/iomgr/udp_server.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_UDP_SERVER_H
+#define GRPC_CORE_LIB_IOMGR_UDP_SERVER_H
+
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/fd_posix.h"
+
+/* Forward decl of struct grpc_server */
+/* This is not typedef'ed to avoid a typedef-redefinition error */
+struct grpc_server;
+
+/* Forward decl of grpc_udp_server */
+typedef struct grpc_udp_server grpc_udp_server;
+
+/* Called when data is available to read from the socket. */
+typedef void (*grpc_udp_server_read_cb)(grpc_exec_ctx *exec_ctx, grpc_fd *emfd,
+                                        struct grpc_server *server);
+
+/* Create a server, initially not bound to any ports */
+grpc_udp_server *grpc_udp_server_create(void);
+
+/* Start listening to bound ports */
+void grpc_udp_server_start(grpc_exec_ctx *exec_ctx, grpc_udp_server *udp_server,
+                           grpc_pollset **pollsets, size_t pollset_count,
+                           struct grpc_server *server);
+
+int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned index);
+
+/* Add a port to the server, returning port number on success, or negative
+   on failure.
+
+   The :: and 0.0.0.0 wildcard addresses are treated identically, accepting
+   both IPv4 and IPv6 connections, but :: is the preferred style.  This usually
+   creates one socket, but possibly two on systems which support IPv6,
+   but not dualstack sockets. */
+
+/* TODO(ctiller): deprecate this, and make grpc_udp_server_add_ports to handle
+                  all of the multiple socket port matching logic in one place */
+int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr,
+                             size_t addr_len, grpc_udp_server_read_cb read_cb);
+
+void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *server,
+                             grpc_closure *on_done);
+
+#endif /* GRPC_CORE_LIB_IOMGR_UDP_SERVER_H */
diff --git a/src/core/lib/iomgr/unix_sockets_posix.c b/src/core/lib/iomgr/unix_sockets_posix.c
new file mode 100644
index 0000000..42e4498
--- /dev/null
+++ b/src/core/lib/iomgr/unix_sockets_posix.c
@@ -0,0 +1,103 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/unix_sockets_posix.h"
+
+#ifdef GPR_HAVE_UNIX_SOCKET
+
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include <grpc/support/alloc.h>
+
+void grpc_create_socketpair_if_unix(int sv[2]) {
+  GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
+}
+
+grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name) {
+  struct sockaddr_un *un;
+
+  grpc_resolved_addresses *addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
+  addrs->naddrs = 1;
+  addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address));
+  un = (struct sockaddr_un *)addrs->addrs->addr;
+  un->sun_family = AF_UNIX;
+  strcpy(un->sun_path, name);
+  addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1;
+  return addrs;
+}
+
+int grpc_is_unix_socket(const struct sockaddr *addr) {
+  return addr->sa_family == AF_UNIX;
+}
+
+void grpc_unlink_if_unix_domain_socket(const struct sockaddr *addr) {
+  if (addr->sa_family != AF_UNIX) {
+    return;
+  }
+  struct sockaddr_un *un = (struct sockaddr_un *)addr;
+  struct stat st;
+
+  if (stat(un->sun_path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) {
+    unlink(un->sun_path);
+  }
+}
+
+int grpc_parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, size_t *len) {
+  struct sockaddr_un *un = (struct sockaddr_un *)addr;
+
+  un->sun_family = AF_UNIX;
+  strcpy(un->sun_path, uri->path);
+  *len = strlen(un->sun_path) + sizeof(un->sun_family) + 1;
+
+  return 1;
+}
+
+char *grpc_unix_get_default_authority(grpc_resolver_factory *factory,
+                                      grpc_uri *uri) {
+  return gpr_strdup("localhost");
+}
+
+char *grpc_sockaddr_to_uri_unix_if_possible(const struct sockaddr *addr) {
+  if (addr->sa_family != AF_UNIX) {
+    return NULL;
+  }
+
+  char *result;
+  gpr_asprintf(&result, "unix:%s", ((struct sockaddr_un *)addr)->sun_path);
+  return result;
+}
+
+#endif
diff --git a/src/core/lib/iomgr/unix_sockets_posix.h b/src/core/lib/iomgr/unix_sockets_posix.h
new file mode 100644
index 0000000..752cab8
--- /dev/null
+++ b/src/core/lib/iomgr/unix_sockets_posix.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_UNIX_SOCKETS_POSIX_H
+#define GRPC_CORE_LIB_IOMGR_UNIX_SOCKETS_POSIX_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/client_config/resolver_factory.h"
+#include "src/core/lib/client_config/uri_parser.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+
+void grpc_create_socketpair_if_unix(int sv[2]);
+
+grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name);
+
+int grpc_is_unix_socket(const struct sockaddr *addr);
+
+void grpc_unlink_if_unix_domain_socket(const struct sockaddr *addr);
+
+int grpc_parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, size_t *len);
+
+char *grpc_unix_get_default_authority(grpc_resolver_factory *factory,
+                                      grpc_uri *uri);
+
+char *grpc_sockaddr_to_uri_unix_if_possible(const struct sockaddr *addr);
+
+#endif /* GRPC_CORE_LIB_IOMGR_UNIX_SOCKETS_POSIX_H */
diff --git a/src/core/lib/iomgr/unix_sockets_posix_noop.c b/src/core/lib/iomgr/unix_sockets_posix_noop.c
new file mode 100644
index 0000000..06f6ee0
--- /dev/null
+++ b/src/core/lib/iomgr/unix_sockets_posix_noop.c
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/unix_sockets_posix.h"
+
+#ifndef GPR_HAVE_UNIX_SOCKET
+
+void grpc_create_socketpair_if_unix(int sv[2]) {}
+
+grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name) {
+  return NULL;
+}
+
+int grpc_is_unix_socket(const struct sockaddr *addr) { return false; }
+
+void grpc_unlink_if_unix_domain_socket(const struct sockaddr *addr) {}
+
+int grpc_parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, size_t *len) {
+  return 0;
+}
+
+char *grpc_unix_get_default_authority(grpc_resolver_factory *factory,
+                                      grpc_uri *uri) {
+  return NULL;
+}
+
+char *grpc_sockaddr_to_uri_unix_if_possible(const struct sockaddr *addr) {
+  return NULL;
+}
+
+#endif
diff --git a/src/core/lib/iomgr/wakeup_fd_eventfd.c b/src/core/lib/iomgr/wakeup_fd_eventfd.c
new file mode 100644
index 0000000..41ded0c
--- /dev/null
+++ b/src/core/lib/iomgr/wakeup_fd_eventfd.c
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_LINUX_EVENTFD
+
+#include <errno.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+#include "src/core/lib/profiling/timers.h"
+
+static void eventfd_create(grpc_wakeup_fd* fd_info) {
+  int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
+  /* TODO(klempner): Handle failure more gracefully */
+  GPR_ASSERT(efd >= 0);
+  fd_info->read_fd = efd;
+  fd_info->write_fd = -1;
+}
+
+static void eventfd_consume(grpc_wakeup_fd* fd_info) {
+  eventfd_t value;
+  int err;
+  do {
+    err = eventfd_read(fd_info->read_fd, &value);
+  } while (err < 0 && errno == EINTR);
+}
+
+static void eventfd_wakeup(grpc_wakeup_fd* fd_info) {
+  int err;
+  GPR_TIMER_BEGIN("eventfd_wakeup", 0);
+  do {
+    err = eventfd_write(fd_info->read_fd, 1);
+  } while (err < 0 && errno == EINTR);
+  GPR_TIMER_END("eventfd_wakeup", 0);
+}
+
+static void eventfd_destroy(grpc_wakeup_fd* fd_info) {
+  if (fd_info->read_fd != 0) close(fd_info->read_fd);
+}
+
+static int eventfd_check_availability(void) {
+  /* TODO(klempner): Actually check if eventfd is available */
+  return 1;
+}
+
+const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = {
+    eventfd_create, eventfd_consume, eventfd_wakeup, eventfd_destroy,
+    eventfd_check_availability};
+
+#endif /* GPR_LINUX_EVENTFD */
diff --git a/src/core/lib/iomgr/wakeup_fd_nospecial.c b/src/core/lib/iomgr/wakeup_fd_nospecial.c
new file mode 100644
index 0000000..39defa6
--- /dev/null
+++ b/src/core/lib/iomgr/wakeup_fd_nospecial.c
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * This is a dummy file to provide an invalid specialized_wakeup_fd_vtable on
+ * systems without anything better than pipe.
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_NO_SPECIAL_WAKEUP_FD
+
+#include <stddef.h>
+#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+
+static int check_availability_invalid(void) { return 0; }
+
+const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable = {
+    NULL, NULL, NULL, NULL, check_availability_invalid};
+
+#endif /* GPR_POSIX_NO_SPECIAL_WAKEUP_FD */
diff --git a/src/core/lib/iomgr/wakeup_fd_pipe.c b/src/core/lib/iomgr/wakeup_fd_pipe.c
new file mode 100644
index 0000000..820919e
--- /dev/null
+++ b/src/core/lib/iomgr/wakeup_fd_pipe.c
@@ -0,0 +1,102 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_WAKEUP_FD
+
+#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+
+static void pipe_init(grpc_wakeup_fd* fd_info) {
+  int pipefd[2];
+  /* TODO(klempner): Make this nonfatal */
+  int r = pipe(pipefd);
+  if (0 != r) {
+    gpr_log(GPR_ERROR, "pipe creation failed (%d): %s", errno, strerror(errno));
+    abort();
+  }
+  GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[0], 1));
+  GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[1], 1));
+  fd_info->read_fd = pipefd[0];
+  fd_info->write_fd = pipefd[1];
+}
+
+static void pipe_consume(grpc_wakeup_fd* fd_info) {
+  char buf[128];
+  ssize_t r;
+
+  for (;;) {
+    r = read(fd_info->read_fd, buf, sizeof(buf));
+    if (r > 0) continue;
+    if (r == 0) return;
+    switch (errno) {
+      case EAGAIN:
+        return;
+      case EINTR:
+        continue;
+      default:
+        gpr_log(GPR_ERROR, "error reading pipe: %s", strerror(errno));
+        return;
+    }
+  }
+}
+
+static void pipe_wakeup(grpc_wakeup_fd* fd_info) {
+  char c = 0;
+  while (write(fd_info->write_fd, &c, 1) != 1 && errno == EINTR)
+    ;
+}
+
+static void pipe_destroy(grpc_wakeup_fd* fd_info) {
+  if (fd_info->read_fd != 0) close(fd_info->read_fd);
+  if (fd_info->write_fd != 0) close(fd_info->write_fd);
+}
+
+static int pipe_check_availability(void) {
+  /* Assume that pipes are always available. */
+  return 1;
+}
+
+const grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable = {
+    pipe_init, pipe_consume, pipe_wakeup, pipe_destroy,
+    pipe_check_availability};
+
+#endif /* GPR_POSIX_WAKUP_FD */
diff --git a/src/core/lib/iomgr/wakeup_fd_pipe.h b/src/core/lib/iomgr/wakeup_fd_pipe.h
new file mode 100644
index 0000000..bbdb1fc
--- /dev/null
+++ b/src/core/lib/iomgr/wakeup_fd_pipe.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_WAKEUP_FD_PIPE_H
+#define GRPC_CORE_LIB_IOMGR_WAKEUP_FD_PIPE_H
+
+#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+
+extern grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable;
+
+#endif /* GRPC_CORE_LIB_IOMGR_WAKEUP_FD_PIPE_H */
diff --git a/src/core/lib/iomgr/wakeup_fd_posix.c b/src/core/lib/iomgr/wakeup_fd_posix.c
new file mode 100644
index 0000000..c4d174f
--- /dev/null
+++ b/src/core/lib/iomgr/wakeup_fd_posix.c
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_WAKEUP_FD
+
+#include <stddef.h>
+#include "src/core/lib/iomgr/wakeup_fd_pipe.h"
+#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+
+static const grpc_wakeup_fd_vtable *wakeup_fd_vtable = NULL;
+int grpc_allow_specialized_wakeup_fd = 1;
+
+void grpc_wakeup_fd_global_init(void) {
+  if (grpc_allow_specialized_wakeup_fd &&
+      grpc_specialized_wakeup_fd_vtable.check_availability()) {
+    wakeup_fd_vtable = &grpc_specialized_wakeup_fd_vtable;
+  } else {
+    wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable;
+  }
+}
+
+void grpc_wakeup_fd_global_destroy(void) { wakeup_fd_vtable = NULL; }
+
+void grpc_wakeup_fd_init(grpc_wakeup_fd *fd_info) {
+  wakeup_fd_vtable->init(fd_info);
+}
+
+void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd *fd_info) {
+  wakeup_fd_vtable->consume(fd_info);
+}
+
+void grpc_wakeup_fd_wakeup(grpc_wakeup_fd *fd_info) {
+  wakeup_fd_vtable->wakeup(fd_info);
+}
+
+void grpc_wakeup_fd_destroy(grpc_wakeup_fd *fd_info) {
+  wakeup_fd_vtable->destroy(fd_info);
+}
+
+#endif /* GPR_POSIX_WAKEUP_FD */
diff --git a/src/core/lib/iomgr/wakeup_fd_posix.h b/src/core/lib/iomgr/wakeup_fd_posix.h
new file mode 100644
index 0000000..20988d5
--- /dev/null
+++ b/src/core/lib/iomgr/wakeup_fd_posix.h
@@ -0,0 +1,101 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * wakeup_fd abstracts the concept of a file descriptor for the purpose of
+ * waking up a thread in select()/poll()/epoll_wait()/etc.
+
+ * The poll() family of system calls provide a way for a thread to block until
+ * there is activity on one (or more) of a set of file descriptors. An
+ * application may wish to wake up this thread to do non file related work. The
+ * typical way to do this is to add a pipe to the set of file descriptors, then
+ * write to the pipe to wake up the thread in poll().
+ *
+ * Linux has a lighter weight eventfd specifically designed for this purpose.
+ * wakeup_fd abstracts the difference between the two.
+ *
+ * Setup:
+ * 1. Before calling anything, call global_init() at least once.
+ * 1. Call grpc_wakeup_fd_create() to get a wakeup_fd.
+ * 2. Add the result of GRPC_WAKEUP_FD_FD to the set of monitored file
+ *    descriptors for the poll() style API you are using. Monitor the file
+ *    descriptor for readability.
+ * 3. To tear down, call grpc_wakeup_fd_destroy(). This closes the underlying
+ *    file descriptor.
+ *
+ * Usage:
+ * 1. To wake up a polling thread, call grpc_wakeup_fd_wakeup() on a wakeup_fd
+ *    it is monitoring.
+ * 2. If the polling thread was awakened by a wakeup_fd event, call
+ *    grpc_wakeup_fd_consume_wakeup() on it.
+ */
+#ifndef GRPC_CORE_LIB_IOMGR_WAKEUP_FD_POSIX_H
+#define GRPC_CORE_LIB_IOMGR_WAKEUP_FD_POSIX_H
+
+void grpc_wakeup_fd_global_init(void);
+void grpc_wakeup_fd_global_destroy(void);
+
+/* Force using the fallback implementation. This is intended for testing
+ * purposes only.*/
+void grpc_wakeup_fd_global_init_force_fallback(void);
+
+typedef struct grpc_wakeup_fd grpc_wakeup_fd;
+
+typedef struct grpc_wakeup_fd_vtable {
+  void (*init)(grpc_wakeup_fd* fd_info);
+  void (*consume)(grpc_wakeup_fd* fd_info);
+  void (*wakeup)(grpc_wakeup_fd* fd_info);
+  void (*destroy)(grpc_wakeup_fd* fd_info);
+  /* Must be called before calling any other functions */
+  int (*check_availability)(void);
+} grpc_wakeup_fd_vtable;
+
+struct grpc_wakeup_fd {
+  int read_fd;
+  int write_fd;
+};
+
+extern int grpc_allow_specialized_wakeup_fd;
+
+#define GRPC_WAKEUP_FD_GET_READ_FD(fd_info) ((fd_info)->read_fd)
+
+void grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info);
+void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info);
+void grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info);
+void grpc_wakeup_fd_destroy(grpc_wakeup_fd* fd_info);
+
+/* Defined in some specialized implementation's .c file, or by
+ * wakeup_fd_nospecial.c if no such implementation exists. */
+extern const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable;
+
+#endif /* GRPC_CORE_LIB_IOMGR_WAKEUP_FD_POSIX_H */
diff --git a/src/core/lib/iomgr/workqueue.h b/src/core/lib/iomgr/workqueue.h
new file mode 100644
index 0000000..9c420c5
--- /dev/null
+++ b/src/core/lib/iomgr/workqueue.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_WORKQUEUE_H
+#define GRPC_CORE_LIB_IOMGR_WORKQUEUE_H
+
+#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/pollset.h"
+
+#ifdef GPR_POSIX_SOCKET
+#include "src/core/lib/iomgr/workqueue_posix.h"
+#endif
+
+#ifdef GPR_WIN32
+#include "src/core/lib/iomgr/workqueue_windows.h"
+#endif
+
+/* grpc_workqueue is forward declared in exec_ctx.h */
+
+/** Create a work queue */
+grpc_workqueue *grpc_workqueue_create(grpc_exec_ctx *exec_ctx);
+
+void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
+
+#define GRPC_WORKQUEUE_REFCOUNT_DEBUG
+#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
+#define GRPC_WORKQUEUE_REF(p, r) \
+  grpc_workqueue_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_WORKQUEUE_UNREF(cl, p, r) \
+  grpc_workqueue_unref((cl), (p), __FILE__, __LINE__, (r))
+void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
+                        const char *reason);
+void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
+                          const char *file, int line, const char *reason);
+#else
+#define GRPC_WORKQUEUE_REF(p, r) grpc_workqueue_ref((p))
+#define GRPC_WORKQUEUE_UNREF(cl, p, r) grpc_workqueue_unref((cl), (p))
+void grpc_workqueue_ref(grpc_workqueue *workqueue);
+void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
+#endif
+
+/** Bind this workqueue to a pollset */
+void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx,
+                                   grpc_workqueue *workqueue,
+                                   grpc_pollset *pollset);
+
+/** Add a work item to a workqueue */
+void grpc_workqueue_push(grpc_workqueue *workqueue, grpc_closure *closure,
+                         int success);
+
+#endif /* GRPC_CORE_LIB_IOMGR_WORKQUEUE_H */
diff --git a/src/core/lib/iomgr/workqueue_posix.c b/src/core/lib/iomgr/workqueue_posix.c
new file mode 100644
index 0000000..76830ef
--- /dev/null
+++ b/src/core/lib/iomgr/workqueue_posix.c
@@ -0,0 +1,144 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SOCKET
+
+#include "src/core/lib/iomgr/workqueue.h"
+
+#include <stdio.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/iomgr/fd_posix.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
+
+static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success);
+
+grpc_workqueue *grpc_workqueue_create(grpc_exec_ctx *exec_ctx) {
+  char name[32];
+  grpc_workqueue *workqueue = gpr_malloc(sizeof(grpc_workqueue));
+  gpr_ref_init(&workqueue->refs, 1);
+  gpr_mu_init(&workqueue->mu);
+  workqueue->closure_list.head = workqueue->closure_list.tail = NULL;
+  grpc_wakeup_fd_init(&workqueue->wakeup_fd);
+  sprintf(name, "workqueue:%p", (void *)workqueue);
+  workqueue->wakeup_read_fd =
+      grpc_fd_create(GRPC_WAKEUP_FD_GET_READ_FD(&workqueue->wakeup_fd), name);
+  grpc_closure_init(&workqueue->read_closure, on_readable, workqueue);
+  grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd,
+                         &workqueue->read_closure);
+  return workqueue;
+}
+
+static void workqueue_destroy(grpc_exec_ctx *exec_ctx,
+                              grpc_workqueue *workqueue) {
+  GPR_ASSERT(grpc_closure_list_empty(workqueue->closure_list));
+  grpc_fd_shutdown(exec_ctx, workqueue->wakeup_read_fd);
+}
+
+#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
+void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
+                        const char *reason) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p   ref %d -> %d %s",
+          workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count + 1,
+          reason);
+#else
+void grpc_workqueue_ref(grpc_workqueue *workqueue) {
+#endif
+  gpr_ref(&workqueue->refs);
+}
+
+#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
+void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
+                          const char *file, int line, const char *reason) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p unref %d -> %d %s",
+          workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count - 1,
+          reason);
+#else
+void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
+#endif
+  if (gpr_unref(&workqueue->refs)) {
+    workqueue_destroy(exec_ctx, workqueue);
+  }
+}
+
+void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx,
+                                   grpc_workqueue *workqueue,
+                                   grpc_pollset *pollset) {
+  grpc_pollset_add_fd(exec_ctx, pollset, workqueue->wakeup_read_fd);
+}
+
+void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
+  gpr_mu_lock(&workqueue->mu);
+  if (grpc_closure_list_empty(workqueue->closure_list)) {
+    grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd);
+  }
+  grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
+  gpr_mu_unlock(&workqueue->mu);
+}
+
+static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  grpc_workqueue *workqueue = arg;
+
+  if (!success) {
+    gpr_mu_destroy(&workqueue->mu);
+    /* HACK: let wakeup_fd code know that we stole the fd */
+    workqueue->wakeup_fd.read_fd = 0;
+    grpc_wakeup_fd_destroy(&workqueue->wakeup_fd);
+    grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, NULL, "destroy");
+    gpr_free(workqueue);
+  } else {
+    gpr_mu_lock(&workqueue->mu);
+    grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
+    grpc_wakeup_fd_consume_wakeup(&workqueue->wakeup_fd);
+    gpr_mu_unlock(&workqueue->mu);
+    grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd,
+                           &workqueue->read_closure);
+  }
+}
+
+void grpc_workqueue_push(grpc_workqueue *workqueue, grpc_closure *closure,
+                         int success) {
+  gpr_mu_lock(&workqueue->mu);
+  if (grpc_closure_list_empty(workqueue->closure_list)) {
+    grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd);
+  }
+  grpc_closure_list_add(&workqueue->closure_list, closure, success);
+  gpr_mu_unlock(&workqueue->mu);
+}
+
+#endif /* GPR_POSIX_SOCKET */
diff --git a/src/core/lib/iomgr/workqueue_posix.h b/src/core/lib/iomgr/workqueue_posix.h
new file mode 100644
index 0000000..956de8f
--- /dev/null
+++ b/src/core/lib/iomgr/workqueue_posix.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H
+#define GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H
+
+#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+
+struct grpc_fd;
+
+struct grpc_workqueue {
+  gpr_refcount refs;
+
+  gpr_mu mu;
+  grpc_closure_list closure_list;
+
+  grpc_wakeup_fd wakeup_fd;
+  struct grpc_fd *wakeup_read_fd;
+
+  grpc_closure read_closure;
+};
+
+#endif /* GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H */
diff --git a/src/core/lib/iomgr/workqueue_windows.c b/src/core/lib/iomgr/workqueue_windows.c
new file mode 100644
index 0000000..6697f93
--- /dev/null
+++ b/src/core/lib/iomgr/workqueue_windows.c
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include "src/core/lib/iomgr/workqueue.h"
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/lib/iomgr/workqueue_windows.h b/src/core/lib/iomgr/workqueue_windows.h
new file mode 100644
index 0000000..8e6980b
--- /dev/null
+++ b/src/core/lib/iomgr/workqueue_windows.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_WORKQUEUE_WINDOWS_H
+#define GRPC_CORE_LIB_IOMGR_WORKQUEUE_WINDOWS_H
+
+#endif /* GRPC_CORE_LIB_IOMGR_WORKQUEUE_WINDOWS_H */
diff --git a/src/core/lib/json/json.c b/src/core/lib/json/json.c
new file mode 100644
index 0000000..9793045
--- /dev/null
+++ b/src/core/lib/json/json.c
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+#include "src/core/lib/json/json.h"
+
+grpc_json *grpc_json_create(grpc_json_type type) {
+  grpc_json *json = gpr_malloc(sizeof(*json));
+  memset(json, 0, sizeof(*json));
+  json->type = type;
+
+  return json;
+}
+
+void grpc_json_destroy(grpc_json *json) {
+  while (json->child) {
+    grpc_json_destroy(json->child);
+  }
+
+  if (json->next) {
+    json->next->prev = json->prev;
+  }
+
+  if (json->prev) {
+    json->prev->next = json->next;
+  } else if (json->parent) {
+    json->parent->child = json->next;
+  }
+
+  gpr_free(json);
+}
diff --git a/src/core/lib/json/json.h b/src/core/lib/json/json.h
new file mode 100644
index 0000000..41d87dd
--- /dev/null
+++ b/src/core/lib/json/json.h
@@ -0,0 +1,88 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_JSON_JSON_H
+#define GRPC_CORE_LIB_JSON_JSON_H
+
+#include <stdlib.h>
+
+#include "src/core/lib/json/json_common.h"
+
+/* A tree-like structure to hold json values. The key and value pointers
+ * are not owned by it.
+ */
+typedef struct grpc_json {
+  struct grpc_json *next;
+  struct grpc_json *prev;
+  struct grpc_json *child;
+  struct grpc_json *parent;
+
+  grpc_json_type type;
+  const char *key;
+  const char *value;
+} grpc_json;
+
+/* The next two functions are going to parse the input string, and
+ * 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 objects will be strings
+ * pointing at your input buffer.
+ *
+ * Delete the allocated tree afterward using grpc_json_destroy().
+ */
+grpc_json *grpc_json_parse_string_with_len(char *input, size_t size);
+grpc_json *grpc_json_parse_string(char *input);
+
+/* This function will create a new string using gpr_realloc, and will
+ * deserialize the grpc_json tree into it. It'll be zero-terminated,
+ * but will be allocated in chunks of 256 bytes.
+ *
+ * The indent parameter controls the way the output is formatted.
+ * If indent is 0, then newlines will be suppressed as well, and the
+ * output will be condensed at its maximum.
+ */
+char *grpc_json_dump_to_string(grpc_json *json, int indent);
+
+/* Use these to create or delete a grpc_json object.
+ * Deletion is recursive. We will not attempt to free any of the strings
+ * in any of the objects of that tree.
+ */
+grpc_json *grpc_json_create(grpc_json_type type);
+void grpc_json_destroy(grpc_json *json);
+
+#endif /* GRPC_CORE_LIB_JSON_JSON_H */
diff --git a/src/core/lib/json/json_common.h b/src/core/lib/json/json_common.h
new file mode 100644
index 0000000..ce98004
--- /dev/null
+++ b/src/core/lib/json/json_common.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_JSON_JSON_COMMON_H
+#define GRPC_CORE_LIB_JSON_JSON_COMMON_H
+
+/* The various json types. */
+typedef enum {
+  GRPC_JSON_OBJECT,
+  GRPC_JSON_ARRAY,
+  GRPC_JSON_STRING,
+  GRPC_JSON_NUMBER,
+  GRPC_JSON_TRUE,
+  GRPC_JSON_FALSE,
+  GRPC_JSON_NULL,
+  GRPC_JSON_TOP_LEVEL
+} grpc_json_type;
+
+#endif /* GRPC_CORE_LIB_JSON_JSON_COMMON_H */
diff --git a/src/core/lib/json/json_reader.c b/src/core/lib/json/json_reader.c
new file mode 100644
index 0000000..4cff13d
--- /dev/null
+++ b/src/core/lib/json/json_reader.c
@@ -0,0 +1,662 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/log.h>
+
+#include "src/core/lib/json/json_reader.h"
+
+static void json_reader_string_clear(grpc_json_reader *reader) {
+  reader->vtable->string_clear(reader->userdata);
+}
+
+static void json_reader_string_add_char(grpc_json_reader *reader, uint32_t c) {
+  reader->vtable->string_add_char(reader->userdata, c);
+}
+
+static void json_reader_string_add_utf32(grpc_json_reader *reader,
+                                         uint32_t utf32) {
+  reader->vtable->string_add_utf32(reader->userdata, utf32);
+}
+
+static uint32_t grpc_json_reader_read_char(grpc_json_reader *reader) {
+  return reader->vtable->read_char(reader->userdata);
+}
+
+static void json_reader_container_begins(grpc_json_reader *reader,
+                                         grpc_json_type type) {
+  reader->vtable->container_begins(reader->userdata, type);
+}
+
+static grpc_json_type grpc_json_reader_container_ends(
+    grpc_json_reader *reader) {
+  return reader->vtable->container_ends(reader->userdata);
+}
+
+static void json_reader_set_key(grpc_json_reader *reader) {
+  reader->vtable->set_key(reader->userdata);
+}
+
+static void json_reader_set_string(grpc_json_reader *reader) {
+  reader->vtable->set_string(reader->userdata);
+}
+
+static int json_reader_set_number(grpc_json_reader *reader) {
+  return reader->vtable->set_number(reader->userdata);
+}
+
+static void json_reader_set_true(grpc_json_reader *reader) {
+  reader->vtable->set_true(reader->userdata);
+}
+
+static void json_reader_set_false(grpc_json_reader *reader) {
+  reader->vtable->set_false(reader->userdata);
+}
+
+static void json_reader_set_null(grpc_json_reader *reader) {
+  reader->vtable->set_null(reader->userdata);
+}
+
+/* Call this function to initialize the reader structure. */
+void grpc_json_reader_init(grpc_json_reader *reader,
+                           grpc_json_reader_vtable *vtable, void *userdata) {
+  memset(reader, 0, sizeof(*reader));
+  reader->vtable = vtable;
+  reader->userdata = userdata;
+  json_reader_string_clear(reader);
+  reader->state = GRPC_JSON_STATE_VALUE_BEGIN;
+}
+
+int grpc_json_reader_is_complete(grpc_json_reader *reader) {
+  return ((reader->depth == 0) &&
+          ((reader->state == GRPC_JSON_STATE_END) ||
+           (reader->state == GRPC_JSON_STATE_VALUE_END)));
+}
+
+grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader) {
+  uint32_t c, success;
+
+  /* This state-machine is a strict implementation of ECMA-404 */
+  for (;;) {
+    c = grpc_json_reader_read_char(reader);
+    switch (c) {
+      /* Let's process the error cases first. */
+      case GRPC_JSON_READ_CHAR_ERROR:
+        return GRPC_JSON_READ_ERROR;
+
+      case GRPC_JSON_READ_CHAR_EAGAIN:
+        return GRPC_JSON_EAGAIN;
+
+      case GRPC_JSON_READ_CHAR_EOF:
+        if (grpc_json_reader_is_complete(reader)) {
+          return GRPC_JSON_DONE;
+        } else {
+          return GRPC_JSON_PARSE_ERROR;
+        }
+        break;
+
+      /* Processing whitespaces. */
+      case ' ':
+      case '\t':
+      case '\n':
+      case '\r':
+        switch (reader->state) {
+          case GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
+          case GRPC_JSON_STATE_OBJECT_KEY_END:
+          case GRPC_JSON_STATE_VALUE_BEGIN:
+          case GRPC_JSON_STATE_VALUE_END:
+          case GRPC_JSON_STATE_END:
+            break;
+
+          case GRPC_JSON_STATE_OBJECT_KEY_STRING:
+          case GRPC_JSON_STATE_VALUE_STRING:
+            if (c != ' ') return GRPC_JSON_PARSE_ERROR;
+            if (reader->unicode_high_surrogate != 0)
+              return GRPC_JSON_PARSE_ERROR;
+            json_reader_string_add_char(reader, c);
+            break;
+
+          case GRPC_JSON_STATE_VALUE_NUMBER:
+          case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
+          case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
+          case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
+            success = (uint32_t)json_reader_set_number(reader);
+            if (!success) return GRPC_JSON_PARSE_ERROR;
+            json_reader_string_clear(reader);
+            reader->state = GRPC_JSON_STATE_VALUE_END;
+            break;
+
+          default:
+            return GRPC_JSON_PARSE_ERROR;
+        }
+        break;
+
+      /* Value, object or array terminations. */
+      case ',':
+      case '}':
+      case ']':
+        switch (reader->state) {
+          case GRPC_JSON_STATE_OBJECT_KEY_STRING:
+          case GRPC_JSON_STATE_VALUE_STRING:
+            if (reader->unicode_high_surrogate != 0)
+              return GRPC_JSON_PARSE_ERROR;
+            json_reader_string_add_char(reader, c);
+            break;
+
+          case GRPC_JSON_STATE_VALUE_NUMBER:
+          case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
+          case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
+          case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
+            success = (uint32_t)json_reader_set_number(reader);
+            if (!success) return GRPC_JSON_PARSE_ERROR;
+            json_reader_string_clear(reader);
+            reader->state = GRPC_JSON_STATE_VALUE_END;
+          /* The missing break here is intentional. */
+
+          case GRPC_JSON_STATE_VALUE_END:
+          case GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
+          case GRPC_JSON_STATE_VALUE_BEGIN:
+            if (c == ',') {
+              if (reader->state != GRPC_JSON_STATE_VALUE_END) {
+                return GRPC_JSON_PARSE_ERROR;
+              }
+              if (reader->in_object) {
+                reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN;
+              } else {
+                reader->state = GRPC_JSON_STATE_VALUE_BEGIN;
+              }
+            } else {
+              if (reader->depth-- == 0) return GRPC_JSON_PARSE_ERROR;
+              if ((c == '}') && !reader->in_object) {
+                return GRPC_JSON_PARSE_ERROR;
+              }
+              if ((c == '}') &&
+                  (reader->state == GRPC_JSON_STATE_OBJECT_KEY_BEGIN) &&
+                  !reader->container_just_begun) {
+                return GRPC_JSON_PARSE_ERROR;
+              }
+              if ((c == ']') && !reader->in_array) return GRPC_JSON_PARSE_ERROR;
+              if ((c == ']') &&
+                  (reader->state == GRPC_JSON_STATE_VALUE_BEGIN) &&
+                  !reader->container_just_begun) {
+                return GRPC_JSON_PARSE_ERROR;
+              }
+              reader->state = GRPC_JSON_STATE_VALUE_END;
+              switch (grpc_json_reader_container_ends(reader)) {
+                case GRPC_JSON_OBJECT:
+                  reader->in_object = 1;
+                  reader->in_array = 0;
+                  break;
+                case GRPC_JSON_ARRAY:
+                  reader->in_object = 0;
+                  reader->in_array = 1;
+                  break;
+                case GRPC_JSON_TOP_LEVEL:
+                  GPR_ASSERT(reader->depth == 0);
+                  reader->in_object = 0;
+                  reader->in_array = 0;
+                  reader->state = GRPC_JSON_STATE_END;
+                  break;
+                default:
+                  GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR);
+              }
+            }
+            break;
+
+          default:
+            return GRPC_JSON_PARSE_ERROR;
+        }
+        break;
+
+      /* In-string escaping. */
+      case '\\':
+        switch (reader->state) {
+          case GRPC_JSON_STATE_OBJECT_KEY_STRING:
+            reader->escaped_string_was_key = 1;
+            reader->state = GRPC_JSON_STATE_STRING_ESCAPE;
+            break;
+
+          case GRPC_JSON_STATE_VALUE_STRING:
+            reader->escaped_string_was_key = 0;
+            reader->state = GRPC_JSON_STATE_STRING_ESCAPE;
+            break;
+
+          /* This is the \\ case. */
+          case GRPC_JSON_STATE_STRING_ESCAPE:
+            if (reader->unicode_high_surrogate != 0)
+              return GRPC_JSON_PARSE_ERROR;
+            json_reader_string_add_char(reader, '\\');
+            if (reader->escaped_string_was_key) {
+              reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
+            } else {
+              reader->state = GRPC_JSON_STATE_VALUE_STRING;
+            }
+            break;
+
+          default:
+            return GRPC_JSON_PARSE_ERROR;
+        }
+        break;
+
+      default:
+        reader->container_just_begun = 0;
+        switch (reader->state) {
+          case GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
+            if (c != '"') return GRPC_JSON_PARSE_ERROR;
+            reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
+            break;
+
+          case GRPC_JSON_STATE_OBJECT_KEY_STRING:
+            if (reader->unicode_high_surrogate != 0)
+              return GRPC_JSON_PARSE_ERROR;
+            if (c == '"') {
+              reader->state = GRPC_JSON_STATE_OBJECT_KEY_END;
+              json_reader_set_key(reader);
+              json_reader_string_clear(reader);
+            } else {
+              if (c < 32) return GRPC_JSON_PARSE_ERROR;
+              json_reader_string_add_char(reader, c);
+            }
+            break;
+
+          case GRPC_JSON_STATE_VALUE_STRING:
+            if (reader->unicode_high_surrogate != 0)
+              return GRPC_JSON_PARSE_ERROR;
+            if (c == '"') {
+              reader->state = GRPC_JSON_STATE_VALUE_END;
+              json_reader_set_string(reader);
+              json_reader_string_clear(reader);
+            } else {
+              if (c < 32) return GRPC_JSON_PARSE_ERROR;
+              json_reader_string_add_char(reader, c);
+            }
+            break;
+
+          case GRPC_JSON_STATE_OBJECT_KEY_END:
+            if (c != ':') return GRPC_JSON_PARSE_ERROR;
+            reader->state = GRPC_JSON_STATE_VALUE_BEGIN;
+            break;
+
+          case GRPC_JSON_STATE_VALUE_BEGIN:
+            switch (c) {
+              case 't':
+                reader->state = GRPC_JSON_STATE_VALUE_TRUE_R;
+                break;
+
+              case 'f':
+                reader->state = GRPC_JSON_STATE_VALUE_FALSE_A;
+                break;
+
+              case 'n':
+                reader->state = GRPC_JSON_STATE_VALUE_NULL_U;
+                break;
+
+              case '"':
+                reader->state = GRPC_JSON_STATE_VALUE_STRING;
+                break;
+
+              case '0':
+                json_reader_string_add_char(reader, c);
+                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_ZERO;
+                break;
+
+              case '1':
+              case '2':
+              case '3':
+              case '4':
+              case '5':
+              case '6':
+              case '7':
+              case '8':
+              case '9':
+              case '-':
+                json_reader_string_add_char(reader, c);
+                reader->state = GRPC_JSON_STATE_VALUE_NUMBER;
+                break;
+
+              case '{':
+                reader->container_just_begun = 1;
+                json_reader_container_begins(reader, GRPC_JSON_OBJECT);
+                reader->depth++;
+                reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN;
+                reader->in_object = 1;
+                reader->in_array = 0;
+                break;
+
+              case '[':
+                reader->container_just_begun = 1;
+                json_reader_container_begins(reader, GRPC_JSON_ARRAY);
+                reader->depth++;
+                reader->in_object = 0;
+                reader->in_array = 1;
+                break;
+              default:
+                return GRPC_JSON_PARSE_ERROR;
+            }
+            break;
+
+          case GRPC_JSON_STATE_STRING_ESCAPE:
+            if (reader->escaped_string_was_key) {
+              reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
+            } else {
+              reader->state = GRPC_JSON_STATE_VALUE_STRING;
+            }
+            if (reader->unicode_high_surrogate && c != 'u')
+              return GRPC_JSON_PARSE_ERROR;
+            switch (c) {
+              case '"':
+              case '/':
+                json_reader_string_add_char(reader, c);
+                break;
+              case 'b':
+                json_reader_string_add_char(reader, '\b');
+                break;
+              case 'f':
+                json_reader_string_add_char(reader, '\f');
+                break;
+              case 'n':
+                json_reader_string_add_char(reader, '\n');
+                break;
+              case 'r':
+                json_reader_string_add_char(reader, '\r');
+                break;
+              case 't':
+                json_reader_string_add_char(reader, '\t');
+                break;
+              case 'u':
+                reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U1;
+                reader->unicode_char = 0;
+                break;
+              default:
+                return GRPC_JSON_PARSE_ERROR;
+            }
+            break;
+
+          case GRPC_JSON_STATE_STRING_ESCAPE_U1:
+          case GRPC_JSON_STATE_STRING_ESCAPE_U2:
+          case GRPC_JSON_STATE_STRING_ESCAPE_U3:
+          case GRPC_JSON_STATE_STRING_ESCAPE_U4:
+            if ((c >= '0') && (c <= '9')) {
+              c -= '0';
+            } else if ((c >= 'A') && (c <= 'F')) {
+              c -= 'A' - 10;
+            } else if ((c >= 'a') && (c <= 'f')) {
+              c -= 'a' - 10;
+            } else {
+              return GRPC_JSON_PARSE_ERROR;
+            }
+            reader->unicode_char = (uint16_t)(reader->unicode_char << 4);
+            reader->unicode_char = (uint16_t)(reader->unicode_char | c);
+
+            switch (reader->state) {
+              case GRPC_JSON_STATE_STRING_ESCAPE_U1:
+                reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U2;
+                break;
+              case GRPC_JSON_STATE_STRING_ESCAPE_U2:
+                reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U3;
+                break;
+              case GRPC_JSON_STATE_STRING_ESCAPE_U3:
+                reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U4;
+                break;
+              case GRPC_JSON_STATE_STRING_ESCAPE_U4:
+                /* See grpc_json_writer_escape_string to have a description
+                 * of what's going on here.
+                 */
+                if ((reader->unicode_char & 0xfc00) == 0xd800) {
+                  /* high surrogate utf-16 */
+                  if (reader->unicode_high_surrogate != 0)
+                    return GRPC_JSON_PARSE_ERROR;
+                  reader->unicode_high_surrogate = reader->unicode_char;
+                } else if ((reader->unicode_char & 0xfc00) == 0xdc00) {
+                  /* low surrogate utf-16 */
+                  uint32_t utf32;
+                  if (reader->unicode_high_surrogate == 0)
+                    return GRPC_JSON_PARSE_ERROR;
+                  utf32 = 0x10000;
+                  utf32 += (uint32_t)(
+                      (reader->unicode_high_surrogate - 0xd800) * 0x400);
+                  utf32 += (uint32_t)(reader->unicode_char - 0xdc00);
+                  json_reader_string_add_utf32(reader, utf32);
+                  reader->unicode_high_surrogate = 0;
+                } else {
+                  /* anything else */
+                  if (reader->unicode_high_surrogate != 0)
+                    return GRPC_JSON_PARSE_ERROR;
+                  json_reader_string_add_utf32(reader, reader->unicode_char);
+                }
+                if (reader->escaped_string_was_key) {
+                  reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
+                } else {
+                  reader->state = GRPC_JSON_STATE_VALUE_STRING;
+                }
+                break;
+              default:
+                GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR);
+            }
+            break;
+
+          case GRPC_JSON_STATE_VALUE_NUMBER:
+            json_reader_string_add_char(reader, c);
+            switch (c) {
+              case '0':
+              case '1':
+              case '2':
+              case '3':
+              case '4':
+              case '5':
+              case '6':
+              case '7':
+              case '8':
+              case '9':
+                break;
+              case 'e':
+              case 'E':
+                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E;
+                break;
+              case '.':
+                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT;
+                break;
+              default:
+                return GRPC_JSON_PARSE_ERROR;
+            }
+            break;
+
+          case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
+            json_reader_string_add_char(reader, c);
+            switch (c) {
+              case '0':
+              case '1':
+              case '2':
+              case '3':
+              case '4':
+              case '5':
+              case '6':
+              case '7':
+              case '8':
+              case '9':
+                break;
+              case 'e':
+              case 'E':
+                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_E;
+                break;
+              default:
+                return GRPC_JSON_PARSE_ERROR;
+            }
+            break;
+
+          case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
+            if (c != '.') return GRPC_JSON_PARSE_ERROR;
+            json_reader_string_add_char(reader, c);
+            reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT;
+            break;
+
+          case GRPC_JSON_STATE_VALUE_NUMBER_DOT:
+            json_reader_string_add_char(reader, c);
+            switch (c) {
+              case '0':
+              case '1':
+              case '2':
+              case '3':
+              case '4':
+              case '5':
+              case '6':
+              case '7':
+              case '8':
+              case '9':
+                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL;
+                break;
+              default:
+                return GRPC_JSON_PARSE_ERROR;
+            }
+            break;
+
+          case GRPC_JSON_STATE_VALUE_NUMBER_E:
+            json_reader_string_add_char(reader, c);
+            switch (c) {
+              case '0':
+              case '1':
+              case '2':
+              case '3':
+              case '4':
+              case '5':
+              case '6':
+              case '7':
+              case '8':
+              case '9':
+              case '+':
+              case '-':
+                reader->state = GRPC_JSON_STATE_VALUE_NUMBER_EPM;
+                break;
+              default:
+                return GRPC_JSON_PARSE_ERROR;
+            }
+            break;
+
+          case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
+            json_reader_string_add_char(reader, c);
+            switch (c) {
+              case '0':
+              case '1':
+              case '2':
+              case '3':
+              case '4':
+              case '5':
+              case '6':
+              case '7':
+              case '8':
+              case '9':
+                break;
+              default:
+                return GRPC_JSON_PARSE_ERROR;
+            }
+            break;
+
+          case GRPC_JSON_STATE_VALUE_TRUE_R:
+            if (c != 'r') return GRPC_JSON_PARSE_ERROR;
+            reader->state = GRPC_JSON_STATE_VALUE_TRUE_U;
+            break;
+
+          case GRPC_JSON_STATE_VALUE_TRUE_U:
+            if (c != 'u') return GRPC_JSON_PARSE_ERROR;
+            reader->state = GRPC_JSON_STATE_VALUE_TRUE_E;
+            break;
+
+          case GRPC_JSON_STATE_VALUE_TRUE_E:
+            if (c != 'e') return GRPC_JSON_PARSE_ERROR;
+            json_reader_set_true(reader);
+            reader->state = GRPC_JSON_STATE_VALUE_END;
+            break;
+
+          case GRPC_JSON_STATE_VALUE_FALSE_A:
+            if (c != 'a') return GRPC_JSON_PARSE_ERROR;
+            reader->state = GRPC_JSON_STATE_VALUE_FALSE_L;
+            break;
+
+          case GRPC_JSON_STATE_VALUE_FALSE_L:
+            if (c != 'l') return GRPC_JSON_PARSE_ERROR;
+            reader->state = GRPC_JSON_STATE_VALUE_FALSE_S;
+            break;
+
+          case GRPC_JSON_STATE_VALUE_FALSE_S:
+            if (c != 's') return GRPC_JSON_PARSE_ERROR;
+            reader->state = GRPC_JSON_STATE_VALUE_FALSE_E;
+            break;
+
+          case GRPC_JSON_STATE_VALUE_FALSE_E:
+            if (c != 'e') return GRPC_JSON_PARSE_ERROR;
+            json_reader_set_false(reader);
+            reader->state = GRPC_JSON_STATE_VALUE_END;
+            break;
+
+          case GRPC_JSON_STATE_VALUE_NULL_U:
+            if (c != 'u') return GRPC_JSON_PARSE_ERROR;
+            reader->state = GRPC_JSON_STATE_VALUE_NULL_L1;
+            break;
+
+          case GRPC_JSON_STATE_VALUE_NULL_L1:
+            if (c != 'l') return GRPC_JSON_PARSE_ERROR;
+            reader->state = GRPC_JSON_STATE_VALUE_NULL_L2;
+            break;
+
+          case GRPC_JSON_STATE_VALUE_NULL_L2:
+            if (c != 'l') return GRPC_JSON_PARSE_ERROR;
+            json_reader_set_null(reader);
+            reader->state = GRPC_JSON_STATE_VALUE_END;
+            break;
+
+          /* All of the VALUE_END cases are handled in the specialized case
+           * above. */
+          case GRPC_JSON_STATE_VALUE_END:
+            switch (c) {
+              case ',':
+              case '}':
+              case ']':
+                GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR);
+                break;
+
+              default:
+                return GRPC_JSON_PARSE_ERROR;
+            }
+            break;
+
+          case GRPC_JSON_STATE_END:
+            return GRPC_JSON_PARSE_ERROR;
+        }
+    }
+  }
+
+  GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR);
+}
diff --git a/src/core/lib/json/json_reader.h b/src/core/lib/json/json_reader.h
new file mode 100644
index 0000000..37a8388
--- /dev/null
+++ b/src/core/lib/json/json_reader.h
@@ -0,0 +1,160 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_JSON_JSON_READER_H
+#define GRPC_CORE_LIB_JSON_JSON_READER_H
+
+#include <grpc/support/port_platform.h>
+#include "src/core/lib/json/json_common.h"
+
+typedef enum {
+  GRPC_JSON_STATE_OBJECT_KEY_BEGIN,
+  GRPC_JSON_STATE_OBJECT_KEY_STRING,
+  GRPC_JSON_STATE_OBJECT_KEY_END,
+  GRPC_JSON_STATE_VALUE_BEGIN,
+  GRPC_JSON_STATE_VALUE_STRING,
+  GRPC_JSON_STATE_STRING_ESCAPE,
+  GRPC_JSON_STATE_STRING_ESCAPE_U1,
+  GRPC_JSON_STATE_STRING_ESCAPE_U2,
+  GRPC_JSON_STATE_STRING_ESCAPE_U3,
+  GRPC_JSON_STATE_STRING_ESCAPE_U4,
+  GRPC_JSON_STATE_VALUE_NUMBER,
+  GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL,
+  GRPC_JSON_STATE_VALUE_NUMBER_ZERO,
+  GRPC_JSON_STATE_VALUE_NUMBER_DOT,
+  GRPC_JSON_STATE_VALUE_NUMBER_E,
+  GRPC_JSON_STATE_VALUE_NUMBER_EPM,
+  GRPC_JSON_STATE_VALUE_TRUE_R,
+  GRPC_JSON_STATE_VALUE_TRUE_U,
+  GRPC_JSON_STATE_VALUE_TRUE_E,
+  GRPC_JSON_STATE_VALUE_FALSE_A,
+  GRPC_JSON_STATE_VALUE_FALSE_L,
+  GRPC_JSON_STATE_VALUE_FALSE_S,
+  GRPC_JSON_STATE_VALUE_FALSE_E,
+  GRPC_JSON_STATE_VALUE_NULL_U,
+  GRPC_JSON_STATE_VALUE_NULL_L1,
+  GRPC_JSON_STATE_VALUE_NULL_L2,
+  GRPC_JSON_STATE_VALUE_END,
+  GRPC_JSON_STATE_END
+} grpc_json_reader_state;
+
+enum {
+  /* The first non-unicode value is 0x110000. But let's pick
+   * a value high enough to start our error codes from. These
+   * values are safe to return from the read_char function.
+   */
+  GRPC_JSON_READ_CHAR_EOF = 0x7ffffff0,
+  GRPC_JSON_READ_CHAR_EAGAIN,
+  GRPC_JSON_READ_CHAR_ERROR
+};
+
+struct grpc_json_reader;
+
+typedef struct grpc_json_reader_vtable {
+  /* Clears your internal string scratchpad. */
+  void (*string_clear)(void *userdata);
+  /* Adds a char to the string scratchpad. */
+  void (*string_add_char)(void *userdata, uint32_t c);
+  /* Adds a utf32 char to the string scratchpad. */
+  void (*string_add_utf32)(void *userdata, uint32_t c);
+  /* Reads a character from your input. May be utf-8, 16 or 32. */
+  uint32_t (*read_char)(void *userdata);
+  /* Starts a container of type GRPC_JSON_ARRAY or GRPC_JSON_OBJECT. */
+  void (*container_begins)(void *userdata, grpc_json_type type);
+  /* Ends the current container. Must return the type of its parent. */
+  grpc_json_type (*container_ends)(void *userdata);
+  /* Your internal string scratchpad is an object's key. */
+  void (*set_key)(void *userdata);
+  /* Your internal string scratchpad is a string value. */
+  void (*set_string)(void *userdata);
+  /* Your internal string scratchpad is a numerical value. Return 1 if valid. */
+  int (*set_number)(void *userdata);
+  /* Sets the values true, false or null. */
+  void (*set_true)(void *userdata);
+  void (*set_false)(void *userdata);
+  void (*set_null)(void *userdata);
+} grpc_json_reader_vtable;
+
+typedef struct grpc_json_reader {
+  /* That structure is fully private, and initialized by grpc_json_reader_init.
+   * The definition is public so you can put it on your stack.
+   */
+
+  void *userdata;
+  grpc_json_reader_vtable *vtable;
+  int depth;
+  int in_object;
+  int in_array;
+  int escaped_string_was_key;
+  int container_just_begun;
+  uint16_t unicode_char, unicode_high_surrogate;
+  grpc_json_reader_state state;
+} grpc_json_reader;
+
+/* The return type of the parser. */
+typedef enum {
+  GRPC_JSON_DONE,          /* The parser finished successfully. */
+  GRPC_JSON_EAGAIN,        /* The parser yields to get more data. */
+  GRPC_JSON_READ_ERROR,    /* The parser passes through a read error. */
+  GRPC_JSON_PARSE_ERROR,   /* The parser found an error in the json stream. */
+  GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */
+} grpc_json_reader_status;
+
+/* Call this function to start parsing the input. It will return the following:
+ *    . GRPC_JSON_DONE if the input got eof, and the parsing finished
+ *      successfully.
+ *    . GRPC_JSON_EAGAIN if the read_char function returned again. Call the
+ *      parser again as needed. It is okay to call the parser in polling mode,
+ *      although a bit dull.
+ *    . GRPC_JSON_READ_ERROR if the read_char function returned an error. The
+ *      state isn't broken however, and the function can be called again if the
+ *      error has been corrected. But please use the EAGAIN feature instead for
+ *      consistency.
+ *    . GRPC_JSON_PARSE_ERROR if the input was somehow invalid.
+ *    . GRPC_JSON_INTERNAL_ERROR if the parser somehow ended into an invalid
+ *      internal state.
+ */
+grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader);
+
+/* Call this function to initialize the reader structure. */
+void grpc_json_reader_init(grpc_json_reader *reader,
+                           grpc_json_reader_vtable *vtable, void *userdata);
+
+/* You may call this from the read_char callback if you don't know where is the
+ * end of your input stream, and you'd like the json reader to hint you that it
+ * has completed reading its input, so you can return an EOF to it. Note that
+ * there might still be trailing whitespaces after that point.
+ */
+int grpc_json_reader_is_complete(grpc_json_reader *reader);
+
+#endif /* GRPC_CORE_LIB_JSON_JSON_READER_H */
diff --git a/src/core/lib/json/json_string.c b/src/core/lib/json/json_string.c
new file mode 100644
index 0000000..8e6f125
--- /dev/null
+++ b/src/core/lib/json/json_string.c
@@ -0,0 +1,379 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/json/json_reader.h"
+#include "src/core/lib/json/json_writer.h"
+
+/* The json reader will construct a bunch of grpc_json objects and
+ * link them all up together in a tree-like structure that will represent
+ * the json data in memory.
+ *
+ * It also uses its own input as a scratchpad to store all of the decoded,
+ * unescaped strings. So we need to keep track of all these pointers in
+ * that opaque structure the reader will carry for us.
+ *
+ * Note that this works because the act of parsing json always reduces its
+ * input size, and never expands it.
+ */
+typedef struct {
+  grpc_json *top;
+  grpc_json *current_container;
+  grpc_json *current_value;
+  uint8_t *input;
+  uint8_t *key;
+  uint8_t *string;
+  uint8_t *string_ptr;
+  size_t remaining_input;
+} json_reader_userdata;
+
+/* This json writer will put everything in a big string.
+ * The point is that we allocate that string in chunks of 256 bytes.
+ */
+typedef struct {
+  char *output;
+  size_t free_space;
+  size_t string_len;
+  size_t allocated;
+} json_writer_userdata;
+
+/* This function checks if there's enough space left in the output buffer,
+ * and will enlarge it if necessary. We're only allocating chunks of 256
+ * bytes at a time (or multiples thereof).
+ */
+static void json_writer_output_check(void *userdata, size_t needed) {
+  json_writer_userdata *state = userdata;
+  if (state->free_space >= needed) return;
+  needed -= state->free_space;
+  /* Round up by 256 bytes. */
+  needed = (needed + 0xff) & ~0xffU;
+  state->output = gpr_realloc(state->output, state->allocated + needed);
+  state->free_space += needed;
+  state->allocated += needed;
+}
+
+/* These are needed by the writer's implementation. */
+static void json_writer_output_char(void *userdata, char c) {
+  json_writer_userdata *state = userdata;
+  json_writer_output_check(userdata, 1);
+  state->output[state->string_len++] = c;
+  state->free_space--;
+}
+
+static void json_writer_output_string_with_len(void *userdata, const char *str,
+                                               size_t len) {
+  json_writer_userdata *state = userdata;
+  json_writer_output_check(userdata, len);
+  memcpy(state->output + state->string_len, str, len);
+  state->string_len += len;
+  state->free_space -= len;
+}
+
+static void json_writer_output_string(void *userdata, const char *str) {
+  size_t len = strlen(str);
+  json_writer_output_string_with_len(userdata, str, len);
+}
+
+/* The reader asks us to clear our scratchpad. In our case, we'll simply mark
+ * the end of the current string, and advance our output pointer.
+ */
+static void json_reader_string_clear(void *userdata) {
+  json_reader_userdata *state = userdata;
+  if (state->string) {
+    GPR_ASSERT(state->string_ptr < state->input);
+    *state->string_ptr++ = 0;
+  }
+  state->string = state->string_ptr;
+}
+
+static void json_reader_string_add_char(void *userdata, uint32_t c) {
+  json_reader_userdata *state = userdata;
+  GPR_ASSERT(state->string_ptr < state->input);
+  GPR_ASSERT(c <= 0xff);
+  *state->string_ptr++ = (uint8_t)c;
+}
+
+/* We are converting a UTF-32 character into UTF-8 here,
+ * as described by RFC3629.
+ */
+static void json_reader_string_add_utf32(void *userdata, uint32_t c) {
+  if (c <= 0x7f) {
+    json_reader_string_add_char(userdata, c);
+  } else if (c <= 0x7ff) {
+    uint32_t b1 = 0xc0 | ((c >> 6) & 0x1f);
+    uint32_t b2 = 0x80 | (c & 0x3f);
+    json_reader_string_add_char(userdata, b1);
+    json_reader_string_add_char(userdata, b2);
+  } else if (c <= 0xffff) {
+    uint32_t b1 = 0xe0 | ((c >> 12) & 0x0f);
+    uint32_t b2 = 0x80 | ((c >> 6) & 0x3f);
+    uint32_t 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) {
+    uint32_t b1 = 0xf0 | ((c >> 18) & 0x07);
+    uint32_t b2 = 0x80 | ((c >> 12) & 0x3f);
+    uint32_t b3 = 0x80 | ((c >> 6) & 0x3f);
+    uint32_t 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);
+    json_reader_string_add_char(userdata, b4);
+  }
+}
+
+/* We consider that the input may be a zero-terminated string. So we
+ * can end up hitting eof before the end of the alleged string length.
+ */
+static uint32_t json_reader_read_char(void *userdata) {
+  uint32_t r;
+  json_reader_userdata *state = userdata;
+
+  if (state->remaining_input == 0) return GRPC_JSON_READ_CHAR_EOF;
+
+  r = *state->input++;
+  state->remaining_input--;
+
+  if (r == 0) {
+    state->remaining_input = 0;
+    return GRPC_JSON_READ_CHAR_EOF;
+  }
+
+  return r;
+}
+
+/* Helper function to create a new grpc_json object and link it into
+ * our tree-in-progress inside our opaque structure.
+ */
+static grpc_json *json_create_and_link(void *userdata, grpc_json_type type) {
+  json_reader_userdata *state = userdata;
+  grpc_json *json = grpc_json_create(type);
+
+  json->parent = state->current_container;
+  json->prev = state->current_value;
+  state->current_value = json;
+
+  if (json->prev) {
+    json->prev->next = json;
+  }
+  if (json->parent) {
+    if (!json->parent->child) {
+      json->parent->child = json;
+    }
+    if (json->parent->type == GRPC_JSON_OBJECT) {
+      json->key = (char *)state->key;
+    }
+  }
+  if (!state->top) {
+    state->top = json;
+  }
+
+  return json;
+}
+
+static void json_reader_container_begins(void *userdata, grpc_json_type type) {
+  json_reader_userdata *state = userdata;
+  grpc_json *container;
+
+  GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT);
+
+  container = json_create_and_link(userdata, type);
+  state->current_container = container;
+  state->current_value = NULL;
+}
+
+/* It's important to remember that the reader is mostly stateless, so it
+ * isn't trying to remember what the container was prior the one that just
+ * ends. Since we're keeping track of these for our own purpose, we are
+ * able to return that information back, which is useful for it to validate
+ * the input json stream.
+ *
+ * Also note that if we're at the top of the tree, and the last container
+ * ends, we have to return GRPC_JSON_TOP_LEVEL.
+ */
+static grpc_json_type json_reader_container_ends(void *userdata) {
+  grpc_json_type container_type = GRPC_JSON_TOP_LEVEL;
+  json_reader_userdata *state = userdata;
+
+  GPR_ASSERT(state->current_container);
+
+  state->current_value = state->current_container;
+  state->current_container = state->current_container->parent;
+
+  if (state->current_container) {
+    container_type = state->current_container->type;
+  }
+
+  return container_type;
+}
+
+/* The next 3 functions basically are the reader asking us to use our string
+ * scratchpad for one of these 3 purposes.
+ *
+ * Note that in the set_number case, we're not going to try interpreting it.
+ * We'll keep it as a string, and leave it to the caller to evaluate it.
+ */
+static void json_reader_set_key(void *userdata) {
+  json_reader_userdata *state = userdata;
+  state->key = state->string;
+}
+
+static void json_reader_set_string(void *userdata) {
+  json_reader_userdata *state = userdata;
+  grpc_json *json = json_create_and_link(userdata, GRPC_JSON_STRING);
+  json->value = (char *)state->string;
+}
+
+static int json_reader_set_number(void *userdata) {
+  json_reader_userdata *state = userdata;
+  grpc_json *json = json_create_and_link(userdata, GRPC_JSON_NUMBER);
+  json->value = (char *)state->string;
+  return 1;
+}
+
+/* The object types true, false and null are self-sufficient, and don't need
+ * any more information beside their type.
+ */
+static void json_reader_set_true(void *userdata) {
+  json_create_and_link(userdata, GRPC_JSON_TRUE);
+}
+
+static void json_reader_set_false(void *userdata) {
+  json_create_and_link(userdata, GRPC_JSON_FALSE);
+}
+
+static void json_reader_set_null(void *userdata) {
+  json_create_and_link(userdata, GRPC_JSON_NULL);
+}
+
+static grpc_json_reader_vtable reader_vtable = {
+    json_reader_string_clear,     json_reader_string_add_char,
+    json_reader_string_add_utf32, json_reader_read_char,
+    json_reader_container_begins, json_reader_container_ends,
+    json_reader_set_key,          json_reader_set_string,
+    json_reader_set_number,       json_reader_set_true,
+    json_reader_set_false,        json_reader_set_null};
+
+/* And finally, let's define our public API. */
+grpc_json *grpc_json_parse_string_with_len(char *input, size_t size) {
+  grpc_json_reader reader;
+  json_reader_userdata state;
+  grpc_json *json = NULL;
+  grpc_json_reader_status status;
+
+  if (!input) return NULL;
+
+  state.top = state.current_container = state.current_value = NULL;
+  state.string = state.key = NULL;
+  state.string_ptr = state.input = (uint8_t *)input;
+  state.remaining_input = size;
+  grpc_json_reader_init(&reader, &reader_vtable, &state);
+
+  status = grpc_json_reader_run(&reader);
+  json = state.top;
+
+  if ((status != GRPC_JSON_DONE) && json) {
+    grpc_json_destroy(json);
+    json = NULL;
+  }
+
+  return json;
+}
+
+#define UNBOUND_JSON_STRING_LENGTH 0x7fffffff
+
+grpc_json *grpc_json_parse_string(char *input) {
+  return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH);
+}
+
+static void json_dump_recursive(grpc_json_writer *writer, grpc_json *json,
+                                int in_object) {
+  while (json) {
+    if (in_object) grpc_json_writer_object_key(writer, json->key);
+
+    switch (json->type) {
+      case GRPC_JSON_OBJECT:
+      case GRPC_JSON_ARRAY:
+        grpc_json_writer_container_begins(writer, json->type);
+        if (json->child)
+          json_dump_recursive(writer, json->child,
+                              json->type == GRPC_JSON_OBJECT);
+        grpc_json_writer_container_ends(writer, json->type);
+        break;
+      case GRPC_JSON_STRING:
+        grpc_json_writer_value_string(writer, json->value);
+        break;
+      case GRPC_JSON_NUMBER:
+        grpc_json_writer_value_raw(writer, json->value);
+        break;
+      case GRPC_JSON_TRUE:
+        grpc_json_writer_value_raw_with_len(writer, "true", 4);
+        break;
+      case GRPC_JSON_FALSE:
+        grpc_json_writer_value_raw_with_len(writer, "false", 5);
+        break;
+      case GRPC_JSON_NULL:
+        grpc_json_writer_value_raw_with_len(writer, "null", 4);
+        break;
+      default:
+        GPR_UNREACHABLE_CODE(abort());
+    }
+    json = json->next;
+  }
+}
+
+static grpc_json_writer_vtable writer_vtable = {
+    json_writer_output_char, json_writer_output_string,
+    json_writer_output_string_with_len};
+
+char *grpc_json_dump_to_string(grpc_json *json, int indent) {
+  grpc_json_writer writer;
+  json_writer_userdata state;
+
+  state.output = NULL;
+  state.free_space = state.string_len = state.allocated = 0;
+  grpc_json_writer_init(&writer, indent, &writer_vtable, &state);
+
+  json_dump_recursive(&writer, json, 0);
+
+  json_writer_output_char(&state, 0);
+
+  return state.output;
+}
diff --git a/src/core/lib/json/json_writer.c b/src/core/lib/json/json_writer.c
new file mode 100644
index 0000000..d614a72
--- /dev/null
+++ b/src/core/lib/json/json_writer.c
@@ -0,0 +1,258 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/json/json_writer.h"
+
+static void json_writer_output_char(grpc_json_writer *writer, char c) {
+  writer->vtable->output_char(writer->userdata, c);
+}
+
+static void json_writer_output_string(grpc_json_writer *writer,
+                                      const char *str) {
+  writer->vtable->output_string(writer->userdata, str);
+}
+
+static void json_writer_output_string_with_len(grpc_json_writer *writer,
+                                               const char *str, size_t len) {
+  writer->vtable->output_string_with_len(writer->userdata, str, len);
+}
+
+void grpc_json_writer_init(grpc_json_writer *writer, int indent,
+                           grpc_json_writer_vtable *vtable, void *userdata) {
+  memset(writer, 0, sizeof(*writer));
+  writer->container_empty = 1;
+  writer->indent = indent;
+  writer->vtable = vtable;
+  writer->userdata = userdata;
+}
+
+static void json_writer_output_indent(grpc_json_writer *writer) {
+  static const char spacesstr[] =
+      "                "
+      "                "
+      "                "
+      "                ";
+
+  unsigned spaces = (unsigned)(writer->depth * writer->indent);
+
+  if (writer->indent == 0) return;
+
+  if (writer->got_key) {
+    json_writer_output_char(writer, ' ');
+    return;
+  }
+
+  while (spaces >= (sizeof(spacesstr) - 1)) {
+    json_writer_output_string_with_len(writer, spacesstr,
+                                       sizeof(spacesstr) - 1);
+    spaces -= (unsigned)(sizeof(spacesstr) - 1);
+  }
+
+  if (spaces == 0) return;
+
+  json_writer_output_string_with_len(
+      writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces);
+}
+
+static void json_writer_value_end(grpc_json_writer *writer) {
+  if (writer->container_empty) {
+    writer->container_empty = 0;
+    if ((writer->indent == 0) || (writer->depth == 0)) return;
+    json_writer_output_char(writer, '\n');
+  } else {
+    json_writer_output_char(writer, ',');
+    if (writer->indent == 0) return;
+    json_writer_output_char(writer, '\n');
+  }
+}
+
+static void json_writer_escape_utf16(grpc_json_writer *writer, uint16_t utf16) {
+  static const char hex[] = "0123456789abcdef";
+
+  json_writer_output_string_with_len(writer, "\\u", 2);
+  json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]);
+  json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]);
+  json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]);
+  json_writer_output_char(writer, hex[(utf16)&0x0f]);
+}
+
+static void json_writer_escape_string(grpc_json_writer *writer,
+                                      const char *string) {
+  json_writer_output_char(writer, '"');
+
+  for (;;) {
+    uint8_t c = (uint8_t)*string++;
+    if (c == 0) {
+      break;
+    } else if ((c >= 32) && (c <= 126)) {
+      if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\');
+      json_writer_output_char(writer, (char)c);
+    } else if ((c < 32) || (c == 127)) {
+      switch (c) {
+        case '\b':
+          json_writer_output_string_with_len(writer, "\\b", 2);
+          break;
+        case '\f':
+          json_writer_output_string_with_len(writer, "\\f", 2);
+          break;
+        case '\n':
+          json_writer_output_string_with_len(writer, "\\n", 2);
+          break;
+        case '\r':
+          json_writer_output_string_with_len(writer, "\\r", 2);
+          break;
+        case '\t':
+          json_writer_output_string_with_len(writer, "\\t", 2);
+          break;
+        default:
+          json_writer_escape_utf16(writer, c);
+          break;
+      }
+    } else {
+      uint32_t utf32 = 0;
+      int extra = 0;
+      int i;
+      int valid = 1;
+      if ((c & 0xe0) == 0xc0) {
+        utf32 = c & 0x1f;
+        extra = 1;
+      } else if ((c & 0xf0) == 0xe0) {
+        utf32 = c & 0x0f;
+        extra = 2;
+      } else if ((c & 0xf8) == 0xf0) {
+        utf32 = c & 0x07;
+        extra = 3;
+      } else {
+        break;
+      }
+      for (i = 0; i < extra; i++) {
+        utf32 <<= 6;
+        c = (uint8_t)(*string++);
+        /* Breaks out and bail on any invalid UTF-8 sequence, including \0. */
+        if ((c & 0xc0) != 0x80) {
+          valid = 0;
+          break;
+        }
+        utf32 |= c & 0x3f;
+      }
+      if (!valid) break;
+      /* The range 0xd800 - 0xdfff is reserved by the surrogates ad vitam.
+       * Any other range is technically reserved for future usage, so if we
+       * don't want the software to break in the future, we have to allow
+       * anything else. The first non-unicode character is 0x110000. */
+      if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000))
+        break;
+      if (utf32 >= 0x10000) {
+        /* If utf32 contains a character that is above 0xffff, it needs to be
+         * broken down into a utf-16 surrogate pair. A surrogate pair is first
+         * a high surrogate, followed by a low surrogate. Each surrogate holds
+         * 10 bits of usable data, thus allowing a total of 20 bits of data.
+         * The high surrogate marker is 0xd800, while the low surrogate marker
+         * is 0xdc00. The low 10 bits of each will be the usable data.
+         *
+         * After re-combining the 20 bits of data, one has to add 0x10000 to
+         * the resulting value, in order to obtain the original character.
+         * This is obviously because the range 0x0000 - 0xffff can be written
+         * without any special trick.
+         *
+         * Since 0x10ffff is the highest allowed character, we're working in
+         * the range 0x00000 - 0xfffff after we decrement it by 0x10000.
+         * That range is exactly 20 bits.
+         */
+        utf32 -= 0x10000;
+        json_writer_escape_utf16(writer, (uint16_t)(0xd800 | (utf32 >> 10)));
+        json_writer_escape_utf16(writer, (uint16_t)(0xdc00 | (utf32 & 0x3ff)));
+      } else {
+        json_writer_escape_utf16(writer, (uint16_t)utf32);
+      }
+    }
+  }
+
+  json_writer_output_char(writer, '"');
+}
+
+void grpc_json_writer_container_begins(grpc_json_writer *writer,
+                                       grpc_json_type type) {
+  if (!writer->got_key) json_writer_value_end(writer);
+  json_writer_output_indent(writer);
+  json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '[');
+  writer->container_empty = 1;
+  writer->got_key = 0;
+  writer->depth++;
+}
+
+void grpc_json_writer_container_ends(grpc_json_writer *writer,
+                                     grpc_json_type type) {
+  if (writer->indent && !writer->container_empty)
+    json_writer_output_char(writer, '\n');
+  writer->depth--;
+  if (!writer->container_empty) json_writer_output_indent(writer);
+  json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']');
+  writer->container_empty = 0;
+  writer->got_key = 0;
+}
+
+void grpc_json_writer_object_key(grpc_json_writer *writer, const char *string) {
+  json_writer_value_end(writer);
+  json_writer_output_indent(writer);
+  json_writer_escape_string(writer, string);
+  json_writer_output_char(writer, ':');
+  writer->got_key = 1;
+}
+
+void grpc_json_writer_value_raw(grpc_json_writer *writer, const char *string) {
+  if (!writer->got_key) json_writer_value_end(writer);
+  json_writer_output_indent(writer);
+  json_writer_output_string(writer, string);
+  writer->got_key = 0;
+}
+
+void grpc_json_writer_value_raw_with_len(grpc_json_writer *writer,
+                                         const char *string, size_t len) {
+  if (!writer->got_key) json_writer_value_end(writer);
+  json_writer_output_indent(writer);
+  json_writer_output_string_with_len(writer, string, len);
+  writer->got_key = 0;
+}
+
+void grpc_json_writer_value_string(grpc_json_writer *writer,
+                                   const char *string) {
+  if (!writer->got_key) json_writer_value_end(writer);
+  json_writer_output_indent(writer);
+  json_writer_escape_string(writer, string);
+  writer->got_key = 0;
+}
diff --git a/src/core/lib/json/json_writer.h b/src/core/lib/json/json_writer.h
new file mode 100644
index 0000000..f90e79c
--- /dev/null
+++ b/src/core/lib/json/json_writer.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* The idea of the writer is basically symmetrical of the reader. While the
+ * reader emits various calls to your code, the writer takes basically the
+ * same calls and emit json out of it. It doesn't try to make any check on
+ * the order of the calls you do on it. Meaning you can theorically force
+ * it to generate invalid json.
+ *
+ * Also, unlike the reader, the writer expects UTF-8 encoded input strings.
+ * These strings will be UTF-8 validated, and any invalid character will
+ * cut the conversion short, before any invalid UTF-8 sequence, thus forming
+ * a valid UTF-8 string overall.
+ */
+
+#ifndef GRPC_CORE_LIB_JSON_JSON_WRITER_H
+#define GRPC_CORE_LIB_JSON_JSON_WRITER_H
+
+#include <stdlib.h>
+
+#include "src/core/lib/json/json_common.h"
+
+typedef struct grpc_json_writer_vtable {
+  /* Adds a character to the output stream. */
+  void (*output_char)(void *userdata, char);
+  /* Adds a zero-terminated string to the output stream. */
+  void (*output_string)(void *userdata, const char *str);
+  /* Adds a fixed-length string to the output stream. */
+  void (*output_string_with_len)(void *userdata, const char *str, size_t len);
+
+} grpc_json_writer_vtable;
+
+typedef struct grpc_json_writer {
+  void *userdata;
+  grpc_json_writer_vtable *vtable;
+  int indent;
+  int depth;
+  int container_empty;
+  int got_key;
+} grpc_json_writer;
+
+/* Call this to initialize your writer structure. The indent parameter is
+ * specifying the number of spaces to use for indenting the output. If you
+ * use indent=0, then the output will not have any newlines either, thus
+ * emitting a condensed json output.
+ */
+void grpc_json_writer_init(grpc_json_writer *writer, int indent,
+                           grpc_json_writer_vtable *vtable, void *userdata);
+
+/* Signals the beginning of a container. */
+void grpc_json_writer_container_begins(grpc_json_writer *writer,
+                                       grpc_json_type type);
+/* Signals the end of a container. */
+void grpc_json_writer_container_ends(grpc_json_writer *writer,
+                                     grpc_json_type type);
+/* Writes down an object key for the next value. */
+void grpc_json_writer_object_key(grpc_json_writer *writer, const char *string);
+/* Sets a raw value. Useful for numbers. */
+void grpc_json_writer_value_raw(grpc_json_writer *writer, const char *string);
+/* Sets a raw value with its length. Useful for values like true or false. */
+void grpc_json_writer_value_raw_with_len(grpc_json_writer *writer,
+                                         const char *string, size_t len);
+/* Sets a string value. It'll be escaped, and utf-8 validated. */
+void grpc_json_writer_value_string(grpc_json_writer *writer,
+                                   const char *string);
+
+#endif /* GRPC_CORE_LIB_JSON_JSON_WRITER_H */
diff --git a/src/core/lib/profiling/basic_timers.c b/src/core/lib/profiling/basic_timers.c
new file mode 100644
index 0000000..15a9584
--- /dev/null
+++ b/src/core/lib/profiling/basic_timers.c
@@ -0,0 +1,274 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GRPC_BASIC_PROFILER
+
+#include "src/core/lib/profiling/timers.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include <stdio.h>
+
+typedef enum { BEGIN = '{', END = '}', MARK = '.' } marker_type;
+
+typedef struct gpr_timer_entry {
+  gpr_timespec tm;
+  const char *tagstr;
+  const char *file;
+  short line;
+  char type;
+  uint8_t important;
+  int thd;
+} gpr_timer_entry;
+
+#define MAX_COUNT 1000000
+
+typedef struct gpr_timer_log {
+  size_t num_entries;
+  struct gpr_timer_log *next;
+  struct gpr_timer_log *prev;
+  gpr_timer_entry log[MAX_COUNT];
+} gpr_timer_log;
+
+typedef struct gpr_timer_log_list {
+  gpr_timer_log *head;
+  /* valid iff head!=NULL */
+  gpr_timer_log *tail;
+} gpr_timer_log_list;
+
+static __thread gpr_timer_log *g_thread_log;
+static gpr_once g_once_init = GPR_ONCE_INIT;
+static FILE *output_file;
+static const char *output_filename = "latency_trace.txt";
+static pthread_mutex_t g_mu;
+static pthread_cond_t g_cv;
+static gpr_timer_log_list g_in_progress_logs;
+static gpr_timer_log_list g_done_logs;
+static int g_shutdown;
+static gpr_thd_id g_writing_thread;
+static __thread int g_thread_id;
+static int g_next_thread_id;
+
+static int timer_log_push_back(gpr_timer_log_list *list, gpr_timer_log *log) {
+  if (list->head == NULL) {
+    list->head = list->tail = log;
+    log->next = log->prev = NULL;
+    return 1;
+  } else {
+    log->prev = list->tail;
+    log->next = NULL;
+    list->tail->next = log;
+    list->tail = log;
+    return 0;
+  }
+}
+
+static gpr_timer_log *timer_log_pop_front(gpr_timer_log_list *list) {
+  gpr_timer_log *out = list->head;
+  if (out != NULL) {
+    list->head = out->next;
+    if (list->head != NULL) {
+      list->head->prev = NULL;
+    } else {
+      list->tail = NULL;
+    }
+  }
+  return out;
+}
+
+static void timer_log_remove(gpr_timer_log_list *list, gpr_timer_log *log) {
+  if (log->prev == NULL) {
+    list->head = log->next;
+    if (list->head != NULL) {
+      list->head->prev = NULL;
+    }
+  } else {
+    log->prev->next = log->next;
+  }
+  if (log->next == NULL) {
+    list->tail = log->prev;
+    if (list->tail != NULL) {
+      list->tail->next = NULL;
+    }
+  } else {
+    log->next->prev = log->prev;
+  }
+}
+
+static void write_log(gpr_timer_log *log) {
+  size_t i;
+  if (output_file == NULL) {
+    output_file = fopen(output_filename, "w");
+  }
+  for (i = 0; i < log->num_entries; i++) {
+    gpr_timer_entry *entry = &(log->log[i]);
+    if (gpr_time_cmp(entry->tm, gpr_time_0(entry->tm.clock_type)) < 0) {
+      entry->tm = gpr_time_0(entry->tm.clock_type);
+    }
+    fprintf(output_file,
+            "{\"t\": %lld.%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": "
+            "\"%s\", \"file\": \"%s\", \"line\": %d, \"imp\": %d}\n",
+            (long long)entry->tm.tv_sec, (int)entry->tm.tv_nsec, entry->thd,
+            entry->type, entry->tagstr, entry->file, entry->line,
+            entry->important);
+  }
+}
+
+static void writing_thread(void *unused) {
+  gpr_timer_log *log;
+  pthread_mutex_lock(&g_mu);
+  for (;;) {
+    while ((log = timer_log_pop_front(&g_done_logs)) == NULL && !g_shutdown) {
+      pthread_cond_wait(&g_cv, &g_mu);
+    }
+    if (log != NULL) {
+      pthread_mutex_unlock(&g_mu);
+      write_log(log);
+      free(log);
+      pthread_mutex_lock(&g_mu);
+    }
+    if (g_shutdown) {
+      pthread_mutex_unlock(&g_mu);
+      return;
+    }
+  }
+}
+
+static void flush_logs(gpr_timer_log_list *list) {
+  gpr_timer_log *log;
+  while ((log = timer_log_pop_front(list)) != NULL) {
+    write_log(log);
+    free(log);
+  }
+}
+
+static void finish_writing() {
+  pthread_mutex_lock(&g_mu);
+  g_shutdown = 1;
+  pthread_cond_signal(&g_cv);
+  pthread_mutex_unlock(&g_mu);
+  gpr_thd_join(g_writing_thread);
+
+  gpr_log(GPR_INFO, "flushing logs");
+
+  pthread_mutex_lock(&g_mu);
+  flush_logs(&g_done_logs);
+  flush_logs(&g_in_progress_logs);
+  pthread_mutex_unlock(&g_mu);
+
+  if (output_file) {
+    fclose(output_file);
+  }
+}
+
+void gpr_timers_set_log_filename(const char *filename) {
+  output_filename = filename;
+}
+
+static void init_output() {
+  gpr_thd_options options = gpr_thd_options_default();
+  gpr_thd_options_set_joinable(&options);
+  gpr_thd_new(&g_writing_thread, writing_thread, NULL, &options);
+  atexit(finish_writing);
+}
+
+static void rotate_log() {
+  gpr_timer_log *new = malloc(sizeof(*new));
+  gpr_once_init(&g_once_init, init_output);
+  new->num_entries = 0;
+  pthread_mutex_lock(&g_mu);
+  if (g_thread_log != NULL) {
+    timer_log_remove(&g_in_progress_logs, g_thread_log);
+    if (timer_log_push_back(&g_done_logs, g_thread_log)) {
+      pthread_cond_signal(&g_cv);
+    }
+  } else {
+    g_thread_id = g_next_thread_id++;
+  }
+  timer_log_push_back(&g_in_progress_logs, new);
+  pthread_mutex_unlock(&g_mu);
+  g_thread_log = new;
+}
+
+static void gpr_timers_log_add(const char *tagstr, marker_type type,
+                               int important, const char *file, int line) {
+  gpr_timer_entry *entry;
+
+  if (g_thread_log == NULL || g_thread_log->num_entries == MAX_COUNT) {
+    rotate_log();
+  }
+
+  entry = &g_thread_log->log[g_thread_log->num_entries++];
+
+  entry->tm = gpr_now(GPR_CLOCK_PRECISE);
+  entry->tagstr = tagstr;
+  entry->type = type;
+  entry->file = file;
+  entry->line = (short)line;
+  entry->important = important != 0;
+  entry->thd = g_thread_id;
+}
+
+/* Latency profiler API implementation. */
+void gpr_timer_add_mark(const char *tagstr, int important, const char *file,
+                        int line) {
+  gpr_timers_log_add(tagstr, MARK, important, file, line);
+}
+
+void gpr_timer_begin(const char *tagstr, int important, const char *file,
+                     int line) {
+  gpr_timers_log_add(tagstr, BEGIN, important, file, line);
+}
+
+void gpr_timer_end(const char *tagstr, int important, const char *file,
+                   int line) {
+  gpr_timers_log_add(tagstr, END, important, file, line);
+}
+
+/* Basic profiler specific API functions. */
+void gpr_timers_global_init(void) {}
+
+void gpr_timers_global_destroy(void) {}
+
+#else  /* !GRPC_BASIC_PROFILER */
+void gpr_timers_global_init(void) {}
+
+void gpr_timers_global_destroy(void) {}
+
+void gpr_timers_set_log_filename(const char *filename) {}
+#endif /* GRPC_BASIC_PROFILER */
diff --git a/src/core/profiling/stap_probes.d b/src/core/lib/profiling/stap_probes.d
similarity index 100%
rename from src/core/profiling/stap_probes.d
rename to src/core/lib/profiling/stap_probes.d
diff --git a/src/core/lib/profiling/stap_timers.c b/src/core/lib/profiling/stap_timers.c
new file mode 100644
index 0000000..f55c1a5
--- /dev/null
+++ b/src/core/lib/profiling/stap_timers.c
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GRPC_STAP_PROFILER
+
+#include "src/core/lib/profiling/timers.h"
+
+#include <sys/sdt.h>
+/* Generated from src/core/profiling/stap_probes.d */
+#include "src/core/lib/profiling/stap_probes.h"
+
+/* Latency profiler API implementation. */
+void gpr_timer_add_mark(int tag, const char *tagstr, void *id, const char *file,
+                        int line) {
+  _STAP_ADD_MARK(tag);
+}
+
+void gpr_timer_add_important_mark(int tag, const char *tagstr, void *id,
+                                  const char *file, int line) {
+  _STAP_ADD_IMPORTANT_MARK(tag);
+}
+
+void gpr_timer_begin(int tag, const char *tagstr, void *id, const char *file,
+                     int line) {
+  _STAP_TIMING_NS_BEGIN(tag);
+}
+
+void gpr_timer_end(int tag, const char *tagstr, void *id, const char *file,
+                   int line) {
+  _STAP_TIMING_NS_END(tag);
+}
+
+#endif /* GRPC_STAP_PROFILER */
diff --git a/src/core/lib/profiling/timers.h b/src/core/lib/profiling/timers.h
new file mode 100644
index 0000000..1303593
--- /dev/null
+++ b/src/core/lib/profiling/timers.h
@@ -0,0 +1,119 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_PROFILING_TIMERS_H
+#define GRPC_CORE_LIB_PROFILING_TIMERS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gpr_timers_global_init(void);
+void gpr_timers_global_destroy(void);
+
+void gpr_timer_add_mark(const char *tagstr, int important, const char *file,
+                        int line);
+void gpr_timer_begin(const char *tagstr, int important, const char *file,
+                     int line);
+void gpr_timer_end(const char *tagstr, int important, const char *file,
+                   int line);
+
+void gpr_timers_set_log_filename(const char *filename);
+
+#if !(defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER))
+/* No profiling. No-op all the things. */
+#define GPR_TIMER_MARK(tag, important) \
+  do {                                 \
+  } while (0)
+
+#define GPR_TIMER_BEGIN(tag, important) \
+  do {                                  \
+  } while (0)
+
+#define GPR_TIMER_END(tag, important) \
+  do {                                \
+  } while (0)
+
+#else /* at least one profiler requested... */
+/* ... hopefully only one. */
+#if defined(GRPC_STAP_PROFILER) && defined(GRPC_BASIC_PROFILER)
+#error "GRPC_STAP_PROFILER and GRPC_BASIC_PROFILER are mutually exclusive."
+#endif
+
+/* Generic profiling interface. */
+#define GPR_TIMER_MARK(tag, important) \
+  gpr_timer_add_mark(tag, important, __FILE__, __LINE__);
+
+#define GPR_TIMER_BEGIN(tag, important) \
+  gpr_timer_begin(tag, important, __FILE__, __LINE__);
+
+#define GPR_TIMER_END(tag, important) \
+  gpr_timer_end(tag, important, __FILE__, __LINE__);
+
+#ifdef GRPC_STAP_PROFILER
+/* Empty placeholder for now. */
+#endif /* GRPC_STAP_PROFILER */
+
+#ifdef GRPC_BASIC_PROFILER
+/* Empty placeholder for now. */
+#endif /* GRPC_BASIC_PROFILER */
+
+#endif /* at least one profiler requested. */
+
+#ifdef __cplusplus
+}
+
+#if (defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER))
+namespace grpc {
+class ProfileScope {
+ public:
+  ProfileScope(const char *desc, bool important) : desc_(desc) {
+    GPR_TIMER_BEGIN(desc_, important ? 1 : 0);
+  }
+  ~ProfileScope() { GPR_TIMER_END(desc_, 0); }
+
+ private:
+  const char *const desc_;
+};
+}
+
+#define GPR_TIMER_SCOPE(tag, important) \
+  ::grpc::ProfileScope _profile_scope_##__LINE__((tag), (important))
+#else
+#define GPR_TIMER_SCOPE(tag, important) \
+  do {                                  \
+  } while (false)
+#endif
+#endif
+
+#endif /* GRPC_CORE_LIB_PROFILING_TIMERS_H */
diff --git a/src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c b/src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c
new file mode 100644
index 0000000..8f82141
--- /dev/null
+++ b/src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c
@@ -0,0 +1,119 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Automatically generated nanopb constant definitions */
+/* Generated by nanopb-0.3.5-dev */
+
+#include "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h"
+
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+
+const pb_field_t grpc_lb_v0_Duration_fields[3] = {
+    PB_FIELD(  1, INT64   , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_Duration, seconds, seconds, 0),
+    PB_FIELD(  2, INT32   , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_Duration, nanos, seconds, 0),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_lb_v0_LoadBalanceRequest_fields[3] = {
+    PB_FIELD(  1, MESSAGE , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_LoadBalanceRequest, initial_request, initial_request, &grpc_lb_v0_InitialLoadBalanceRequest_fields),
+    PB_FIELD(  2, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_LoadBalanceRequest, client_stats, initial_request, &grpc_lb_v0_ClientStats_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_lb_v0_InitialLoadBalanceRequest_fields[2] = {
+    PB_FIELD(  1, STRING  , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_InitialLoadBalanceRequest, name, name, 0),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_lb_v0_ClientStats_fields[4] = {
+    PB_FIELD(  1, INT64   , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_ClientStats, total_requests, total_requests, 0),
+    PB_FIELD(  2, INT64   , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_ClientStats, client_rpc_errors, total_requests, 0),
+    PB_FIELD(  3, INT64   , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_ClientStats, dropped_requests, client_rpc_errors, 0),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_lb_v0_LoadBalanceResponse_fields[3] = {
+    PB_FIELD(  1, MESSAGE , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_LoadBalanceResponse, initial_response, initial_response, &grpc_lb_v0_InitialLoadBalanceResponse_fields),
+    PB_FIELD(  2, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_LoadBalanceResponse, server_list, initial_response, &grpc_lb_v0_ServerList_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_lb_v0_InitialLoadBalanceResponse_fields[4] = {
+    PB_FIELD(  1, STRING  , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_InitialLoadBalanceResponse, client_config, client_config, 0),
+    PB_FIELD(  2, STRING  , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_InitialLoadBalanceResponse, load_balancer_delegate, client_config, 0),
+    PB_FIELD(  3, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval, load_balancer_delegate, &grpc_lb_v0_Duration_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_lb_v0_ServerList_fields[3] = {
+    PB_FIELD(  1, MESSAGE , REPEATED, CALLBACK, FIRST, grpc_lb_v0_ServerList, servers, servers, &grpc_lb_v0_Server_fields),
+    PB_FIELD(  3, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_ServerList, expiration_interval, servers, &grpc_lb_v0_Duration_fields),
+    PB_LAST_FIELD
+};
+
+const pb_field_t grpc_lb_v0_Server_fields[5] = {
+    PB_FIELD(  1, STRING  , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_Server, ip_address, ip_address, 0),
+    PB_FIELD(  2, INT32   , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_Server, port, ip_address, 0),
+    PB_FIELD(  3, BYTES   , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_Server, load_balance_token, port, 0),
+    PB_FIELD(  4, BOOL    , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_Server, drop_request, load_balance_token, 0),
+    PB_LAST_FIELD
+};
+
+
+/* Check that field information fits in pb_field_t */
+#if !defined(PB_FIELD_32BIT)
+/* If you get an error here, it means that you need to define PB_FIELD_32BIT
+ * compile-time option. You can do that in pb.h or on compiler command line.
+ * 
+ * The reason you need to do this is that some of your messages contain tag
+ * numbers or field sizes that are larger than what can fit in 8 or 16 bit
+ * field descriptors.
+ */
+PB_STATIC_ASSERT((pb_membersize(grpc_lb_v0_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v0_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v0_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v0_Duration_grpc_lb_v0_LoadBalanceRequest_grpc_lb_v0_InitialLoadBalanceRequest_grpc_lb_v0_ClientStats_grpc_lb_v0_LoadBalanceResponse_grpc_lb_v0_InitialLoadBalanceResponse_grpc_lb_v0_ServerList_grpc_lb_v0_Server)
+#endif
+
+#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
+/* If you get an error here, it means that you need to define PB_FIELD_16BIT
+ * compile-time option. You can do that in pb.h or on compiler command line.
+ * 
+ * The reason you need to do this is that some of your messages contain tag
+ * numbers or field sizes that are larger than what can fit in the default
+ * 8 bit descriptors.
+ */
+PB_STATIC_ASSERT((pb_membersize(grpc_lb_v0_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v0_ServerList, servers) < 256 && pb_membersize(grpc_lb_v0_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v0_Duration_grpc_lb_v0_LoadBalanceRequest_grpc_lb_v0_InitialLoadBalanceRequest_grpc_lb_v0_ClientStats_grpc_lb_v0_LoadBalanceResponse_grpc_lb_v0_InitialLoadBalanceResponse_grpc_lb_v0_ServerList_grpc_lb_v0_Server)
+#endif
+
+
diff --git a/src/core/proto/grpc/lb/v0/load_balancer.pb.h b/src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h
similarity index 100%
rename from src/core/proto/grpc/lb/v0/load_balancer.pb.h
rename to src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h
diff --git a/src/core/lib/security/auth_filters.h b/src/core/lib/security/auth_filters.h
new file mode 100644
index 0000000..162b60e
--- /dev/null
+++ b/src/core/lib/security/auth_filters.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_AUTH_FILTERS_H
+#define GRPC_CORE_LIB_SECURITY_AUTH_FILTERS_H
+
+#include "src/core/lib/channel/channel_stack.h"
+
+extern const grpc_channel_filter grpc_client_auth_filter;
+extern const grpc_channel_filter grpc_server_auth_filter;
+
+#endif /* GRPC_CORE_LIB_SECURITY_AUTH_FILTERS_H */
diff --git a/src/core/lib/security/b64.c b/src/core/lib/security/b64.c
new file mode 100644
index 0000000..1d38795
--- /dev/null
+++ b/src/core/lib/security/b64.c
@@ -0,0 +1,233 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/security/b64.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+/* --- Constants. --- */
+
+static const int8_t base64_bytes[] = {
+    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+    -1,   -1,   -1,   -1,   -1,   -1,   -1,   0x3E, -1,   -1,   -1,   0x3F,
+    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, -1,   -1,
+    -1,   0x7F, -1,   -1,   -1,   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+    0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
+    0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, -1,   -1,   -1,   -1,   -1,
+    -1,   0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
+    0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
+    0x31, 0x32, 0x33, -1,   -1,   -1,   -1,   -1};
+
+static const char base64_url_unsafe_chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char base64_url_safe_chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+#define GRPC_BASE64_PAD_CHAR '='
+#define GRPC_BASE64_PAD_BYTE 0x7F
+#define GRPC_BASE64_MULTILINE_LINE_LEN 76
+#define GRPC_BASE64_MULTILINE_NUM_BLOCKS (GRPC_BASE64_MULTILINE_LINE_LEN / 4)
+
+/* --- base64 functions. --- */
+
+char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe,
+                         int multiline) {
+  const unsigned char *data = vdata;
+  const char *base64_chars =
+      url_safe ? base64_url_safe_chars : base64_url_unsafe_chars;
+  size_t result_projected_size =
+      4 * ((data_size + 3) / 3) +
+      2 * (multiline ? (data_size / (3 * GRPC_BASE64_MULTILINE_NUM_BLOCKS))
+                     : 0) +
+      1;
+  char *result = gpr_malloc(result_projected_size);
+  char *current = result;
+  size_t num_blocks = 0;
+  size_t i = 0;
+
+  /* Encode each block. */
+  while (data_size >= 3) {
+    *current++ = base64_chars[(data[i] >> 2) & 0x3F];
+    *current++ =
+        base64_chars[((data[i] & 0x03) << 4) | ((data[i + 1] >> 4) & 0x0F)];
+    *current++ =
+        base64_chars[((data[i + 1] & 0x0F) << 2) | ((data[i + 2] >> 6) & 0x03)];
+    *current++ = base64_chars[data[i + 2] & 0x3F];
+
+    data_size -= 3;
+    i += 3;
+    if (multiline && (++num_blocks == GRPC_BASE64_MULTILINE_NUM_BLOCKS)) {
+      *current++ = '\r';
+      *current++ = '\n';
+      num_blocks = 0;
+    }
+  }
+
+  /* Take care of the tail. */
+  if (data_size == 2) {
+    *current++ = base64_chars[(data[i] >> 2) & 0x3F];
+    *current++ =
+        base64_chars[((data[i] & 0x03) << 4) | ((data[i + 1] >> 4) & 0x0F)];
+    *current++ = base64_chars[(data[i + 1] & 0x0F) << 2];
+    *current++ = GRPC_BASE64_PAD_CHAR;
+  } else if (data_size == 1) {
+    *current++ = base64_chars[(data[i] >> 2) & 0x3F];
+    *current++ = base64_chars[(data[i] & 0x03) << 4];
+    *current++ = GRPC_BASE64_PAD_CHAR;
+    *current++ = GRPC_BASE64_PAD_CHAR;
+  }
+
+  GPR_ASSERT(current >= result);
+  GPR_ASSERT((uintptr_t)(current - result) < result_projected_size);
+  result[current - result] = '\0';
+  return result;
+}
+
+gpr_slice grpc_base64_decode(const char *b64, int url_safe) {
+  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) {
+  uint32_t packed = ((uint32_t)codes[0] << 2) | ((uint32_t)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) {
+  uint32_t packed = ((uint32_t)codes[0] << 10) | ((uint32_t)codes[1] << 4) |
+                    ((uint32_t)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. */
+    uint32_t packed = ((uint32_t)codes[0] << 18) | ((uint32_t)codes[1] << 12) |
+                      ((uint32_t)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;
+  unsigned char codes[4];
+  size_t num_codes = 0;
+
+  while (b64_len--) {
+    unsigned char c = (unsigned char)(*b64++);
+    signed char code;
+    if (c >= GPR_ARRAY_SIZE(base64_bytes)) continue;
+    if (url_safe) {
+      if (c == '+' || c == '/') {
+        gpr_log(GPR_ERROR, "Invalid character for url safe base64 %c", c);
+        goto fail;
+      }
+      if (c == '-') {
+        c = '+';
+      } else if (c == '_') {
+        c = '/';
+      }
+    }
+    code = base64_bytes[c];
+    if (code == -1) {
+      if (c != '\r' && c != '\n') {
+        gpr_log(GPR_ERROR, "Invalid character %c", c);
+        goto fail;
+      }
+    } else {
+      codes[num_codes++] = (unsigned char)code;
+      if (num_codes == 4) {
+        if (!decode_group(codes, num_codes, current, &result_size)) goto fail;
+        num_codes = 0;
+      }
+    }
+  }
+
+  if (num_codes != 0 &&
+      !decode_group(codes, num_codes, current, &result_size)) {
+    goto fail;
+  }
+  GPR_SLICE_SET_LENGTH(result, result_size);
+  return result;
+
+fail:
+  gpr_slice_unref(result);
+  return gpr_empty_slice();
+}
diff --git a/src/core/lib/security/b64.h b/src/core/lib/security/b64.h
new file mode 100644
index 0000000..0bf372a
--- /dev/null
+++ b/src/core/lib/security/b64.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_B64_H
+#define GRPC_CORE_LIB_SECURITY_B64_H
+
+#include <grpc/support/slice.h>
+
+/* Encodes data using base64. It is the caller's responsability to free
+   the returned char * using gpr_free. Returns NULL on NULL input. */
+char *grpc_base64_encode(const void *data, size_t data_size, int url_safe,
+                         int multiline);
+
+/* Decodes data according to the base64 specification. Returns an empty
+   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_CORE_LIB_SECURITY_B64_H */
diff --git a/src/core/lib/security/client_auth_filter.c b/src/core/lib/security/client_auth_filter.c
new file mode 100644
index 0000000..af6073e
--- /dev/null
+++ b/src/core/lib/security/client_auth_filter.c
@@ -0,0 +1,336 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/security/auth_filters.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/security/security_connector.h"
+#include "src/core/lib/security/security_context.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/call.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#define MAX_CREDENTIALS_METADATA_COUNT 4
+
+/* We can have a per-call credentials. */
+typedef struct {
+  grpc_call_credentials *creds;
+  grpc_mdstr *host;
+  grpc_mdstr *method;
+  /* 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;
+  uint8_t security_context_set;
+  grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
+  grpc_auth_metadata_context auth_md_context;
+} call_data;
+
+/* We can have a per-channel credentials. */
+typedef struct {
+  grpc_channel_security_connector *security_connector;
+  grpc_auth_context *auth_context;
+} channel_data;
+
+static void reset_auth_metadata_context(
+    grpc_auth_metadata_context *auth_md_context) {
+  if (auth_md_context->service_url != NULL) {
+    gpr_free((char *)auth_md_context->service_url);
+    auth_md_context->service_url = NULL;
+  }
+  if (auth_md_context->method_name != NULL) {
+    gpr_free((char *)auth_md_context->method_name);
+    auth_md_context->method_name = NULL;
+  }
+  GRPC_AUTH_CONTEXT_UNREF(
+      (grpc_auth_context *)auth_md_context->channel_auth_context,
+      "grpc_auth_metadata_context");
+  auth_md_context->channel_auth_context = NULL;
+}
+
+static void bubble_up_error(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                            grpc_status_code status, const char *error_msg) {
+  call_data *calld = elem->call_data;
+  gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg);
+  grpc_transport_stream_op_add_cancellation(&calld->op, status);
+  grpc_call_next_op(exec_ctx, elem, &calld->op);
+}
+
+static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
+                                    grpc_credentials_md *md_elems,
+                                    size_t num_md,
+                                    grpc_credentials_status status) {
+  grpc_call_element *elem = (grpc_call_element *)user_data;
+  call_data *calld = elem->call_data;
+  grpc_transport_stream_op *op = &calld->op;
+  grpc_metadata_batch *mdb;
+  size_t i;
+  reset_auth_metadata_context(&calld->auth_md_context);
+  if (status != GRPC_CREDENTIALS_OK) {
+    bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED,
+                    "Credentials failed to get metadata.");
+    return;
+  }
+  GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT);
+  GPR_ASSERT(op->send_initial_metadata != NULL);
+  mdb = op->send_initial_metadata;
+  for (i = 0; i < num_md; i++) {
+    grpc_metadata_batch_add_tail(
+        mdb, &calld->md_links[i],
+        grpc_mdelem_from_slices(gpr_slice_ref(md_elems[i].key),
+                                gpr_slice_ref(md_elems[i].value)));
+  }
+  grpc_call_next_op(exec_ctx, elem, op);
+}
+
+void build_auth_metadata_context(grpc_security_connector *sc,
+                                 grpc_auth_context *auth_context,
+                                 call_data *calld) {
+  char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method));
+  char *last_slash = strrchr(service, '/');
+  char *method_name = NULL;
+  char *service_url = NULL;
+  reset_auth_metadata_context(&calld->auth_md_context);
+  if (last_slash == NULL) {
+    gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
+    service[0] = '\0';
+  } else if (last_slash == service) {
+    /* No service part in fully qualified method name: will just be "/". */
+    service[1] = '\0';
+  } else {
+    *last_slash = '\0';
+    method_name = gpr_strdup(last_slash + 1);
+  }
+  if (method_name == NULL) method_name = gpr_strdup("");
+  gpr_asprintf(&service_url, "%s://%s%s",
+               sc->url_scheme == NULL ? "" : sc->url_scheme,
+               grpc_mdstr_as_c_string(calld->host), service);
+  calld->auth_md_context.service_url = service_url;
+  calld->auth_md_context.method_name = method_name;
+  calld->auth_md_context.channel_auth_context =
+      GRPC_AUTH_CONTEXT_REF(auth_context, "grpc_auth_metadata_context");
+  gpr_free(service);
+}
+
+static void send_security_metadata(grpc_exec_ctx *exec_ctx,
+                                   grpc_call_element *elem,
+                                   grpc_transport_stream_op *op) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  grpc_client_security_context *ctx =
+      (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value;
+  grpc_call_credentials *channel_call_creds =
+      chand->security_connector->request_metadata_creds;
+  int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL);
+
+  if (channel_call_creds == NULL && !call_creds_has_md) {
+    /* Skip sending metadata altogether. */
+    grpc_call_next_op(exec_ctx, elem, op);
+    return;
+  }
+
+  if (channel_call_creds != NULL && call_creds_has_md) {
+    calld->creds = grpc_composite_call_credentials_create(channel_call_creds,
+                                                          ctx->creds, NULL);
+    if (calld->creds == NULL) {
+      bubble_up_error(exec_ctx, elem, GRPC_STATUS_INTERNAL,
+                      "Incompatible credentials set on channel and call.");
+      return;
+    }
+  } else {
+    calld->creds = grpc_call_credentials_ref(
+        call_creds_has_md ? ctx->creds : channel_call_creds);
+  }
+
+  build_auth_metadata_context(&chand->security_connector->base,
+                              chand->auth_context, calld);
+  calld->op = *op; /* Copy op (originates from the caller's stack). */
+  GPR_ASSERT(calld->pollset);
+  grpc_call_credentials_get_request_metadata(
+      exec_ctx, calld->creds, calld->pollset, calld->auth_md_context,
+      on_credentials_metadata, elem);
+}
+
+static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data,
+                            grpc_security_status status) {
+  grpc_call_element *elem = (grpc_call_element *)user_data;
+  call_data *calld = elem->call_data;
+
+  if (status == GRPC_SECURITY_OK) {
+    send_security_metadata(exec_ctx, elem, &calld->op);
+  } else {
+    char *error_msg;
+    gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.",
+                 grpc_mdstr_as_c_string(calld->host));
+    bubble_up_error(exec_ctx, elem, GRPC_STATUS_INTERNAL, error_msg);
+    gpr_free(error_msg);
+  }
+}
+
+/* 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 auth_start_transport_op(grpc_exec_ctx *exec_ctx,
+                                    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 *chand = elem->channel_data;
+  grpc_linked_mdelem *l;
+  grpc_client_security_context *sec_ctx = NULL;
+
+  if (calld->security_context_set == 0 &&
+      op->cancel_with_status == GRPC_STATUS_OK) {
+    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->auth_context, "client_auth_filter");
+  }
+
+  if (op->send_initial_metadata != NULL) {
+    for (l = op->send_initial_metadata->list.head; l != NULL; l = l->next) {
+      grpc_mdelem *md = l->md;
+      /* Pointer comparison is OK for md_elems created from the same context.
+       */
+      if (md->key == GRPC_MDSTR_AUTHORITY) {
+        if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host);
+        calld->host = GRPC_MDSTR_REF(md->value);
+      } else if (md->key == GRPC_MDSTR_PATH) {
+        if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method);
+        calld->method = GRPC_MDSTR_REF(md->value);
+      }
+    }
+    if (calld->host != NULL) {
+      const char *call_host = grpc_mdstr_as_c_string(calld->host);
+      calld->op = *op; /* Copy op (originates from the caller's stack). */
+      grpc_channel_security_connector_check_call_host(
+          exec_ctx, chand->security_connector, call_host, chand->auth_context,
+          on_host_checked, elem);
+      return; /* early exit */
+    }
+  }
+
+  /* pass control down the stack */
+  grpc_call_next_op(exec_ctx, elem, op);
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                           grpc_call_element_args *args) {
+  call_data *calld = elem->call_data;
+  memset(calld, 0, sizeof(*calld));
+}
+
+static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                        grpc_pollset *pollset) {
+  call_data *calld = elem->call_data;
+  calld->pollset = pollset;
+}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_call_element *elem) {
+  call_data *calld = elem->call_data;
+  grpc_call_credentials_unref(calld->creds);
+  if (calld->host != NULL) {
+    GRPC_MDSTR_UNREF(calld->host);
+  }
+  if (calld->method != NULL) {
+    GRPC_MDSTR_UNREF(calld->method);
+  }
+  reset_auth_metadata_context(&calld->auth_md_context);
+}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_channel_element *elem,
+                              grpc_channel_element_args *args) {
+  grpc_security_connector *sc =
+      grpc_find_security_connector_in_args(args->channel_args);
+  grpc_auth_context *auth_context =
+      grpc_find_auth_context_in_args(args->channel_args);
+
+  /* grab pointers to our data from the channel element */
+  channel_data *chand = elem->channel_data;
+
+  /* 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(!args->is_last);
+  GPR_ASSERT(sc != NULL);
+  GPR_ASSERT(auth_context != NULL);
+
+  /* initialize members */
+  chand->security_connector =
+      (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF(
+          sc, "client_auth_filter");
+  chand->auth_context =
+      GRPC_AUTH_CONTEXT_REF(auth_context, "client_auth_filter");
+}
+
+/* Destructor for channel data */
+static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem) {
+  /* grab pointers to our data from the channel element */
+  channel_data *chand = elem->channel_data;
+  grpc_channel_security_connector *sc = chand->security_connector;
+  if (sc != NULL) {
+    GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "client_auth_filter");
+  }
+  GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "client_auth_filter");
+}
+
+const grpc_channel_filter grpc_client_auth_filter = {
+    auth_start_transport_op, grpc_channel_next_op, sizeof(call_data),
+    init_call_elem,          set_pollset,          destroy_call_elem,
+    sizeof(channel_data),    init_channel_elem,    destroy_channel_elem,
+    grpc_call_next_get_peer, "client-auth"};
diff --git a/src/core/lib/security/credentials.c b/src/core/lib/security/credentials.c
new file mode 100644
index 0000000..99a07e5
--- /dev/null
+++ b/src/core/lib/security/credentials.c
@@ -0,0 +1,1281 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/security/credentials.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/http_client_filter.h"
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/http/parser.h"
+#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/api_trace.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/time.h>
+
+/* -- Common. -- */
+
+struct grpc_credentials_metadata_request {
+  grpc_call_credentials *creds;
+  grpc_credentials_metadata_cb cb;
+  void *user_data;
+};
+
+static grpc_credentials_metadata_request *
+grpc_credentials_metadata_request_create(grpc_call_credentials *creds,
+                                         grpc_credentials_metadata_cb cb,
+                                         void *user_data) {
+  grpc_credentials_metadata_request *r =
+      gpr_malloc(sizeof(grpc_credentials_metadata_request));
+  r->creds = grpc_call_credentials_ref(creds);
+  r->cb = cb;
+  r->user_data = user_data;
+  return r;
+}
+
+static void grpc_credentials_metadata_request_destroy(
+    grpc_credentials_metadata_request *r) {
+  grpc_call_credentials_unref(r->creds);
+  gpr_free(r);
+}
+
+grpc_channel_credentials *grpc_channel_credentials_ref(
+    grpc_channel_credentials *creds) {
+  if (creds == NULL) return NULL;
+  gpr_ref(&creds->refcount);
+  return creds;
+}
+
+void grpc_channel_credentials_unref(grpc_channel_credentials *creds) {
+  if (creds == NULL) return;
+  if (gpr_unref(&creds->refcount)) {
+    if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds);
+    gpr_free(creds);
+  }
+}
+
+void grpc_channel_credentials_release(grpc_channel_credentials *creds) {
+  GRPC_API_TRACE("grpc_channel_credentials_release(creds=%p)", 1, (creds));
+  grpc_channel_credentials_unref(creds);
+}
+
+grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds) {
+  if (creds == NULL) return NULL;
+  gpr_ref(&creds->refcount);
+  return creds;
+}
+
+void grpc_call_credentials_unref(grpc_call_credentials *creds) {
+  if (creds == NULL) return;
+  if (gpr_unref(&creds->refcount)) {
+    if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds);
+    gpr_free(creds);
+  }
+}
+
+void grpc_call_credentials_release(grpc_call_credentials *creds) {
+  GRPC_API_TRACE("grpc_call_credentials_release(creds=%p)", 1, (creds));
+  grpc_call_credentials_unref(creds);
+}
+
+void grpc_call_credentials_get_request_metadata(
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
+    grpc_pollset *pollset, grpc_auth_metadata_context context,
+    grpc_credentials_metadata_cb cb, void *user_data) {
+  if (creds == NULL || creds->vtable->get_request_metadata == NULL) {
+    if (cb != NULL) {
+      cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
+    }
+    return;
+  }
+  creds->vtable->get_request_metadata(exec_ctx, creds, pollset, context, cb,
+                                      user_data);
+}
+
+grpc_security_status grpc_channel_credentials_create_security_connector(
+    grpc_channel_credentials *channel_creds, const char *target,
+    const grpc_channel_args *args, grpc_channel_security_connector **sc,
+    grpc_channel_args **new_args) {
+  *new_args = NULL;
+  if (channel_creds == NULL) {
+    return GRPC_SECURITY_ERROR;
+  }
+  GPR_ASSERT(channel_creds->vtable->create_security_connector != NULL);
+  return channel_creds->vtable->create_security_connector(
+      channel_creds, NULL, target, args, sc, new_args);
+}
+
+grpc_server_credentials *grpc_server_credentials_ref(
+    grpc_server_credentials *creds) {
+  if (creds == NULL) return NULL;
+  gpr_ref(&creds->refcount);
+  return creds;
+}
+
+void grpc_server_credentials_unref(grpc_server_credentials *creds) {
+  if (creds == NULL) return;
+  if (gpr_unref(&creds->refcount)) {
+    if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds);
+    if (creds->processor.destroy != NULL && creds->processor.state != NULL) {
+      creds->processor.destroy(creds->processor.state);
+    }
+    gpr_free(creds);
+  }
+}
+
+void grpc_server_credentials_release(grpc_server_credentials *creds) {
+  GRPC_API_TRACE("grpc_server_credentials_release(creds=%p)", 1, (creds));
+  grpc_server_credentials_unref(creds);
+}
+
+grpc_security_status grpc_server_credentials_create_security_connector(
+    grpc_server_credentials *creds, grpc_server_security_connector **sc) {
+  if (creds == NULL || creds->vtable->create_security_connector == NULL) {
+    gpr_log(GPR_ERROR, "Server credentials cannot create security context.");
+    return GRPC_SECURITY_ERROR;
+  }
+  return creds->vtable->create_security_connector(creds, sc);
+}
+
+void grpc_server_credentials_set_auth_metadata_processor(
+    grpc_server_credentials *creds, grpc_auth_metadata_processor processor) {
+  GRPC_API_TRACE(
+      "grpc_server_credentials_set_auth_metadata_processor("
+      "creds=%p, "
+      "processor=grpc_auth_metadata_processor { process: %p, state: %p })",
+      3, (creds, (void *)(intptr_t)processor.process, processor.state));
+  if (creds == NULL) return;
+  if (creds->processor.destroy != NULL && creds->processor.state != NULL) {
+    creds->processor.destroy(creds->processor.state);
+  }
+  creds->processor = processor;
+}
+
+static void server_credentials_pointer_arg_destroy(void *p) {
+  grpc_server_credentials_unref(p);
+}
+
+static void *server_credentials_pointer_arg_copy(void *p) {
+  return grpc_server_credentials_ref(p);
+}
+
+static int server_credentials_pointer_cmp(void *a, void *b) {
+  return GPR_ICMP(a, b);
+}
+
+static const grpc_arg_pointer_vtable cred_ptr_vtable = {
+    server_credentials_pointer_arg_copy, server_credentials_pointer_arg_destroy,
+    server_credentials_pointer_cmp};
+
+grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *p) {
+  grpc_arg arg;
+  memset(&arg, 0, sizeof(grpc_arg));
+  arg.type = GRPC_ARG_POINTER;
+  arg.key = GRPC_SERVER_CREDENTIALS_ARG;
+  arg.value.pointer.p = p;
+  arg.value.pointer.vtable = &cred_ptr_vtable;
+  return arg;
+}
+
+grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg) {
+  if (strcmp(arg->key, GRPC_SERVER_CREDENTIALS_ARG) != 0) return NULL;
+  if (arg->type != GRPC_ARG_POINTER) {
+    gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
+            GRPC_SERVER_CREDENTIALS_ARG);
+    return NULL;
+  }
+  return arg->value.pointer.p;
+}
+
+grpc_server_credentials *grpc_find_server_credentials_in_args(
+    const grpc_channel_args *args) {
+  size_t i;
+  if (args == NULL) return NULL;
+  for (i = 0; i < args->num_args; i++) {
+    grpc_server_credentials *p =
+        grpc_server_credentials_from_arg(&args->args[i]);
+    if (p != NULL) return p;
+  }
+  return NULL;
+}
+
+/* -- Ssl credentials. -- */
+
+static void ssl_destruct(grpc_channel_credentials *creds) {
+  grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
+  if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
+  if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
+  if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
+}
+
+static void ssl_server_destruct(grpc_server_credentials *creds) {
+  grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
+  size_t i;
+  for (i = 0; i < c->config.num_key_cert_pairs; i++) {
+    if (c->config.pem_private_keys[i] != NULL) {
+      gpr_free(c->config.pem_private_keys[i]);
+    }
+    if (c->config.pem_cert_chains[i] != NULL) {
+      gpr_free(c->config.pem_cert_chains[i]);
+    }
+  }
+  if (c->config.pem_private_keys != NULL) gpr_free(c->config.pem_private_keys);
+  if (c->config.pem_private_keys_sizes != NULL) {
+    gpr_free(c->config.pem_private_keys_sizes);
+  }
+  if (c->config.pem_cert_chains != NULL) gpr_free(c->config.pem_cert_chains);
+  if (c->config.pem_cert_chains_sizes != NULL) {
+    gpr_free(c->config.pem_cert_chains_sizes);
+  }
+  if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
+}
+
+static grpc_security_status ssl_create_security_connector(
+    grpc_channel_credentials *creds, grpc_call_credentials *call_creds,
+    const char *target, const grpc_channel_args *args,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+  grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
+  grpc_security_status status = GRPC_SECURITY_OK;
+  size_t i = 0;
+  const char *overridden_target_name = NULL;
+  grpc_arg new_arg;
+
+  for (i = 0; args && i < args->num_args; i++) {
+    grpc_arg *arg = &args->args[i];
+    if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 &&
+        arg->type == GRPC_ARG_STRING) {
+      overridden_target_name = arg->value.string;
+      break;
+    }
+  }
+  status = grpc_ssl_channel_security_connector_create(
+      call_creds, &c->config, target, overridden_target_name, sc);
+  if (status != GRPC_SECURITY_OK) {
+    return status;
+  }
+  new_arg.type = GRPC_ARG_STRING;
+  new_arg.key = GRPC_ARG_HTTP2_SCHEME;
+  new_arg.value.string = "https";
+  *new_args = grpc_channel_args_copy_and_add(args, &new_arg, 1);
+  return status;
+}
+
+static grpc_security_status ssl_server_create_security_connector(
+    grpc_server_credentials *creds, grpc_server_security_connector **sc) {
+  grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
+  return grpc_ssl_server_security_connector_create(&c->config, sc);
+}
+
+static grpc_channel_credentials_vtable ssl_vtable = {
+    ssl_destruct, ssl_create_security_connector};
+
+static grpc_server_credentials_vtable ssl_server_vtable = {
+    ssl_server_destruct, ssl_server_create_security_connector};
+
+static void ssl_copy_key_material(const char *input, unsigned char **output,
+                                  size_t *output_size) {
+  *output_size = strlen(input);
+  *output = gpr_malloc(*output_size);
+  memcpy(*output, input, *output_size);
+}
+
+static void ssl_build_config(const char *pem_root_certs,
+                             grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
+                             grpc_ssl_config *config) {
+  if (pem_root_certs != NULL) {
+    ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
+                          &config->pem_root_certs_size);
+  }
+  if (pem_key_cert_pair != NULL) {
+    GPR_ASSERT(pem_key_cert_pair->private_key != NULL);
+    GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL);
+    ssl_copy_key_material(pem_key_cert_pair->private_key,
+                          &config->pem_private_key,
+                          &config->pem_private_key_size);
+    ssl_copy_key_material(pem_key_cert_pair->cert_chain,
+                          &config->pem_cert_chain,
+                          &config->pem_cert_chain_size);
+  }
+}
+
+static void ssl_build_server_config(
+    const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
+    size_t num_key_cert_pairs, int force_client_auth,
+    grpc_ssl_server_config *config) {
+  size_t i;
+  config->force_client_auth = force_client_auth;
+  if (pem_root_certs != NULL) {
+    ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
+                          &config->pem_root_certs_size);
+  }
+  if (num_key_cert_pairs > 0) {
+    GPR_ASSERT(pem_key_cert_pairs != NULL);
+    config->pem_private_keys =
+        gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *));
+    config->pem_cert_chains =
+        gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *));
+    config->pem_private_keys_sizes =
+        gpr_malloc(num_key_cert_pairs * sizeof(size_t));
+    config->pem_cert_chains_sizes =
+        gpr_malloc(num_key_cert_pairs * sizeof(size_t));
+  }
+  config->num_key_cert_pairs = num_key_cert_pairs;
+  for (i = 0; i < num_key_cert_pairs; i++) {
+    GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL);
+    GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL);
+    ssl_copy_key_material(pem_key_cert_pairs[i].private_key,
+                          &config->pem_private_keys[i],
+                          &config->pem_private_keys_sizes[i]);
+    ssl_copy_key_material(pem_key_cert_pairs[i].cert_chain,
+                          &config->pem_cert_chains[i],
+                          &config->pem_cert_chains_sizes[i]);
+  }
+}
+
+grpc_channel_credentials *grpc_ssl_credentials_create(
+    const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
+    void *reserved) {
+  grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials));
+  GRPC_API_TRACE(
+      "grpc_ssl_credentials_create(pem_root_certs=%s, "
+      "pem_key_cert_pair=%p, "
+      "reserved=%p)",
+      3, (pem_root_certs, pem_key_cert_pair, reserved));
+  GPR_ASSERT(reserved == NULL);
+  memset(c, 0, sizeof(grpc_ssl_credentials));
+  c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL;
+  c->base.vtable = &ssl_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  ssl_build_config(pem_root_certs, pem_key_cert_pair, &c->config);
+  return &c->base;
+}
+
+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, int force_client_auth, void *reserved) {
+  grpc_ssl_server_credentials *c =
+      gpr_malloc(sizeof(grpc_ssl_server_credentials));
+  GRPC_API_TRACE(
+      "grpc_ssl_server_credentials_create("
+      "pem_root_certs=%s, pem_key_cert_pairs=%p, num_key_cert_pairs=%lu, "
+      "force_client_auth=%d, reserved=%p)",
+      5, (pem_root_certs, pem_key_cert_pairs, (unsigned long)num_key_cert_pairs,
+          force_client_auth, reserved));
+  GPR_ASSERT(reserved == NULL);
+  memset(c, 0, sizeof(grpc_ssl_server_credentials));
+  c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL;
+  gpr_ref_init(&c->base.refcount, 1);
+  c->base.vtable = &ssl_server_vtable;
+  ssl_build_server_config(pem_root_certs, pem_key_cert_pairs,
+                          num_key_cert_pairs, force_client_auth, &c->config);
+  return &c->base;
+}
+
+/* -- Jwt credentials -- */
+
+static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) {
+  if (c->cached.jwt_md != NULL) {
+    grpc_credentials_md_store_unref(c->cached.jwt_md);
+    c->cached.jwt_md = NULL;
+  }
+  if (c->cached.service_url != NULL) {
+    gpr_free(c->cached.service_url);
+    c->cached.service_url = NULL;
+  }
+  c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
+}
+
+static void jwt_destruct(grpc_call_credentials *creds) {
+  grpc_service_account_jwt_access_credentials *c =
+      (grpc_service_account_jwt_access_credentials *)creds;
+  grpc_auth_json_key_destruct(&c->key);
+  jwt_reset_cache(c);
+  gpr_mu_destroy(&c->cache_mu);
+}
+
+static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx,
+                                     grpc_call_credentials *creds,
+                                     grpc_pollset *pollset,
+                                     grpc_auth_metadata_context context,
+                                     grpc_credentials_metadata_cb cb,
+                                     void *user_data) {
+  grpc_service_account_jwt_access_credentials *c =
+      (grpc_service_account_jwt_access_credentials *)creds;
+  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;
+  {
+    gpr_mu_lock(&c->cache_mu);
+    if (c->cached.service_url != NULL &&
+        strcmp(c->cached.service_url, context.service_url) == 0 &&
+        c->cached.jwt_md != NULL &&
+        (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);
+    }
+    gpr_mu_unlock(&c->cache_mu);
+  }
+
+  if (jwt_md == NULL) {
+    char *jwt = NULL;
+    /* Generate a new jwt. */
+    gpr_mu_lock(&c->cache_mu);
+    jwt_reset_cache(c);
+    jwt = grpc_jwt_encode_and_sign(&c->key, context.service_url,
+                                   c->jwt_lifetime, NULL);
+    if (jwt != NULL) {
+      char *md_value;
+      gpr_asprintf(&md_value, "Bearer %s", jwt);
+      gpr_free(jwt);
+      c->cached.jwt_expiration =
+          gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime);
+      c->cached.service_url = gpr_strdup(context.service_url);
+      c->cached.jwt_md = grpc_credentials_md_store_create(1);
+      grpc_credentials_md_store_add_cstrings(
+          c->cached.jwt_md, GRPC_AUTHORIZATION_METADATA_KEY, md_value);
+      gpr_free(md_value);
+      jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md);
+    }
+    gpr_mu_unlock(&c->cache_mu);
+  }
+
+  if (jwt_md != NULL) {
+    cb(exec_ctx, user_data, jwt_md->entries, jwt_md->num_entries,
+       GRPC_CREDENTIALS_OK);
+    grpc_credentials_md_store_unref(jwt_md);
+  } else {
+    cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_ERROR);
+  }
+}
+
+static grpc_call_credentials_vtable jwt_vtable = {jwt_destruct,
+                                                  jwt_get_request_metadata};
+
+grpc_call_credentials *
+grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
+    grpc_auth_json_key key, gpr_timespec token_lifetime) {
+  grpc_service_account_jwt_access_credentials *c;
+  if (!grpc_auth_json_key_is_valid(&key)) {
+    gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
+    return NULL;
+  }
+  c = gpr_malloc(sizeof(grpc_service_account_jwt_access_credentials));
+  memset(c, 0, sizeof(grpc_service_account_jwt_access_credentials));
+  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_JWT;
+  gpr_ref_init(&c->base.refcount, 1);
+  c->base.vtable = &jwt_vtable;
+  c->key = key;
+  c->jwt_lifetime = token_lifetime;
+  gpr_mu_init(&c->cache_mu);
+  jwt_reset_cache(c);
+  return &c->base;
+}
+
+grpc_call_credentials *grpc_service_account_jwt_access_credentials_create(
+    const char *json_key, gpr_timespec token_lifetime, void *reserved) {
+  GRPC_API_TRACE(
+      "grpc_service_account_jwt_access_credentials_create("
+      "json_key=%s, "
+      "token_lifetime="
+      "gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
+      "reserved=%p)",
+      5,
+      (json_key, (long long)token_lifetime.tv_sec, (int)token_lifetime.tv_nsec,
+       (int)token_lifetime.clock_type, reserved));
+  GPR_ASSERT(reserved == NULL);
+  return grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
+      grpc_auth_json_key_create_from_string(json_key), token_lifetime);
+}
+
+/* -- Oauth2TokenFetcher credentials -- */
+
+static void oauth2_token_fetcher_destruct(grpc_call_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);
+}
+
+grpc_credentials_status
+grpc_oauth2_token_fetcher_credentials_parse_server_response(
+    const grpc_http_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;
+  grpc_json *json = NULL;
+
+  if (response == NULL) {
+    gpr_log(GPR_ERROR, "Received NULL response.");
+    status = GRPC_CREDENTIALS_ERROR;
+    goto end;
+  }
+
+  if (response->body_length > 0) {
+    null_terminated_body = gpr_malloc(response->body_length + 1);
+    null_terminated_body[response->body_length] = '\0';
+    memcpy(null_terminated_body, response->body, response->body_length);
+  }
+
+  if (response->status != 200) {
+    gpr_log(GPR_ERROR, "Call to http server ended with error %d [%s].",
+            response->status,
+            null_terminated_body != NULL ? null_terminated_body : "");
+    status = GRPC_CREDENTIALS_ERROR;
+    goto end;
+  } else {
+    grpc_json *access_token = NULL;
+    grpc_json *token_type = NULL;
+    grpc_json *expires_in = NULL;
+    grpc_json *ptr;
+    json = grpc_json_parse_string(null_terminated_body);
+    if (json == NULL) {
+      gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body);
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    if (json->type != GRPC_JSON_OBJECT) {
+      gpr_log(GPR_ERROR, "Response should be a JSON object");
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    for (ptr = json->child; ptr; ptr = ptr->next) {
+      if (strcmp(ptr->key, "access_token") == 0) {
+        access_token = ptr;
+      } else if (strcmp(ptr->key, "token_type") == 0) {
+        token_type = ptr;
+      } else if (strcmp(ptr->key, "expires_in") == 0) {
+        expires_in = ptr;
+      }
+    }
+    if (access_token == NULL || access_token->type != GRPC_JSON_STRING) {
+      gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON.");
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    if (token_type == NULL || token_type->type != GRPC_JSON_STRING) {
+      gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON.");
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    if (expires_in == NULL || expires_in->type != GRPC_JSON_NUMBER) {
+      gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON.");
+      status = GRPC_CREDENTIALS_ERROR;
+      goto end;
+    }
+    gpr_asprintf(&new_access_token, "%s %s", token_type->value,
+                 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(
+        *token_md, GRPC_AUTHORIZATION_METADATA_KEY, new_access_token);
+    status = GRPC_CREDENTIALS_OK;
+  }
+
+end:
+  if (status != GRPC_CREDENTIALS_OK && (*token_md != NULL)) {
+    grpc_credentials_md_store_unref(*token_md);
+    *token_md = NULL;
+  }
+  if (null_terminated_body != NULL) gpr_free(null_terminated_body);
+  if (new_access_token != NULL) gpr_free(new_access_token);
+  if (json != NULL) grpc_json_destroy(json);
+  return status;
+}
+
+static void on_oauth2_token_fetcher_http_response(
+    grpc_exec_ctx *exec_ctx, void *user_data,
+    const grpc_http_response *response) {
+  grpc_credentials_metadata_request *r =
+      (grpc_credentials_metadata_request *)user_data;
+  grpc_oauth2_token_fetcher_credentials *c =
+      (grpc_oauth2_token_fetcher_credentials *)r->creds;
+  gpr_timespec token_lifetime;
+  grpc_credentials_status status;
+
+  gpr_mu_lock(&c->mu);
+  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(GPR_CLOCK_REALTIME), token_lifetime);
+    r->cb(exec_ctx, r->user_data, c->access_token_md->entries,
+          c->access_token_md->num_entries, status);
+  } else {
+    c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
+    r->cb(exec_ctx, r->user_data, NULL, 0, status);
+  }
+  gpr_mu_unlock(&c->mu);
+  grpc_credentials_metadata_request_destroy(r);
+}
+
+static void oauth2_token_fetcher_get_request_metadata(
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
+    grpc_pollset *pollset, grpc_auth_metadata_context context,
+    grpc_credentials_metadata_cb cb, void *user_data) {
+  grpc_oauth2_token_fetcher_credentials *c =
+      (grpc_oauth2_token_fetcher_credentials *)creds;
+  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(GPR_CLOCK_REALTIME)),
+             refresh_threshold) > 0)) {
+      cached_access_token_md =
+          grpc_credentials_md_store_ref(c->access_token_md);
+    }
+    gpr_mu_unlock(&c->mu);
+  }
+  if (cached_access_token_md != NULL) {
+    cb(exec_ctx, user_data, cached_access_token_md->entries,
+       cached_access_token_md->num_entries, GRPC_CREDENTIALS_OK);
+    grpc_credentials_md_store_unref(cached_access_token_md);
+  } else {
+    c->fetch_func(
+        exec_ctx,
+        grpc_credentials_metadata_request_create(creds, cb, user_data),
+        &c->httpcli_context, pollset, on_oauth2_token_fetcher_http_response,
+        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold));
+  }
+}
+
+static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c,
+                                      grpc_fetch_oauth2_func fetch_func) {
+  memset(c, 0, sizeof(grpc_oauth2_token_fetcher_credentials));
+  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
+  gpr_ref_init(&c->base.refcount, 1);
+  gpr_mu_init(&c->mu);
+  c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
+  c->fetch_func = fetch_func;
+  grpc_httpcli_context_init(&c->httpcli_context);
+}
+
+/* -- GoogleComputeEngine credentials. -- */
+
+static grpc_call_credentials_vtable compute_engine_vtable = {
+    oauth2_token_fetcher_destruct, oauth2_token_fetcher_get_request_metadata};
+
+static void compute_engine_fetch_oauth2(
+    grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req,
+    grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
+    grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
+  grpc_http_header header = {"Metadata-Flavor", "Google"};
+  grpc_httpcli_request request;
+  memset(&request, 0, sizeof(grpc_httpcli_request));
+  request.host = GRPC_COMPUTE_ENGINE_METADATA_HOST;
+  request.http.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
+  request.http.hdr_count = 1;
+  request.http.hdrs = &header;
+  grpc_httpcli_get(exec_ctx, httpcli_context, pollset, &request, deadline,
+                   response_cb, metadata_req);
+}
+
+grpc_call_credentials *grpc_google_compute_engine_credentials_create(
+    void *reserved) {
+  grpc_oauth2_token_fetcher_credentials *c =
+      gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials));
+  GRPC_API_TRACE("grpc_compute_engine_credentials_create(reserved=%p)", 1,
+                 (reserved));
+  GPR_ASSERT(reserved == NULL);
+  init_oauth2_token_fetcher(c, compute_engine_fetch_oauth2);
+  c->base.vtable = &compute_engine_vtable;
+  return &c->base;
+}
+
+/* -- GoogleRefreshToken credentials. -- */
+
+static void refresh_token_destruct(grpc_call_credentials *creds) {
+  grpc_google_refresh_token_credentials *c =
+      (grpc_google_refresh_token_credentials *)creds;
+  grpc_auth_refresh_token_destruct(&c->refresh_token);
+  oauth2_token_fetcher_destruct(&c->base.base);
+}
+
+static grpc_call_credentials_vtable refresh_token_vtable = {
+    refresh_token_destruct, oauth2_token_fetcher_get_request_metadata};
+
+static void refresh_token_fetch_oauth2(
+    grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req,
+    grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
+    grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
+  grpc_google_refresh_token_credentials *c =
+      (grpc_google_refresh_token_credentials *)metadata_req->creds;
+  grpc_http_header header = {"Content-Type",
+                             "application/x-www-form-urlencoded"};
+  grpc_httpcli_request request;
+  char *body = NULL;
+  gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING,
+               c->refresh_token.client_id, c->refresh_token.client_secret,
+               c->refresh_token.refresh_token);
+  memset(&request, 0, sizeof(grpc_httpcli_request));
+  request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST;
+  request.http.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH;
+  request.http.hdr_count = 1;
+  request.http.hdrs = &header;
+  request.handshaker = &grpc_httpcli_ssl;
+  grpc_httpcli_post(exec_ctx, httpcli_context, pollset, &request, body,
+                    strlen(body), deadline, response_cb, metadata_req);
+  gpr_free(body);
+}
+
+grpc_call_credentials *
+grpc_refresh_token_credentials_create_from_auth_refresh_token(
+    grpc_auth_refresh_token refresh_token) {
+  grpc_google_refresh_token_credentials *c;
+  if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
+    gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation");
+    return NULL;
+  }
+  c = gpr_malloc(sizeof(grpc_google_refresh_token_credentials));
+  memset(c, 0, sizeof(grpc_google_refresh_token_credentials));
+  init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2);
+  c->base.base.vtable = &refresh_token_vtable;
+  c->refresh_token = refresh_token;
+  return &c->base.base;
+}
+
+grpc_call_credentials *grpc_google_refresh_token_credentials_create(
+    const char *json_refresh_token, void *reserved) {
+  GRPC_API_TRACE(
+      "grpc_refresh_token_credentials_create(json_refresh_token=%s, "
+      "reserved=%p)",
+      2, (json_refresh_token, reserved));
+  GPR_ASSERT(reserved == NULL);
+  return grpc_refresh_token_credentials_create_from_auth_refresh_token(
+      grpc_auth_refresh_token_create_from_string(json_refresh_token));
+}
+
+/* -- Metadata-only credentials. -- */
+
+static void md_only_test_destruct(grpc_call_credentials *creds) {
+  grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
+  grpc_credentials_md_store_unref(c->md_store);
+}
+
+static void on_simulated_token_fetch_done(grpc_exec_ctx *exec_ctx,
+                                          void *user_data, bool success) {
+  grpc_credentials_metadata_request *r =
+      (grpc_credentials_metadata_request *)user_data;
+  grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds;
+  r->cb(exec_ctx, r->user_data, c->md_store->entries, c->md_store->num_entries,
+        GRPC_CREDENTIALS_OK);
+  grpc_credentials_metadata_request_destroy(r);
+}
+
+static void md_only_test_get_request_metadata(
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
+    grpc_pollset *pollset, grpc_auth_metadata_context context,
+    grpc_credentials_metadata_cb cb, void *user_data) {
+  grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
+
+  if (c->is_async) {
+    grpc_credentials_metadata_request *cb_arg =
+        grpc_credentials_metadata_request_create(creds, cb, user_data);
+    grpc_executor_enqueue(
+        grpc_closure_create(on_simulated_token_fetch_done, cb_arg), true);
+  } else {
+    cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK);
+  }
+}
+
+static grpc_call_credentials_vtable md_only_test_vtable = {
+    md_only_test_destruct, md_only_test_get_request_metadata};
+
+grpc_call_credentials *grpc_md_only_test_credentials_create(
+    const char *md_key, const char *md_value, int is_async) {
+  grpc_md_only_test_credentials *c =
+      gpr_malloc(sizeof(grpc_md_only_test_credentials));
+  memset(c, 0, sizeof(grpc_md_only_test_credentials));
+  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
+  c->base.vtable = &md_only_test_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  c->md_store = grpc_credentials_md_store_create(1);
+  grpc_credentials_md_store_add_cstrings(c->md_store, md_key, md_value);
+  c->is_async = is_async;
+  return &c->base;
+}
+
+/* -- Oauth2 Access Token credentials. -- */
+
+static void access_token_destruct(grpc_call_credentials *creds) {
+  grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
+  grpc_credentials_md_store_unref(c->access_token_md);
+}
+
+static void access_token_get_request_metadata(
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
+    grpc_pollset *pollset, grpc_auth_metadata_context context,
+    grpc_credentials_metadata_cb cb, void *user_data) {
+  grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
+  cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK);
+}
+
+static grpc_call_credentials_vtable access_token_vtable = {
+    access_token_destruct, access_token_get_request_metadata};
+
+grpc_call_credentials *grpc_access_token_credentials_create(
+    const char *access_token, void *reserved) {
+  grpc_access_token_credentials *c =
+      gpr_malloc(sizeof(grpc_access_token_credentials));
+  char *token_md_value;
+  GRPC_API_TRACE(
+      "grpc_access_token_credentials_create(access_token=%s, "
+      "reserved=%p)",
+      2, (access_token, reserved));
+  GPR_ASSERT(reserved == NULL);
+  memset(c, 0, sizeof(grpc_access_token_credentials));
+  c->base.type = GRPC_CALL_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 grpc_security_status fake_transport_security_create_security_connector(
+    grpc_channel_credentials *c, grpc_call_credentials *call_creds,
+    const char *target, const grpc_channel_args *args,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+  *sc = grpc_fake_channel_security_connector_create(call_creds);
+  return GRPC_SECURITY_OK;
+}
+
+static grpc_security_status
+fake_transport_security_server_create_security_connector(
+    grpc_server_credentials *c, grpc_server_security_connector **sc) {
+  *sc = grpc_fake_server_security_connector_create();
+  return GRPC_SECURITY_OK;
+}
+
+static grpc_channel_credentials_vtable
+    fake_transport_security_credentials_vtable = {
+        NULL, fake_transport_security_create_security_connector};
+
+static grpc_server_credentials_vtable
+    fake_transport_security_server_credentials_vtable = {
+        NULL, fake_transport_security_server_create_security_connector};
+
+grpc_channel_credentials *grpc_fake_transport_security_credentials_create(
+    void) {
+  grpc_channel_credentials *c = gpr_malloc(sizeof(grpc_channel_credentials));
+  memset(c, 0, sizeof(grpc_channel_credentials));
+  c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
+  c->vtable = &fake_transport_security_credentials_vtable;
+  gpr_ref_init(&c->refcount, 1);
+  return c;
+}
+
+grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
+    void) {
+  grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials));
+  memset(c, 0, sizeof(grpc_server_credentials));
+  c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
+  gpr_ref_init(&c->refcount, 1);
+  c->vtable = &fake_transport_security_server_credentials_vtable;
+  return c;
+}
+
+/* -- Composite call credentials. -- */
+
+typedef struct {
+  grpc_composite_call_credentials *composite_creds;
+  size_t creds_index;
+  grpc_credentials_md_store *md_elems;
+  grpc_auth_metadata_context auth_md_context;
+  void *user_data;
+  grpc_pollset *pollset;
+  grpc_credentials_metadata_cb cb;
+} grpc_composite_call_credentials_metadata_context;
+
+static void composite_call_destruct(grpc_call_credentials *creds) {
+  grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
+  size_t i;
+  for (i = 0; i < c->inner.num_creds; i++) {
+    grpc_call_credentials_unref(c->inner.creds_array[i]);
+  }
+  gpr_free(c->inner.creds_array);
+}
+
+static void composite_call_md_context_destroy(
+    grpc_composite_call_credentials_metadata_context *ctx) {
+  grpc_credentials_md_store_unref(ctx->md_elems);
+  gpr_free(ctx);
+}
+
+static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
+                                       grpc_credentials_md *md_elems,
+                                       size_t num_md,
+                                       grpc_credentials_status status) {
+  grpc_composite_call_credentials_metadata_context *ctx =
+      (grpc_composite_call_credentials_metadata_context *)user_data;
+  if (status != GRPC_CREDENTIALS_OK) {
+    ctx->cb(exec_ctx, ctx->user_data, NULL, 0, status);
+    return;
+  }
+
+  /* Copy the metadata in the context. */
+  if (num_md > 0) {
+    size_t i;
+    for (i = 0; i < num_md; i++) {
+      grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key,
+                                    md_elems[i].value);
+    }
+  }
+
+  /* See if we need to get some more metadata. */
+  if (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
+    grpc_call_credentials *inner_creds =
+        ctx->composite_creds->inner.creds_array[ctx->creds_index++];
+    grpc_call_credentials_get_request_metadata(
+        exec_ctx, inner_creds, ctx->pollset, ctx->auth_md_context,
+        composite_call_metadata_cb, ctx);
+    return;
+  }
+
+  /* We're done!. */
+  ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries,
+          ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK);
+  composite_call_md_context_destroy(ctx);
+}
+
+static void composite_call_get_request_metadata(
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
+    grpc_pollset *pollset, grpc_auth_metadata_context auth_md_context,
+    grpc_credentials_metadata_cb cb, void *user_data) {
+  grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
+  grpc_composite_call_credentials_metadata_context *ctx;
+
+  ctx = gpr_malloc(sizeof(grpc_composite_call_credentials_metadata_context));
+  memset(ctx, 0, sizeof(grpc_composite_call_credentials_metadata_context));
+  ctx->auth_md_context = auth_md_context;
+  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);
+  grpc_call_credentials_get_request_metadata(
+      exec_ctx, c->inner.creds_array[ctx->creds_index++], pollset,
+      auth_md_context, composite_call_metadata_cb, ctx);
+}
+
+static grpc_call_credentials_vtable composite_call_credentials_vtable = {
+    composite_call_destruct, composite_call_get_request_metadata};
+
+static grpc_call_credentials_array get_creds_array(
+    grpc_call_credentials **creds_addr) {
+  grpc_call_credentials_array result;
+  grpc_call_credentials *creds = *creds_addr;
+  result.creds_array = creds_addr;
+  result.num_creds = 1;
+  if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
+    result = *grpc_composite_call_credentials_get_credentials(creds);
+  }
+  return result;
+}
+
+grpc_call_credentials *grpc_composite_call_credentials_create(
+    grpc_call_credentials *creds1, grpc_call_credentials *creds2,
+    void *reserved) {
+  size_t i;
+  size_t creds_array_byte_size;
+  grpc_call_credentials_array creds1_array;
+  grpc_call_credentials_array creds2_array;
+  grpc_composite_call_credentials *c;
+  GRPC_API_TRACE(
+      "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, "
+      "reserved=%p)",
+      3, (creds1, creds2, reserved));
+  GPR_ASSERT(reserved == NULL);
+  GPR_ASSERT(creds1 != NULL);
+  GPR_ASSERT(creds2 != NULL);
+  c = gpr_malloc(sizeof(grpc_composite_call_credentials));
+  memset(c, 0, sizeof(grpc_composite_call_credentials));
+  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE;
+  c->base.vtable = &composite_call_credentials_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  creds1_array = get_creds_array(&creds1);
+  creds2_array = get_creds_array(&creds2);
+  c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
+  creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials *);
+  c->inner.creds_array = gpr_malloc(creds_array_byte_size);
+  memset(c->inner.creds_array, 0, creds_array_byte_size);
+  for (i = 0; i < creds1_array.num_creds; i++) {
+    grpc_call_credentials *cur_creds = creds1_array.creds_array[i];
+    c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds);
+  }
+  for (i = 0; i < creds2_array.num_creds; i++) {
+    grpc_call_credentials *cur_creds = creds2_array.creds_array[i];
+    c->inner.creds_array[i + creds1_array.num_creds] =
+        grpc_call_credentials_ref(cur_creds);
+  }
+  return &c->base;
+}
+
+const grpc_call_credentials_array *
+grpc_composite_call_credentials_get_credentials(grpc_call_credentials *creds) {
+  const grpc_composite_call_credentials *c =
+      (const grpc_composite_call_credentials *)creds;
+  GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
+  return &c->inner;
+}
+
+grpc_call_credentials *grpc_credentials_contains_type(
+    grpc_call_credentials *creds, const char *type,
+    grpc_call_credentials **composite_creds) {
+  size_t i;
+  if (strcmp(creds->type, type) == 0) {
+    if (composite_creds != NULL) *composite_creds = NULL;
+    return creds;
+  } else if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
+    const grpc_call_credentials_array *inner_creds_array =
+        grpc_composite_call_credentials_get_credentials(creds);
+    for (i = 0; i < inner_creds_array->num_creds; i++) {
+      if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) {
+        if (composite_creds != NULL) *composite_creds = creds;
+        return inner_creds_array->creds_array[i];
+      }
+    }
+  }
+  return NULL;
+}
+
+/* -- IAM credentials. -- */
+
+static void iam_destruct(grpc_call_credentials *creds) {
+  grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
+  grpc_credentials_md_store_unref(c->iam_md);
+}
+
+static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx,
+                                     grpc_call_credentials *creds,
+                                     grpc_pollset *pollset,
+                                     grpc_auth_metadata_context context,
+                                     grpc_credentials_metadata_cb cb,
+                                     void *user_data) {
+  grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
+  cb(exec_ctx, user_data, c->iam_md->entries, c->iam_md->num_entries,
+     GRPC_CREDENTIALS_OK);
+}
+
+static grpc_call_credentials_vtable iam_vtable = {iam_destruct,
+                                                  iam_get_request_metadata};
+
+grpc_call_credentials *grpc_google_iam_credentials_create(
+    const char *token, const char *authority_selector, void *reserved) {
+  grpc_google_iam_credentials *c;
+  GRPC_API_TRACE(
+      "grpc_iam_credentials_create(token=%s, authority_selector=%s, "
+      "reserved=%p)",
+      3, (token, authority_selector, reserved));
+  GPR_ASSERT(reserved == NULL);
+  GPR_ASSERT(token != NULL);
+  GPR_ASSERT(authority_selector != NULL);
+  c = gpr_malloc(sizeof(grpc_google_iam_credentials));
+  memset(c, 0, sizeof(grpc_google_iam_credentials));
+  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_IAM;
+  c->base.vtable = &iam_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  c->iam_md = grpc_credentials_md_store_create(2);
+  grpc_credentials_md_store_add_cstrings(
+      c->iam_md, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token);
+  grpc_credentials_md_store_add_cstrings(
+      c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector);
+  return &c->base;
+}
+
+/* -- Plugin credentials. -- */
+
+typedef struct {
+  void *user_data;
+  grpc_credentials_metadata_cb cb;
+} grpc_metadata_plugin_request;
+
+static void plugin_destruct(grpc_call_credentials *creds) {
+  grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
+  if (c->plugin.state != NULL && c->plugin.destroy != NULL) {
+    c->plugin.destroy(c->plugin.state);
+  }
+}
+
+static void plugin_md_request_metadata_ready(void *request,
+                                             const grpc_metadata *md,
+                                             size_t num_md,
+                                             grpc_status_code status,
+                                             const char *error_details) {
+  /* called from application code */
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_metadata_plugin_request *r = (grpc_metadata_plugin_request *)request;
+  if (status != GRPC_STATUS_OK) {
+    if (error_details != NULL) {
+      gpr_log(GPR_ERROR, "Getting metadata from plugin failed with error: %s",
+              error_details);
+    }
+    r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR);
+  } else {
+    size_t i;
+    grpc_credentials_md *md_array = NULL;
+    if (num_md > 0) {
+      md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md));
+      for (i = 0; i < num_md; i++) {
+        md_array[i].key = gpr_slice_from_copied_string(md[i].key);
+        md_array[i].value =
+            gpr_slice_from_copied_buffer(md[i].value, md[i].value_length);
+      }
+    }
+    r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK);
+    if (md_array != NULL) {
+      for (i = 0; i < num_md; i++) {
+        gpr_slice_unref(md_array[i].key);
+        gpr_slice_unref(md_array[i].value);
+      }
+      gpr_free(md_array);
+    }
+  }
+  gpr_free(r);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx,
+                                        grpc_call_credentials *creds,
+                                        grpc_pollset *pollset,
+                                        grpc_auth_metadata_context context,
+                                        grpc_credentials_metadata_cb cb,
+                                        void *user_data) {
+  grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
+  if (c->plugin.get_metadata != NULL) {
+    grpc_metadata_plugin_request *request = gpr_malloc(sizeof(*request));
+    memset(request, 0, sizeof(*request));
+    request->user_data = user_data;
+    request->cb = cb;
+    c->plugin.get_metadata(c->plugin.state, context,
+                           plugin_md_request_metadata_ready, request);
+  } else {
+    cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
+  }
+}
+
+static grpc_call_credentials_vtable plugin_vtable = {
+    plugin_destruct, plugin_get_request_metadata};
+
+grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
+    grpc_metadata_credentials_plugin plugin, void *reserved) {
+  grpc_plugin_credentials *c = gpr_malloc(sizeof(*c));
+  GRPC_API_TRACE("grpc_metadata_credentials_create_from_plugin(reserved=%p)", 1,
+                 (reserved));
+  GPR_ASSERT(reserved == NULL);
+  memset(c, 0, sizeof(*c));
+  c->base.type = plugin.type;
+  c->base.vtable = &plugin_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  c->plugin = plugin;
+  return &c->base;
+}
+
+/* -- Composite channel credentials. -- */
+
+static void composite_channel_destruct(grpc_channel_credentials *creds) {
+  grpc_composite_channel_credentials *c =
+      (grpc_composite_channel_credentials *)creds;
+  grpc_channel_credentials_unref(c->inner_creds);
+  grpc_call_credentials_unref(c->call_creds);
+}
+
+static grpc_security_status composite_channel_create_security_connector(
+    grpc_channel_credentials *creds, grpc_call_credentials *call_creds,
+    const char *target, const grpc_channel_args *args,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+  grpc_composite_channel_credentials *c =
+      (grpc_composite_channel_credentials *)creds;
+  grpc_security_status status = GRPC_SECURITY_ERROR;
+
+  GPR_ASSERT(c->inner_creds != NULL && c->call_creds != NULL &&
+             c->inner_creds->vtable != NULL &&
+             c->inner_creds->vtable->create_security_connector != NULL);
+  /* If we are passed a call_creds, create a call composite to pass it
+     downstream. */
+  if (call_creds != NULL) {
+    grpc_call_credentials *composite_call_creds =
+        grpc_composite_call_credentials_create(c->call_creds, call_creds, NULL);
+    status = c->inner_creds->vtable->create_security_connector(
+        c->inner_creds, composite_call_creds, target, args, sc, new_args);
+    grpc_call_credentials_unref(composite_call_creds);
+  } else {
+    status = c->inner_creds->vtable->create_security_connector(
+        c->inner_creds, c->call_creds, target, args, sc, new_args);
+  }
+  return status;
+}
+
+static grpc_channel_credentials_vtable composite_channel_credentials_vtable = {
+    composite_channel_destruct, composite_channel_create_security_connector};
+
+grpc_channel_credentials *grpc_composite_channel_credentials_create(
+    grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds,
+    void *reserved) {
+  grpc_composite_channel_credentials *c = gpr_malloc(sizeof(*c));
+  memset(c, 0, sizeof(*c));
+  GPR_ASSERT(channel_creds != NULL && call_creds != NULL && reserved == NULL);
+  GRPC_API_TRACE(
+      "grpc_composite_channel_credentials_create(channel_creds=%p, "
+      "call_creds=%p, reserved=%p)",
+      3, (channel_creds, call_creds, reserved));
+  c->base.type = channel_creds->type;
+  c->base.vtable = &composite_channel_credentials_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  c->inner_creds = grpc_channel_credentials_ref(channel_creds);
+  c->call_creds = grpc_call_credentials_ref(call_creds);
+  return &c->base;
+}
diff --git a/src/core/lib/security/credentials.h b/src/core/lib/security/credentials.h
new file mode 100644
index 0000000..7168b98
--- /dev/null
+++ b/src/core/lib/security/credentials.h
@@ -0,0 +1,377 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_H
+#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_H
+
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc/support/sync.h>
+#include "src/core/lib/transport/metadata_batch.h"
+
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/http/parser.h"
+#include "src/core/lib/security/json_token.h"
+#include "src/core/lib/security/security_connector.h"
+
+struct grpc_http_response;
+
+/* --- Constants. --- */
+
+typedef enum {
+  GRPC_CREDENTIALS_OK = 0,
+  GRPC_CREDENTIALS_ERROR
+} grpc_credentials_status;
+
+#define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake"
+
+#define GRPC_CHANNEL_CREDENTIALS_TYPE_SSL "Ssl"
+#define GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY \
+  "FakeTransportSecurity"
+
+#define GRPC_CALL_CREDENTIALS_TYPE_OAUTH2 "Oauth2"
+#define GRPC_CALL_CREDENTIALS_TYPE_JWT "Jwt"
+#define GRPC_CALL_CREDENTIALS_TYPE_IAM "Iam"
+#define GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE "Composite"
+
+#define GRPC_AUTHORIZATION_METADATA_KEY "authorization"
+#define GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY \
+  "x-goog-iam-authorization-token"
+#define GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY "x-goog-iam-authority-selector"
+
+#define GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY "gcloud"
+#define GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE \
+  "application_default_credentials.json"
+
+#define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60
+
+#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata"
+#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
+  "/computeMetadata/v1/instance/service-accounts/default/token"
+
+#define GRPC_GOOGLE_OAUTH2_SERVICE_HOST "www.googleapis.com"
+#define GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH "/oauth2/v3/token"
+
+#define GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX                         \
+  "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" \
+  "assertion="
+
+#define GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING \
+  "client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token"
+
+/* --- Google utils --- */
+
+/* It is the caller's responsibility to gpr_free the result if not NULL. */
+char *grpc_get_well_known_google_credentials_file_path(void);
+
+/* Implementation function for the different platforms. */
+char *grpc_get_well_known_google_credentials_file_path_impl(void);
+
+/* Override for testing only. Not thread-safe */
+typedef char *(*grpc_well_known_credentials_path_getter)(void);
+void grpc_override_well_known_credentials_path_getter(
+    grpc_well_known_credentials_path_getter getter);
+
+/* --- grpc_channel_credentials. --- */
+
+typedef struct {
+  void (*destruct)(grpc_channel_credentials *c);
+
+  grpc_security_status (*create_security_connector)(
+      grpc_channel_credentials *c, grpc_call_credentials *call_creds,
+      const char *target, const grpc_channel_args *args,
+      grpc_channel_security_connector **sc, grpc_channel_args **new_args);
+} grpc_channel_credentials_vtable;
+
+struct grpc_channel_credentials {
+  const grpc_channel_credentials_vtable *vtable;
+  const char *type;
+  gpr_refcount refcount;
+};
+
+grpc_channel_credentials *grpc_channel_credentials_ref(
+    grpc_channel_credentials *creds);
+void grpc_channel_credentials_unref(grpc_channel_credentials *creds);
+
+/* Creates a security connector for the channel. May also create new channel
+   args for the channel to be used in place of the passed in const args if
+   returned non NULL. In that case the caller is responsible for destroying
+   new_args after channel creation. */
+grpc_security_status grpc_channel_credentials_create_security_connector(
+    grpc_channel_credentials *creds, const char *target,
+    const grpc_channel_args *args, grpc_channel_security_connector **sc,
+    grpc_channel_args **new_args);
+
+/* --- grpc_credentials_md. --- */
+
+typedef struct {
+  gpr_slice key;
+  gpr_slice value;
+} grpc_credentials_md;
+
+typedef struct {
+  grpc_credentials_md *entries;
+  size_t num_entries;
+  size_t allocated;
+  gpr_refcount refcount;
+} grpc_credentials_md_store;
+
+grpc_credentials_md_store *grpc_credentials_md_store_create(
+    size_t initial_capacity);
+
+/* Will ref key and value. */
+void grpc_credentials_md_store_add(grpc_credentials_md_store *store,
+                                   gpr_slice key, gpr_slice value);
+void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store,
+                                            const char *key, const char *value);
+grpc_credentials_md_store *grpc_credentials_md_store_ref(
+    grpc_credentials_md_store *store);
+void grpc_credentials_md_store_unref(grpc_credentials_md_store *store);
+
+/* --- grpc_call_credentials. --- */
+
+typedef void (*grpc_credentials_metadata_cb)(grpc_exec_ctx *exec_ctx,
+                                             void *user_data,
+                                             grpc_credentials_md *md_elems,
+                                             size_t num_md,
+                                             grpc_credentials_status status);
+
+typedef struct {
+  void (*destruct)(grpc_call_credentials *c);
+  void (*get_request_metadata)(grpc_exec_ctx *exec_ctx,
+                               grpc_call_credentials *c, grpc_pollset *pollset,
+                               grpc_auth_metadata_context context,
+                               grpc_credentials_metadata_cb cb,
+                               void *user_data);
+} grpc_call_credentials_vtable;
+
+struct grpc_call_credentials {
+  const grpc_call_credentials_vtable *vtable;
+  const char *type;
+  gpr_refcount refcount;
+};
+
+grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds);
+void grpc_call_credentials_unref(grpc_call_credentials *creds);
+void grpc_call_credentials_get_request_metadata(
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
+    grpc_pollset *pollset, grpc_auth_metadata_context context,
+    grpc_credentials_metadata_cb cb, void *user_data);
+
+typedef struct {
+  grpc_call_credentials **creds_array;
+  size_t num_creds;
+} grpc_call_credentials_array;
+
+const grpc_call_credentials_array *
+grpc_composite_call_credentials_get_credentials(
+    grpc_call_credentials *composite_creds);
+
+/* Returns creds if creds is of the specified type or the inner creds of the
+   specified type (if found), if the creds is of type COMPOSITE.
+   If composite_creds is not NULL, *composite_creds will point to creds if of
+   type COMPOSITE in case of success. */
+grpc_call_credentials *grpc_credentials_contains_type(
+    grpc_call_credentials *creds, const char *type,
+    grpc_call_credentials **composite_creds);
+
+/* Exposed for testing only. */
+grpc_credentials_status
+grpc_oauth2_token_fetcher_credentials_parse_server_response(
+    const struct grpc_http_response *response,
+    grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime);
+
+void grpc_flush_cached_google_default_credentials(void);
+
+/* Metadata-only credentials with the specified key and value where
+   asynchronicity can be simulated for testing. */
+grpc_call_credentials *grpc_md_only_test_credentials_create(
+    const char *md_key, const char *md_value, int is_async);
+
+/* Private constructor for jwt credentials from an already parsed json key.
+   Takes ownership of the key. */
+grpc_call_credentials *
+grpc_service_account_jwt_access_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_call_credentials *
+grpc_refresh_token_credentials_create_from_auth_refresh_token(
+    grpc_auth_refresh_token token);
+
+/* --- grpc_server_credentials. --- */
+
+typedef struct {
+  void (*destruct)(grpc_server_credentials *c);
+  grpc_security_status (*create_security_connector)(
+      grpc_server_credentials *c, grpc_server_security_connector **sc);
+} grpc_server_credentials_vtable;
+
+struct grpc_server_credentials {
+  const grpc_server_credentials_vtable *vtable;
+  const char *type;
+  gpr_refcount refcount;
+  grpc_auth_metadata_processor processor;
+};
+
+grpc_security_status grpc_server_credentials_create_security_connector(
+    grpc_server_credentials *creds, grpc_server_security_connector **sc);
+
+grpc_server_credentials *grpc_server_credentials_ref(
+    grpc_server_credentials *creds);
+
+void grpc_server_credentials_unref(grpc_server_credentials *creds);
+
+#define GRPC_SERVER_CREDENTIALS_ARG "grpc.server_credentials"
+
+grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *c);
+grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg);
+grpc_server_credentials *grpc_find_server_credentials_in_args(
+    const grpc_channel_args *args);
+
+/* -- Fake transport security credentials. -- */
+
+/* Creates a fake transport security credentials object for testing. */
+grpc_channel_credentials *grpc_fake_transport_security_credentials_create(void);
+/* Creates a fake server transport security credentials object for testing. */
+grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
+    void);
+
+/* -- Ssl credentials. -- */
+
+typedef struct {
+  grpc_channel_credentials base;
+  grpc_ssl_config config;
+} grpc_ssl_credentials;
+
+typedef struct {
+  grpc_server_credentials base;
+  grpc_ssl_server_config config;
+} grpc_ssl_server_credentials;
+
+/* -- Channel composite credentials. -- */
+
+typedef struct {
+  grpc_channel_credentials base;
+  grpc_channel_credentials *inner_creds;
+  grpc_call_credentials *call_creds;
+} grpc_composite_channel_credentials;
+
+/* -- Jwt credentials -- */
+
+typedef struct {
+  grpc_call_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_service_account_jwt_access_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_exec_ctx *exec_ctx,
+                                       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_call_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;
+
+/* -- GoogleRefreshToken credentials. -- */
+
+typedef struct {
+  grpc_oauth2_token_fetcher_credentials base;
+  grpc_auth_refresh_token refresh_token;
+} grpc_google_refresh_token_credentials;
+
+/* -- Oauth2 Access Token credentials. -- */
+
+typedef struct {
+  grpc_call_credentials base;
+  grpc_credentials_md_store *access_token_md;
+} grpc_access_token_credentials;
+
+/* --  Metadata-only Test credentials. -- */
+
+typedef struct {
+  grpc_call_credentials base;
+  grpc_credentials_md_store *md_store;
+  int is_async;
+} grpc_md_only_test_credentials;
+
+/* -- GoogleIAM credentials. -- */
+
+typedef struct {
+  grpc_call_credentials base;
+  grpc_credentials_md_store *iam_md;
+} grpc_google_iam_credentials;
+
+/* -- Composite credentials. -- */
+
+typedef struct {
+  grpc_call_credentials base;
+  grpc_call_credentials_array inner;
+} grpc_composite_call_credentials;
+
+/* -- Plugin credentials. -- */
+
+typedef struct {
+  grpc_call_credentials base;
+  grpc_metadata_credentials_plugin plugin;
+  grpc_credentials_md_store *plugin_md;
+} grpc_plugin_credentials;
+
+#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_H */
diff --git a/src/core/lib/security/credentials_metadata.c b/src/core/lib/security/credentials_metadata.c
new file mode 100644
index 0000000..c3bfcb1
--- /dev/null
+++ b/src/core/lib/security/credentials_metadata.c
@@ -0,0 +1,101 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/security/credentials.h"
+
+#include <grpc/support/alloc.h>
+
+#include <string.h>
+
+static void store_ensure_capacity(grpc_credentials_md_store *store) {
+  if (store->num_entries == store->allocated) {
+    store->allocated = (store->allocated == 0) ? 1 : store->allocated * 2;
+    store->entries = gpr_realloc(
+        store->entries, store->allocated * sizeof(grpc_credentials_md));
+  }
+}
+
+grpc_credentials_md_store *grpc_credentials_md_store_create(
+    size_t initial_capacity) {
+  grpc_credentials_md_store *store =
+      gpr_malloc(sizeof(grpc_credentials_md_store));
+  memset(store, 0, sizeof(grpc_credentials_md_store));
+  if (initial_capacity > 0) {
+    store->entries = gpr_malloc(initial_capacity * sizeof(grpc_credentials_md));
+    store->allocated = initial_capacity;
+  }
+  gpr_ref_init(&store->refcount, 1);
+  return store;
+}
+
+void grpc_credentials_md_store_add(grpc_credentials_md_store *store,
+                                   gpr_slice key, gpr_slice value) {
+  if (store == NULL) return;
+  store_ensure_capacity(store);
+  store->entries[store->num_entries].key = gpr_slice_ref(key);
+  store->entries[store->num_entries].value = gpr_slice_ref(value);
+  store->num_entries++;
+}
+
+void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store,
+                                            const char *key,
+                                            const char *value) {
+  if (store == NULL) return;
+  store_ensure_capacity(store);
+  store->entries[store->num_entries].key = gpr_slice_from_copied_string(key);
+  store->entries[store->num_entries].value =
+      gpr_slice_from_copied_string(value);
+  store->num_entries++;
+}
+
+grpc_credentials_md_store *grpc_credentials_md_store_ref(
+    grpc_credentials_md_store *store) {
+  if (store == NULL) return NULL;
+  gpr_ref(&store->refcount);
+  return store;
+}
+
+void grpc_credentials_md_store_unref(grpc_credentials_md_store *store) {
+  if (store == NULL) return;
+  if (gpr_unref(&store->refcount)) {
+    if (store->entries != NULL) {
+      size_t i;
+      for (i = 0; i < store->num_entries; i++) {
+        gpr_slice_unref(store->entries[i].key);
+        gpr_slice_unref(store->entries[i].value);
+      }
+      gpr_free(store->entries);
+    }
+    gpr_free(store);
+  }
+}
diff --git a/src/core/lib/security/credentials_posix.c b/src/core/lib/security/credentials_posix.c
new file mode 100644
index 0000000..b758cd0
--- /dev/null
+++ b/src/core/lib/security/credentials_posix.c
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_FILE
+
+#include "src/core/lib/security/credentials.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
+
+char *grpc_get_well_known_google_credentials_file_path_impl(void) {
+  char *result = NULL;
+  char *home = gpr_getenv("HOME");
+  if (home == NULL) {
+    gpr_log(GPR_ERROR, "Could not get HOME environment variable.");
+    return NULL;
+  }
+  gpr_asprintf(&result, "%s/.config/%s/%s", home,
+               GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY,
+               GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE);
+  gpr_free(home);
+  return result;
+}
+
+#endif /* GPR_POSIX_FILE */
diff --git a/src/core/lib/security/credentials_win32.c b/src/core/lib/security/credentials_win32.c
new file mode 100644
index 0000000..a225ab0
--- /dev/null
+++ b/src/core/lib/security/credentials_win32.c
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include "src/core/lib/security/credentials.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
+
+char *grpc_get_well_known_google_credentials_file_path_impl(void) {
+  char *result = NULL;
+  char *appdata_path = gpr_getenv("APPDATA");
+  if (appdata_path == NULL) {
+    gpr_log(GPR_ERROR, "Could not get APPDATA environment variable.");
+    return NULL;
+  }
+  gpr_asprintf(&result, "%s/%s/%s", appdata_path,
+               GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY,
+               GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE);
+  gpr_free(appdata_path);
+  return result;
+}
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/lib/security/google_default_credentials.c b/src/core/lib/security/google_default_credentials.c
new file mode 100644
index 0000000..5c34228
--- /dev/null
+++ b/src/core/lib/security/google_default_credentials.c
@@ -0,0 +1,266 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/security/credentials.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/http/parser.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/load_file.h"
+#include "src/core/lib/surface/api_trace.h"
+
+/* -- Constants. -- */
+
+#define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal"
+
+/* -- Default credentials. -- */
+
+static grpc_channel_credentials *default_credentials = NULL;
+static int compute_engine_detection_done = 0;
+static gpr_mu g_state_mu;
+static gpr_mu *g_polling_mu;
+static gpr_once g_once = GPR_ONCE_INIT;
+
+static void init_default_credentials(void) { gpr_mu_init(&g_state_mu); }
+
+typedef struct {
+  grpc_pollset *pollset;
+  int is_done;
+  int success;
+} compute_engine_detector;
+
+static void on_compute_engine_detection_http_response(
+    grpc_exec_ctx *exec_ctx, void *user_data,
+    const grpc_http_response *response) {
+  compute_engine_detector *detector = (compute_engine_detector *)user_data;
+  if (response != NULL && response->status == 200 && response->hdr_count > 0) {
+    /* Internet providers can return a generic response to all requests, so
+       it is necessary to check that metadata header is present also. */
+    size_t i;
+    for (i = 0; i < response->hdr_count; i++) {
+      grpc_http_header *header = &response->hdrs[i];
+      if (strcmp(header->key, "Metadata-Flavor") == 0 &&
+          strcmp(header->value, "Google") == 0) {
+        detector->success = 1;
+        break;
+      }
+    }
+  }
+  gpr_mu_lock(g_polling_mu);
+  detector->is_done = 1;
+  grpc_pollset_kick(detector->pollset, NULL);
+  gpr_mu_unlock(g_polling_mu);
+}
+
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool s) {
+  grpc_pollset_destroy(p);
+}
+
+static int is_stack_running_on_compute_engine(void) {
+  compute_engine_detector detector;
+  grpc_httpcli_request request;
+  grpc_httpcli_context context;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_closure destroy_closure;
+
+  /* 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 = gpr_time_from_seconds(1, GPR_TIMESPAN);
+
+  detector.pollset = gpr_malloc(grpc_pollset_size());
+  grpc_pollset_init(detector.pollset, &g_polling_mu);
+  detector.is_done = 0;
+  detector.success = 0;
+
+  memset(&request, 0, sizeof(grpc_httpcli_request));
+  request.host = GRPC_COMPUTE_ENGINE_DETECTION_HOST;
+  request.http.path = "/";
+
+  grpc_httpcli_context_init(&context);
+
+  grpc_httpcli_get(
+      &exec_ctx, &context, detector.pollset, &request,
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay),
+      on_compute_engine_detection_http_response, &detector);
+
+  grpc_exec_ctx_finish(&exec_ctx);
+
+  /* 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(g_polling_mu);
+  while (!detector.is_done) {
+    grpc_pollset_worker *worker = NULL;
+    grpc_pollset_work(&exec_ctx, detector.pollset, &worker,
+                      gpr_now(GPR_CLOCK_MONOTONIC),
+                      gpr_inf_future(GPR_CLOCK_MONOTONIC));
+  }
+  gpr_mu_unlock(g_polling_mu);
+
+  grpc_httpcli_context_destroy(&context);
+  grpc_closure_init(&destroy_closure, destroy_pollset, detector.pollset);
+  grpc_pollset_shutdown(&exec_ctx, detector.pollset, &destroy_closure);
+  grpc_exec_ctx_finish(&exec_ctx);
+  g_polling_mu = NULL;
+
+  gpr_free(detector.pollset);
+
+  return detector.success;
+}
+
+/* Takes ownership of creds_path if not NULL. */
+static grpc_call_credentials *create_default_creds_from_path(char *creds_path) {
+  grpc_json *json = NULL;
+  grpc_auth_json_key key;
+  grpc_auth_refresh_token token;
+  grpc_call_credentials *result = NULL;
+  gpr_slice creds_data = gpr_empty_slice();
+  int file_ok = 0;
+  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;
+
+  /* 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_service_account_jwt_access_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;
+}
+
+grpc_channel_credentials *grpc_google_default_credentials_create(void) {
+  grpc_channel_credentials *result = NULL;
+  grpc_call_credentials *call_creds = NULL;
+
+  GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ());
+
+  gpr_once_init(&g_once, init_default_credentials);
+
+  gpr_mu_lock(&g_state_mu);
+
+  if (default_credentials != NULL) {
+    result = grpc_channel_credentials_ref(default_credentials);
+    goto end;
+  }
+
+  /* First, try the environment variable. */
+  call_creds = create_default_creds_from_path(
+      gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR));
+  if (call_creds != NULL) goto end;
+
+  /* Then the well-known file. */
+  call_creds = create_default_creds_from_path(
+      grpc_get_well_known_google_credentials_file_path());
+  if (call_creds != NULL) goto end;
+
+  /* At last try to see if we're on compute engine (do the detection only once
+     since it requires a network test). */
+  if (!compute_engine_detection_done) {
+    int need_compute_engine_creds = is_stack_running_on_compute_engine();
+    compute_engine_detection_done = 1;
+    if (need_compute_engine_creds) {
+      call_creds = grpc_google_compute_engine_credentials_create(NULL);
+    }
+  }
+
+end:
+  if (result == NULL) {
+    if (call_creds != NULL) {
+      /* Blend with default ssl credentials and add a global reference so that
+         it
+         can be cached and re-served. */
+      grpc_channel_credentials *ssl_creds =
+          grpc_ssl_credentials_create(NULL, NULL, NULL);
+      default_credentials = grpc_channel_credentials_ref(
+          grpc_composite_channel_credentials_create(ssl_creds, call_creds,
+                                                    NULL));
+      GPR_ASSERT(default_credentials != NULL);
+      grpc_channel_credentials_unref(ssl_creds);
+      grpc_call_credentials_unref(call_creds);
+      result = default_credentials;
+    } else {
+      gpr_log(GPR_ERROR, "Could not create google default credentials.");
+    }
+  }
+  gpr_mu_unlock(&g_state_mu);
+  return result;
+}
+
+void grpc_flush_cached_google_default_credentials(void) {
+  gpr_once_init(&g_once, init_default_credentials);
+  gpr_mu_lock(&g_state_mu);
+  if (default_credentials != NULL) {
+    grpc_channel_credentials_unref(default_credentials);
+    default_credentials = NULL;
+  }
+  compute_engine_detection_done = 0;
+  gpr_mu_unlock(&g_state_mu);
+}
+
+/* -- Well known credentials path. -- */
+
+static grpc_well_known_credentials_path_getter creds_path_getter = NULL;
+
+char *grpc_get_well_known_google_credentials_file_path(void) {
+  if (creds_path_getter != NULL) return creds_path_getter();
+  return grpc_get_well_known_google_credentials_file_path_impl();
+}
+
+void grpc_override_well_known_credentials_path_getter(
+    grpc_well_known_credentials_path_getter getter) {
+  creds_path_getter = getter;
+}
diff --git a/src/core/lib/security/handshake.c b/src/core/lib/security/handshake.c
new file mode 100644
index 0000000..adb6d7f
--- /dev/null
+++ b/src/core/lib/security/handshake.c
@@ -0,0 +1,336 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/security/handshake.h"
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+#include "src/core/lib/security/secure_endpoint.h"
+#include "src/core/lib/security/security_context.h"
+
+#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256
+
+typedef struct {
+  grpc_security_connector *connector;
+  tsi_handshaker *handshaker;
+  bool is_client_side;
+  unsigned char *handshake_buffer;
+  size_t handshake_buffer_size;
+  grpc_endpoint *wrapped_endpoint;
+  grpc_endpoint *secure_endpoint;
+  gpr_slice_buffer left_overs;
+  gpr_slice_buffer incoming;
+  gpr_slice_buffer outgoing;
+  grpc_security_handshake_done_cb cb;
+  void *user_data;
+  grpc_closure on_handshake_data_sent_to_peer;
+  grpc_closure on_handshake_data_received_from_peer;
+  grpc_auth_context *auth_context;
+} grpc_security_handshake;
+
+static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
+                                                 void *setup, bool success);
+
+static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup,
+                                           bool success);
+
+static void security_connector_remove_handshake(grpc_security_handshake *h) {
+  GPR_ASSERT(!h->is_client_side);
+  grpc_security_connector_handshake_list *node;
+  grpc_security_connector_handshake_list *tmp;
+  grpc_server_security_connector *sc =
+      (grpc_server_security_connector *)h->connector;
+  gpr_mu_lock(&sc->mu);
+  node = sc->handshaking_handshakes;
+  if (node && node->handshake == h) {
+    sc->handshaking_handshakes = node->next;
+    gpr_free(node);
+    gpr_mu_unlock(&sc->mu);
+    return;
+  }
+  while (node) {
+    if (node->next->handshake == h) {
+      tmp = node->next;
+      node->next = node->next->next;
+      gpr_free(tmp);
+      gpr_mu_unlock(&sc->mu);
+      return;
+    }
+    node = node->next;
+  }
+  gpr_mu_unlock(&sc->mu);
+}
+
+static void security_handshake_done(grpc_exec_ctx *exec_ctx,
+                                    grpc_security_handshake *h,
+                                    int is_success) {
+  if (!h->is_client_side) {
+    security_connector_remove_handshake(h);
+  }
+  if (is_success) {
+    h->cb(exec_ctx, h->user_data, GRPC_SECURITY_OK, h->secure_endpoint,
+          h->auth_context);
+  } else {
+    if (h->secure_endpoint != NULL) {
+      grpc_endpoint_shutdown(exec_ctx, h->secure_endpoint);
+      grpc_endpoint_destroy(exec_ctx, h->secure_endpoint);
+    } else {
+      grpc_endpoint_destroy(exec_ctx, h->wrapped_endpoint);
+    }
+    h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, NULL, NULL);
+  }
+  if (h->handshaker != NULL) tsi_handshaker_destroy(h->handshaker);
+  if (h->handshake_buffer != NULL) gpr_free(h->handshake_buffer);
+  gpr_slice_buffer_destroy(&h->left_overs);
+  gpr_slice_buffer_destroy(&h->outgoing);
+  gpr_slice_buffer_destroy(&h->incoming);
+  GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake");
+  GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake");
+  gpr_free(h);
+}
+
+static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
+                            grpc_security_status status,
+                            grpc_auth_context *auth_context) {
+  grpc_security_handshake *h = user_data;
+  tsi_frame_protector *protector;
+  tsi_result result;
+  if (status != GRPC_SECURITY_OK) {
+    gpr_log(GPR_ERROR, "Error checking peer.");
+    security_handshake_done(exec_ctx, h, 0);
+    return;
+  }
+  h->auth_context = GRPC_AUTH_CONTEXT_REF(auth_context, "handshake");
+  result =
+      tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Frame protector creation failed with error %s.",
+            tsi_result_to_string(result));
+    security_handshake_done(exec_ctx, h, 0);
+    return;
+  }
+  h->secure_endpoint =
+      grpc_secure_endpoint_create(protector, h->wrapped_endpoint,
+                                  h->left_overs.slices, h->left_overs.count);
+  h->left_overs.count = 0;
+  h->left_overs.length = 0;
+  security_handshake_done(exec_ctx, h, 1);
+  return;
+}
+
+static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) {
+  tsi_peer peer;
+  tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer);
+
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Peer extraction failed with error %s",
+            tsi_result_to_string(result));
+    security_handshake_done(exec_ctx, h, 0);
+    return;
+  }
+  grpc_security_connector_check_peer(exec_ctx, h->connector, peer,
+                                     on_peer_checked, h);
+}
+
+static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
+                                         grpc_security_handshake *h) {
+  size_t offset = 0;
+  tsi_result result = TSI_OK;
+  gpr_slice to_send;
+
+  do {
+    size_t to_send_size = h->handshake_buffer_size - offset;
+    result = tsi_handshaker_get_bytes_to_send_to_peer(
+        h->handshaker, h->handshake_buffer + offset, &to_send_size);
+    offset += to_send_size;
+    if (result == TSI_INCOMPLETE_DATA) {
+      h->handshake_buffer_size *= 2;
+      h->handshake_buffer =
+          gpr_realloc(h->handshake_buffer, h->handshake_buffer_size);
+    }
+  } while (result == TSI_INCOMPLETE_DATA);
+
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshake failed with error %s",
+            tsi_result_to_string(result));
+    security_handshake_done(exec_ctx, h, 0);
+    return;
+  }
+
+  to_send =
+      gpr_slice_from_copied_buffer((const char *)h->handshake_buffer, offset);
+  gpr_slice_buffer_reset_and_unref(&h->outgoing);
+  gpr_slice_buffer_add(&h->outgoing, to_send);
+  /* TODO(klempner,jboeuf): This should probably use the client setup
+     deadline */
+  grpc_endpoint_write(exec_ctx, h->wrapped_endpoint, &h->outgoing,
+                      &h->on_handshake_data_sent_to_peer);
+}
+
+static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
+                                                 void *handshake,
+                                                 bool success) {
+  grpc_security_handshake *h = handshake;
+  size_t consumed_slice_size = 0;
+  tsi_result result = TSI_OK;
+  size_t i;
+  size_t num_left_overs;
+  int has_left_overs_in_current_slice = 0;
+
+  if (!success) {
+    gpr_log(GPR_ERROR, "Read failed.");
+    security_handshake_done(exec_ctx, h, 0);
+    return;
+  }
+
+  for (i = 0; i < h->incoming.count; i++) {
+    consumed_slice_size = GPR_SLICE_LENGTH(h->incoming.slices[i]);
+    result = tsi_handshaker_process_bytes_from_peer(
+        h->handshaker, GPR_SLICE_START_PTR(h->incoming.slices[i]),
+        &consumed_slice_size);
+    if (!tsi_handshaker_is_in_progress(h->handshaker)) break;
+  }
+
+  if (tsi_handshaker_is_in_progress(h->handshaker)) {
+    /* We may need more data. */
+    if (result == TSI_INCOMPLETE_DATA) {
+      grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming,
+                         &h->on_handshake_data_received_from_peer);
+      return;
+    } else {
+      send_handshake_bytes_to_peer(exec_ctx, h);
+      return;
+    }
+  }
+
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshake failed with error %s",
+            tsi_result_to_string(result));
+    security_handshake_done(exec_ctx, h, 0);
+    return;
+  }
+
+  /* Handshake is done and successful this point. */
+  has_left_overs_in_current_slice =
+      (consumed_slice_size < GPR_SLICE_LENGTH(h->incoming.slices[i]));
+  num_left_overs =
+      (has_left_overs_in_current_slice ? 1 : 0) + h->incoming.count - i - 1;
+  if (num_left_overs == 0) {
+    check_peer(exec_ctx, h);
+    return;
+  }
+
+  /* Put the leftovers in our buffer (ownership transfered). */
+  if (has_left_overs_in_current_slice) {
+    gpr_slice_buffer_add(
+        &h->left_overs,
+        gpr_slice_split_tail(&h->incoming.slices[i], consumed_slice_size));
+    gpr_slice_unref(
+        h->incoming.slices[i]); /* split_tail above increments refcount. */
+  }
+  gpr_slice_buffer_addn(
+      &h->left_overs, &h->incoming.slices[i + 1],
+      num_left_overs - (size_t)has_left_overs_in_current_slice);
+  check_peer(exec_ctx, h);
+}
+
+/* If handshake is NULL, the handshake is done. */
+static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx,
+                                           void *handshake, bool success) {
+  grpc_security_handshake *h = handshake;
+
+  /* Make sure that write is OK. */
+  if (!success) {
+    gpr_log(GPR_ERROR, "Write failed.");
+    if (handshake != NULL) security_handshake_done(exec_ctx, h, 0);
+    return;
+  }
+
+  /* We may be done. */
+  if (tsi_handshaker_is_in_progress(h->handshaker)) {
+    /* TODO(klempner,jboeuf): This should probably use the client setup
+       deadline */
+    grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming,
+                       &h->on_handshake_data_received_from_peer);
+  } else {
+    check_peer(exec_ctx, h);
+  }
+}
+
+void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
+                                tsi_handshaker *handshaker,
+                                grpc_security_connector *connector,
+                                bool is_client_side,
+                                grpc_endpoint *nonsecure_endpoint,
+                                grpc_security_handshake_done_cb cb,
+                                void *user_data) {
+  grpc_security_connector_handshake_list *handshake_node;
+  grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake));
+  memset(h, 0, sizeof(grpc_security_handshake));
+  h->handshaker = handshaker;
+  h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake");
+  h->is_client_side = is_client_side;
+  h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
+  h->handshake_buffer = gpr_malloc(h->handshake_buffer_size);
+  h->wrapped_endpoint = nonsecure_endpoint;
+  h->user_data = user_data;
+  h->cb = cb;
+  grpc_closure_init(&h->on_handshake_data_sent_to_peer,
+                    on_handshake_data_sent_to_peer, h);
+  grpc_closure_init(&h->on_handshake_data_received_from_peer,
+                    on_handshake_data_received_from_peer, h);
+  gpr_slice_buffer_init(&h->left_overs);
+  gpr_slice_buffer_init(&h->outgoing);
+  gpr_slice_buffer_init(&h->incoming);
+  if (!is_client_side) {
+    grpc_server_security_connector *server_connector =
+        (grpc_server_security_connector *)connector;
+    handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list));
+    handshake_node->handshake = h;
+    gpr_mu_lock(&server_connector->mu);
+    handshake_node->next = server_connector->handshaking_handshakes;
+    server_connector->handshaking_handshakes = handshake_node;
+    gpr_mu_unlock(&server_connector->mu);
+  }
+  send_handshake_bytes_to_peer(exec_ctx, h);
+}
+
+void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx,
+                                      void *handshake) {
+  grpc_security_handshake *h = handshake;
+  grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint);
+}
diff --git a/src/core/lib/security/handshake.h b/src/core/lib/security/handshake.h
new file mode 100644
index 0000000..b5d7bb3
--- /dev/null
+++ b/src/core/lib/security/handshake.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_HANDSHAKE_H
+#define GRPC_CORE_LIB_SECURITY_HANDSHAKE_H
+
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/security/security_connector.h"
+
+/* Calls the callback upon completion. Takes owership of handshaker. */
+void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
+                                tsi_handshaker *handshaker,
+                                grpc_security_connector *connector,
+                                bool is_client_side,
+                                grpc_endpoint *nonsecure_endpoint,
+                                grpc_security_handshake_done_cb cb,
+                                void *user_data);
+
+void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, void *handshake);
+
+#endif /* GRPC_CORE_LIB_SECURITY_HANDSHAKE_H */
diff --git a/src/core/lib/security/json_token.c b/src/core/lib/security/json_token.c
new file mode 100644
index 0000000..9705428
--- /dev/null
+++ b/src/core/lib/security/json_token.c
@@ -0,0 +1,411 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/security/json_token.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/security/b64.h"
+#include "src/core/lib/support/string.h"
+
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+
+/* --- Constants. --- */
+
+/* 1 hour max. */
+gpr_timespec grpc_max_auth_token_lifetime() {
+  gpr_timespec out;
+  out.tv_sec = 3600;
+  out.tv_nsec = 0;
+  out.clock_type = GPR_TIMESPAN;
+  return out;
+}
+
+#define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
+#define GRPC_JWT_TYPE "JWT"
+
+/* --- Override for testing. --- */
+
+static grpc_jwt_encode_and_sign_override g_jwt_encode_and_sign_override = NULL;
+
+/* --- grpc_auth_json_key. --- */
+
+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) {
+    if (strcmp(child->key, prop_name) == 0) break;
+  }
+  if (child == NULL || child->type != GRPC_JSON_STRING) {
+    gpr_log(GPR_ERROR, "Invalid or missing %s property.", prop_name);
+    return NULL;
+  }
+  return child->value;
+}
+
+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;
+  *json_key_field = gpr_strdup(prop_value);
+  return 1;
+}
+
+int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key) {
+  return (json_key != NULL) &&
+         strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID);
+}
+
+grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json) {
+  grpc_auth_json_key result;
+  BIO *bio = NULL;
+  const char *prop_value;
+  int success = 0;
+
+  memset(&result, 0, sizeof(grpc_auth_json_key));
+  result.type = GRPC_AUTH_JSON_TYPE_INVALID;
+  if (json == NULL) {
+    gpr_log(GPR_ERROR, "Invalid json.");
+    goto end;
+  }
+
+  prop_value = json_get_string_property(json, "type");
+  if (prop_value == NULL ||
+      strcmp(prop_value, GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT)) {
+    goto end;
+  }
+  result.type = GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT;
+
+  if (!set_json_key_string_property(json, "private_key_id",
+                                    &result.private_key_id) ||
+      !set_json_key_string_property(json, "client_id", &result.client_id) ||
+      !set_json_key_string_property(json, "client_email",
+                                    &result.client_email)) {
+    goto end;
+  }
+
+  prop_value = json_get_string_property(json, "private_key");
+  if (prop_value == NULL) {
+    goto end;
+  }
+  bio = BIO_new(BIO_s_mem());
+  success = BIO_puts(bio, prop_value);
+  if ((success < 0) || ((size_t)success != strlen(prop_value))) {
+    gpr_log(GPR_ERROR, "Could not write into openssl BIO.");
+    goto end;
+  }
+  result.private_key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, "");
+  if (result.private_key == NULL) {
+    gpr_log(GPR_ERROR, "Could not deserialize private key.");
+    goto end;
+  }
+  success = 1;
+
+end:
+  if (bio != NULL) BIO_free(bio);
+  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;
+}
+
+void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) {
+  if (json_key == NULL) return;
+  json_key->type = GRPC_AUTH_JSON_TYPE_INVALID;
+  if (json_key->client_id != NULL) {
+    gpr_free(json_key->client_id);
+    json_key->client_id = NULL;
+  }
+  if (json_key->private_key_id != NULL) {
+    gpr_free(json_key->private_key_id);
+    json_key->private_key_id = NULL;
+  }
+  if (json_key->client_email != NULL) {
+    gpr_free(json_key->client_email);
+    json_key->client_email = NULL;
+  }
+  if (json_key->private_key != NULL) {
+    RSA_free(json_key->private_key);
+    json_key->private_key = NULL;
+  }
+}
+
+/* --- jwt encoding and signature. --- */
+
+static grpc_json *create_child(grpc_json *brother, grpc_json *parent,
+                               const char *key, const char *value,
+                               grpc_json_type type) {
+  grpc_json *child = grpc_json_create(type);
+  if (brother) brother->next = child;
+  if (!parent->child) parent->child = child;
+  child->parent = parent;
+  child->value = value;
+  child->key = key;
+  return child;
+}
+
+static char *encoded_jwt_header(const char *key_id, const char *algorithm) {
+  grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT);
+  grpc_json *child = NULL;
+  char *json_str = NULL;
+  char *result = NULL;
+
+  child = create_child(NULL, json, "alg", algorithm, GRPC_JSON_STRING);
+  child = create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING);
+  create_child(child, json, "kid", key_id, GRPC_JSON_STRING);
+
+  json_str = grpc_json_dump_to_string(json, 0);
+  result = grpc_base64_encode(json_str, strlen(json_str), 1, 0);
+  gpr_free(json_str);
+  grpc_json_destroy(json);
+  return result;
+}
+
+static char *encoded_jwt_claim(const grpc_auth_json_key *json_key,
+                               const char *audience,
+                               gpr_timespec token_lifetime, const char *scope) {
+  grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT);
+  grpc_json *child = NULL;
+  char *json_str = NULL;
+  char *result = NULL;
+  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];
+  if (gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime()) > 0) {
+    gpr_log(GPR_INFO, "Cropping token lifetime to maximum allowed value.");
+    expiration = gpr_time_add(now, grpc_max_auth_token_lifetime());
+  }
+  int64_ttoa(now.tv_sec, now_str);
+  int64_ttoa(expiration.tv_sec, expiration_str);
+
+  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 {
+    /* Unscoped JWTs need a sub field. */
+    child = create_child(child, json, "sub", json_key->client_email,
+                         GRPC_JSON_STRING);
+  }
+
+  child = create_child(child, json, "aud", audience, GRPC_JSON_STRING);
+  child = create_child(child, json, "iat", now_str, GRPC_JSON_NUMBER);
+  create_child(child, json, "exp", expiration_str, GRPC_JSON_NUMBER);
+
+  json_str = grpc_json_dump_to_string(json, 0);
+  result = grpc_base64_encode(json_str, strlen(json_str), 1, 0);
+  gpr_free(json_str);
+  grpc_json_destroy(json);
+  return result;
+}
+
+static char *dot_concat_and_free_strings(char *str1, char *str2) {
+  size_t str1_len = strlen(str1);
+  size_t str2_len = strlen(str2);
+  size_t result_len = str1_len + 1 /* dot */ + str2_len;
+  char *result = gpr_malloc(result_len + 1 /* NULL terminated */);
+  char *current = result;
+  memcpy(current, str1, str1_len);
+  current += str1_len;
+  *(current++) = '.';
+  memcpy(current, str2, str2_len);
+  current += str2_len;
+  GPR_ASSERT(current >= result);
+  GPR_ASSERT((uintptr_t)(current - result) == result_len);
+  *current = '\0';
+  gpr_free(str1);
+  gpr_free(str2);
+  return result;
+}
+
+const EVP_MD *openssl_digest_from_algorithm(const char *algorithm) {
+  if (strcmp(algorithm, GRPC_JWT_RSA_SHA256_ALGORITHM) == 0) {
+    return EVP_sha256();
+  } else {
+    gpr_log(GPR_ERROR, "Unknown algorithm %s.", algorithm);
+    return NULL;
+  }
+}
+
+char *compute_and_encode_signature(const grpc_auth_json_key *json_key,
+                                   const char *signature_algorithm,
+                                   const char *to_sign) {
+  const EVP_MD *md = openssl_digest_from_algorithm(signature_algorithm);
+  EVP_MD_CTX *md_ctx = NULL;
+  EVP_PKEY *key = EVP_PKEY_new();
+  size_t sig_len = 0;
+  unsigned char *sig = NULL;
+  char *result = NULL;
+  if (md == NULL) return NULL;
+  md_ctx = EVP_MD_CTX_create();
+  if (md_ctx == NULL) {
+    gpr_log(GPR_ERROR, "Could not create MD_CTX");
+    goto end;
+  }
+  EVP_PKEY_set1_RSA(key, json_key->private_key);
+  if (EVP_DigestSignInit(md_ctx, NULL, md, NULL, key) != 1) {
+    gpr_log(GPR_ERROR, "DigestInit failed.");
+    goto end;
+  }
+  if (EVP_DigestSignUpdate(md_ctx, to_sign, strlen(to_sign)) != 1) {
+    gpr_log(GPR_ERROR, "DigestUpdate failed.");
+    goto end;
+  }
+  if (EVP_DigestSignFinal(md_ctx, NULL, &sig_len) != 1) {
+    gpr_log(GPR_ERROR, "DigestFinal (get signature length) failed.");
+    goto end;
+  }
+  sig = gpr_malloc(sig_len);
+  if (EVP_DigestSignFinal(md_ctx, sig, &sig_len) != 1) {
+    gpr_log(GPR_ERROR, "DigestFinal (signature compute) failed.");
+    goto end;
+  }
+  result = grpc_base64_encode(sig, sig_len, 1, 0);
+
+end:
+  if (key != NULL) EVP_PKEY_free(key);
+  if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx);
+  if (sig != NULL) gpr_free(sig);
+  return result;
+}
+
+char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key,
+                               const char *audience,
+                               gpr_timespec token_lifetime, const char *scope) {
+  if (g_jwt_encode_and_sign_override != NULL) {
+    return g_jwt_encode_and_sign_override(json_key, audience, token_lifetime,
+                                          scope);
+  } else {
+    const char *sig_algo = GRPC_JWT_RSA_SHA256_ALGORITHM;
+    char *to_sign = dot_concat_and_free_strings(
+        encoded_jwt_header(json_key->private_key_id, sig_algo),
+        encoded_jwt_claim(json_key, audience, token_lifetime, scope));
+    char *sig = compute_and_encode_signature(json_key, sig_algo, to_sign);
+    if (sig == NULL) {
+      gpr_free(to_sign);
+      return NULL;
+    }
+    return dot_concat_and_free_strings(to_sign, sig);
+  }
+}
+
+void grpc_jwt_encode_and_sign_set_override(
+    grpc_jwt_encode_and_sign_override func) {
+  g_jwt_encode_and_sign_override = func;
+}
+
+/* --- grpc_auth_refresh_token --- */
+
+int grpc_auth_refresh_token_is_valid(
+    const grpc_auth_refresh_token *refresh_token) {
+  return (refresh_token != NULL) &&
+         strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID);
+}
+
+grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
+    const grpc_json *json) {
+  grpc_auth_refresh_token result;
+  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.");
+    goto end;
+  }
+
+  prop_value = json_get_string_property(json, "type");
+  if (prop_value == NULL ||
+      strcmp(prop_value, GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER)) {
+    goto end;
+  }
+  result.type = GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER;
+
+  if (!set_json_key_string_property(json, "client_secret",
+                                    &result.client_secret) ||
+      !set_json_key_string_property(json, "client_id", &result.client_id) ||
+      !set_json_key_string_property(json, "refresh_token",
+                                    &result.refresh_token)) {
+    goto end;
+  }
+  success = 1;
+
+end:
+  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;
+}
+
+void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token) {
+  if (refresh_token == NULL) return;
+  refresh_token->type = GRPC_AUTH_JSON_TYPE_INVALID;
+  if (refresh_token->client_id != NULL) {
+    gpr_free(refresh_token->client_id);
+    refresh_token->client_id = NULL;
+  }
+  if (refresh_token->client_secret != NULL) {
+    gpr_free(refresh_token->client_secret);
+    refresh_token->client_secret = NULL;
+  }
+  if (refresh_token->refresh_token != NULL) {
+    gpr_free(refresh_token->refresh_token);
+    refresh_token->refresh_token = NULL;
+  }
+}
diff --git a/src/core/lib/security/json_token.h b/src/core/lib/security/json_token.h
new file mode 100644
index 0000000..376fb03
--- /dev/null
+++ b/src/core/lib/security/json_token.h
@@ -0,0 +1,118 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_JSON_TOKEN_H
+#define GRPC_CORE_LIB_SECURITY_JSON_TOKEN_H
+
+#include <grpc/support/slice.h>
+#include <openssl/rsa.h>
+
+#include "src/core/lib/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 {
+  const char *type;
+  char *private_key_id;
+  char *client_id;
+  char *client_email;
+  RSA *private_key;
+} grpc_auth_json_key;
+
+/* Returns 1 if the object is valid, 0 otherwise. */
+int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key);
+
+/* Creates a json_key object from string. Returns an invalid object if a parsing
+   error has been encountered. */
+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);
+
+/* --- json token encoding and signing. --- */
+
+/* Caller is responsible for calling gpr_free on the returned value. May return
+   NULL on invalid input. The scope parameter may be NULL. */
+char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key,
+                               const char *audience,
+                               gpr_timespec token_lifetime, const char *scope);
+
+/* Override encode_and_sign function for testing. */
+typedef char *(*grpc_jwt_encode_and_sign_override)(
+    const grpc_auth_json_key *json_key, const char *audience,
+    gpr_timespec token_lifetime, const char *scope);
+
+/* Set a custom encode_and_sign override for testing. */
+void grpc_jwt_encode_and_sign_set_override(
+    grpc_jwt_encode_and_sign_override func);
+
+/* --- auth_refresh_token parsing. --- */
+
+typedef struct {
+  const char *type;
+  char *client_id;
+  char *client_secret;
+  char *refresh_token;
+} grpc_auth_refresh_token;
+
+/* Returns 1 if the object is valid, 0 otherwise. */
+int grpc_auth_refresh_token_is_valid(
+    const grpc_auth_refresh_token *refresh_token);
+
+/* Creates a refresh token object from string. Returns an invalid object if a
+   parsing error has been encountered. */
+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);
+
+#endif /* GRPC_CORE_LIB_SECURITY_JSON_TOKEN_H */
diff --git a/src/core/lib/security/jwt_verifier.c b/src/core/lib/security/jwt_verifier.c
new file mode 100644
index 0000000..460b92f
--- /dev/null
+++ b/src/core/lib/security/jwt_verifier.c
@@ -0,0 +1,843 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/security/jwt_verifier.h"
+
+#include <limits.h>
+#include <string.h>
+
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/security/b64.h"
+#include "src/core/lib/tsi/ssl_types.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());
+  size_t len = strlen(x509_str);
+  GPR_ASSERT(len < INT_MAX);
+  BIO_write(bio, x509_str, (int)len);
+  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),
+                     TSI_SIZE_AS_SIZE(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(grpc_exec_ctx *exec_ctx, 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(grpc_exec_ctx *exec_ctx, 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.handshaker = &grpc_httpcli_ssl;
+  req.host = gpr_strdup(jwks_uri);
+  req.http.path = strchr(jwks_uri, '/');
+  if (req.http.path == NULL) {
+    req.http.path = "";
+  } else {
+    *(req.host + (req.http.path - jwks_uri)) = '\0';
+  }
+  grpc_httpcli_get(
+      exec_ctx, &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(grpc_exec_ctx *exec_ctx,
+                                    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.handshaker = &grpc_httpcli_ssl;
+
+  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.http.path, "/%s", iss);
+    } else {
+      *(path_prefix++) = '\0';
+      gpr_asprintf(&req.http.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.http.path = gpr_strdup(GRPC_OPENID_CONFIG_URL_SUFFIX);
+    } else {
+      *(path_prefix++) = 0;
+      gpr_asprintf(&req.http.path, "/%s%s", path_prefix,
+                   GRPC_OPENID_CONFIG_URL_SUFFIX);
+    }
+    http_cb = on_openid_config_retrieved;
+  }
+
+  grpc_httpcli_get(
+      exec_ctx, &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.http.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_exec_ctx *exec_ctx,
+                              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, (size_t)(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, (size_t)(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(
+      exec_ctx,
+      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/lib/security/jwt_verifier.h b/src/core/lib/security/jwt_verifier.h
new file mode 100644
index 0000000..28a9eff
--- /dev/null
+++ b/src/core/lib/security/jwt_verifier.h
@@ -0,0 +1,136 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_JWT_VERIFIER_H
+#define GRPC_CORE_LIB_SECURITY_JWT_VERIFIER_H
+
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/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_exec_ctx *exec_ctx,
+                              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_CORE_LIB_SECURITY_JWT_VERIFIER_H */
diff --git a/src/core/lib/security/secure_endpoint.c b/src/core/lib/security/secure_endpoint.c
new file mode 100644
index 0000000..e233b08
--- /dev/null
+++ b/src/core/lib/security/secure_endpoint.c
@@ -0,0 +1,384 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/security/secure_endpoint.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/sync.h>
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/tsi/transport_security_interface.h"
+
+#define STAGING_BUFFER_SIZE 8192
+
+typedef struct {
+  grpc_endpoint base;
+  grpc_endpoint *wrapped_ep;
+  struct tsi_frame_protector *protector;
+  gpr_mu protector_mu;
+  /* saved upper level callbacks and user_data. */
+  grpc_closure *read_cb;
+  grpc_closure *write_cb;
+  grpc_closure on_read;
+  gpr_slice_buffer *read_buffer;
+  gpr_slice_buffer source_buffer;
+  /* saved handshaker leftover data to unprotect. */
+  gpr_slice_buffer leftover_bytes;
+  /* buffers for read and write */
+  gpr_slice read_staging_buffer;
+
+  gpr_slice write_staging_buffer;
+  gpr_slice_buffer output_buffer;
+
+  gpr_refcount ref;
+} secure_endpoint;
+
+int grpc_trace_secure_endpoint = 0;
+
+static void destroy(grpc_exec_ctx *exec_ctx, secure_endpoint *secure_ep) {
+  secure_endpoint *ep = secure_ep;
+  grpc_endpoint_destroy(exec_ctx, ep->wrapped_ep);
+  tsi_frame_protector_destroy(ep->protector);
+  gpr_slice_buffer_destroy(&ep->leftover_bytes);
+  gpr_slice_unref(ep->read_staging_buffer);
+  gpr_slice_unref(ep->write_staging_buffer);
+  gpr_slice_buffer_destroy(&ep->output_buffer);
+  gpr_slice_buffer_destroy(&ep->source_buffer);
+  gpr_mu_destroy(&ep->protector_mu);
+  gpr_free(ep);
+}
+
+/*#define GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG*/
+#ifdef GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG
+#define SECURE_ENDPOINT_UNREF(exec_ctx, ep, reason) \
+  secure_endpoint_unref((exec_ctx), (ep), (reason), __FILE__, __LINE__)
+#define SECURE_ENDPOINT_REF(ep, reason) \
+  secure_endpoint_ref((ep), (reason), __FILE__, __LINE__)
+static void secure_endpoint_unref(secure_endpoint *ep,
+                                  grpc_closure_list *closure_list,
+                                  const char *reason, const char *file,
+                                  int line) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP unref %p : %s %d -> %d",
+          ep, reason, ep->ref.count, ep->ref.count - 1);
+  if (gpr_unref(&ep->ref)) {
+    destroy(exec_ctx, ep);
+  }
+}
+
+static void secure_endpoint_ref(secure_endpoint *ep, const char *reason,
+                                const char *file, int line) {
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP   ref %p : %s %d -> %d",
+          ep, reason, ep->ref.count, ep->ref.count + 1);
+  gpr_ref(&ep->ref);
+}
+#else
+#define SECURE_ENDPOINT_UNREF(exec_ctx, ep, reason) \
+  secure_endpoint_unref((exec_ctx), (ep))
+#define SECURE_ENDPOINT_REF(ep, reason) secure_endpoint_ref((ep))
+static void secure_endpoint_unref(grpc_exec_ctx *exec_ctx,
+                                  secure_endpoint *ep) {
+  if (gpr_unref(&ep->ref)) {
+    destroy(exec_ctx, ep);
+  }
+}
+
+static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); }
+#endif
+
+static void flush_read_staging_buffer(secure_endpoint *ep, uint8_t **cur,
+                                      uint8_t **end) {
+  gpr_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer);
+  ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
+  *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
+  *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
+}
+
+static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep,
+                         bool success) {
+  if (grpc_trace_secure_endpoint) {
+    size_t i;
+    for (i = 0; i < ep->read_buffer->count; i++) {
+      char *data = gpr_dump_slice(ep->read_buffer->slices[i],
+                                  GPR_DUMP_HEX | GPR_DUMP_ASCII);
+      gpr_log(GPR_DEBUG, "READ %p: %s", ep, data);
+      gpr_free(data);
+    }
+  }
+  ep->read_buffer = NULL;
+  grpc_exec_ctx_enqueue(exec_ctx, ep->read_cb, success, NULL);
+  SECURE_ENDPOINT_UNREF(exec_ctx, ep, "read");
+}
+
+static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
+  unsigned i;
+  uint8_t keep_looping = 0;
+  tsi_result result = TSI_OK;
+  secure_endpoint *ep = (secure_endpoint *)user_data;
+  uint8_t *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
+  uint8_t *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
+
+  if (!success) {
+    gpr_slice_buffer_reset_and_unref(ep->read_buffer);
+    call_read_cb(exec_ctx, ep, 0);
+    return;
+  }
+
+  /* TODO(yangg) check error, maybe bail out early */
+  for (i = 0; i < ep->source_buffer.count; i++) {
+    gpr_slice encrypted = ep->source_buffer.slices[i];
+    uint8_t *message_bytes = GPR_SLICE_START_PTR(encrypted);
+    size_t message_size = GPR_SLICE_LENGTH(encrypted);
+
+    while (message_size > 0 || keep_looping) {
+      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,
+                                             &processed_message_size, cur,
+                                             &unprotected_buffer_size_written);
+      gpr_mu_unlock(&ep->protector_mu);
+      if (result != TSI_OK) {
+        gpr_log(GPR_ERROR, "Decryption error: %s",
+                tsi_result_to_string(result));
+        break;
+      }
+      message_bytes += processed_message_size;
+      message_size -= processed_message_size;
+      cur += unprotected_buffer_size_written;
+
+      if (cur == end) {
+        flush_read_staging_buffer(ep, &cur, &end);
+        /* Force to enter the loop again to extract buffered bytes in protector.
+           The bytes could be buffered because of running out of staging_buffer.
+           If this happens at the end of all slices, doing another unprotect
+           avoids leaving data in the protector. */
+        keep_looping = 1;
+      } else if (unprotected_buffer_size_written > 0) {
+        keep_looping = 1;
+      } else {
+        keep_looping = 0;
+      }
+    }
+    if (result != TSI_OK) break;
+  }
+
+  if (cur != GPR_SLICE_START_PTR(ep->read_staging_buffer)) {
+    gpr_slice_buffer_add(
+        ep->read_buffer,
+        gpr_slice_split_head(
+            &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
+     helps latency */
+  gpr_slice_buffer_reset_and_unref(&ep->source_buffer);
+
+  if (result != TSI_OK) {
+    gpr_slice_buffer_reset_and_unref(ep->read_buffer);
+    call_read_cb(exec_ctx, ep, 0);
+    return;
+  }
+
+  call_read_cb(exec_ctx, ep, 1);
+}
+
+static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
+                          gpr_slice_buffer *slices, grpc_closure *cb) {
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  ep->read_cb = cb;
+  ep->read_buffer = slices;
+  gpr_slice_buffer_reset_and_unref(ep->read_buffer);
+
+  SECURE_ENDPOINT_REF(ep, "read");
+  if (ep->leftover_bytes.count) {
+    gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer);
+    GPR_ASSERT(ep->leftover_bytes.count == 0);
+    on_read(exec_ctx, ep, 1);
+    return;
+  }
+
+  grpc_endpoint_read(exec_ctx, ep->wrapped_ep, &ep->source_buffer,
+                     &ep->on_read);
+}
+
+static void flush_write_staging_buffer(secure_endpoint *ep, uint8_t **cur,
+                                       uint8_t **end) {
+  gpr_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer);
+  ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
+  *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
+  *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
+}
+
+static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
+                           gpr_slice_buffer *slices, grpc_closure *cb) {
+  unsigned i;
+  tsi_result result = TSI_OK;
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  uint8_t *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
+  uint8_t *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
+
+  gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
+
+  if (grpc_trace_secure_endpoint) {
+    for (i = 0; i < slices->count; i++) {
+      char *data =
+          gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
+      gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data);
+      gpr_free(data);
+    }
+  }
+
+  for (i = 0; i < slices->count; i++) {
+    gpr_slice plain = slices->slices[i];
+    uint8_t *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 = (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,
+                                           &processed_message_size, cur,
+                                           &protected_buffer_size_to_send);
+      gpr_mu_unlock(&ep->protector_mu);
+      if (result != TSI_OK) {
+        gpr_log(GPR_ERROR, "Encryption error: %s",
+                tsi_result_to_string(result));
+        break;
+      }
+      message_bytes += processed_message_size;
+      message_size -= processed_message_size;
+      cur += protected_buffer_size_to_send;
+
+      if (cur == end) {
+        flush_write_staging_buffer(ep, &cur, &end);
+      }
+    }
+    if (result != TSI_OK) break;
+  }
+  if (result == TSI_OK) {
+    size_t still_pending_size;
+    do {
+      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,
+                                                 &still_pending_size);
+      gpr_mu_unlock(&ep->protector_mu);
+      if (result != TSI_OK) break;
+      cur += protected_buffer_size_to_send;
+      if (cur == end) {
+        flush_write_staging_buffer(ep, &cur, &end);
+      }
+    } while (still_pending_size > 0);
+    if (cur != GPR_SLICE_START_PTR(ep->write_staging_buffer)) {
+      gpr_slice_buffer_add(
+          &ep->output_buffer,
+          gpr_slice_split_head(
+              &ep->write_staging_buffer,
+              (size_t)(cur - GPR_SLICE_START_PTR(ep->write_staging_buffer))));
+    }
+  }
+
+  if (result != TSI_OK) {
+    /* TODO(yangg) do different things according to the error type? */
+    gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
+    grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
+    return;
+  }
+
+  grpc_endpoint_write(exec_ctx, ep->wrapped_ep, &ep->output_buffer, cb);
+}
+
+static void endpoint_shutdown(grpc_exec_ctx *exec_ctx,
+                              grpc_endpoint *secure_ep) {
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  grpc_endpoint_shutdown(exec_ctx, ep->wrapped_ep);
+}
+
+static void endpoint_destroy(grpc_exec_ctx *exec_ctx,
+                             grpc_endpoint *secure_ep) {
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  SECURE_ENDPOINT_UNREF(exec_ctx, ep, "destroy");
+}
+
+static void endpoint_add_to_pollset(grpc_exec_ctx *exec_ctx,
+                                    grpc_endpoint *secure_ep,
+                                    grpc_pollset *pollset) {
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  grpc_endpoint_add_to_pollset(exec_ctx, ep->wrapped_ep, pollset);
+}
+
+static void endpoint_add_to_pollset_set(grpc_exec_ctx *exec_ctx,
+                                        grpc_endpoint *secure_ep,
+                                        grpc_pollset_set *pollset_set) {
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  grpc_endpoint_add_to_pollset_set(exec_ctx, ep->wrapped_ep, pollset_set);
+}
+
+static char *endpoint_get_peer(grpc_endpoint *secure_ep) {
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  return grpc_endpoint_get_peer(ep->wrapped_ep);
+}
+
+static const grpc_endpoint_vtable vtable = {
+    endpoint_read,           endpoint_write,
+    endpoint_add_to_pollset, endpoint_add_to_pollset_set,
+    endpoint_shutdown,       endpoint_destroy,
+    endpoint_get_peer};
+
+grpc_endpoint *grpc_secure_endpoint_create(
+    struct tsi_frame_protector *protector, grpc_endpoint *transport,
+    gpr_slice *leftover_slices, size_t leftover_nslices) {
+  size_t i;
+  secure_endpoint *ep = (secure_endpoint *)gpr_malloc(sizeof(secure_endpoint));
+  ep->base.vtable = &vtable;
+  ep->wrapped_ep = transport;
+  ep->protector = protector;
+  gpr_slice_buffer_init(&ep->leftover_bytes);
+  for (i = 0; i < leftover_nslices; i++) {
+    gpr_slice_buffer_add(&ep->leftover_bytes,
+                         gpr_slice_ref(leftover_slices[i]));
+  }
+  ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
+  ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
+  gpr_slice_buffer_init(&ep->output_buffer);
+  gpr_slice_buffer_init(&ep->source_buffer);
+  ep->read_buffer = NULL;
+  grpc_closure_init(&ep->on_read, on_read, ep);
+  gpr_mu_init(&ep->protector_mu);
+  gpr_ref_init(&ep->ref, 1);
+  return &ep->base;
+}
diff --git a/src/core/lib/security/secure_endpoint.h b/src/core/lib/security/secure_endpoint.h
new file mode 100644
index 0000000..57bd160
--- /dev/null
+++ b/src/core/lib/security/secure_endpoint.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_SECURE_ENDPOINT_H
+#define GRPC_CORE_LIB_SECURITY_SECURE_ENDPOINT_H
+
+#include <grpc/support/slice.h>
+#include "src/core/lib/iomgr/endpoint.h"
+
+struct tsi_frame_protector;
+
+extern int grpc_trace_secure_endpoint;
+
+/* Takes ownership of protector and to_wrap, and refs leftover_slices. */
+grpc_endpoint *grpc_secure_endpoint_create(
+    struct tsi_frame_protector *protector, grpc_endpoint *to_wrap,
+    gpr_slice *leftover_slices, size_t leftover_nslices);
+
+#endif /* GRPC_CORE_LIB_SECURITY_SECURE_ENDPOINT_H */
diff --git a/src/core/lib/security/security_connector.c b/src/core/lib/security/security_connector.c
new file mode 100644
index 0000000..48b23a9
--- /dev/null
+++ b/src/core/lib/security/security_connector.c
@@ -0,0 +1,812 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/security/security_connector.h"
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/transport/chttp2/transport/alpn.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/security/handshake.h"
+#include "src/core/lib/security/secure_endpoint.h"
+#include "src/core/lib/security/security_context.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/load_file.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/tsi/fake_transport_security.h"
+#include "src/core/lib/tsi/ssl_transport_security.h"
+
+/* -- Constants. -- */
+
+#ifndef INSTALL_PREFIX
+static const char *installed_roots_path = "/usr/share/grpc/roots.pem";
+#else
+static const char *installed_roots_path =
+    INSTALL_PREFIX "/share/grpc/roots.pem";
+#endif
+
+/* -- Overridden default roots. -- */
+
+static grpc_ssl_roots_override_callback ssl_roots_override_cb = NULL;
+
+void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb) {
+  ssl_roots_override_cb = cb;
+}
+
+/* -- Cipher suites. -- */
+
+/* Defines the cipher suites that we accept by default. All these cipher suites
+   are compliant with HTTP2. */
+#define GRPC_SSL_CIPHER_SUITES                                            \
+  "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-" \
+  "SHA384:ECDHE-RSA-AES256-GCM-SHA384"
+
+static gpr_once cipher_suites_once = GPR_ONCE_INIT;
+static const char *cipher_suites = NULL;
+
+static void init_cipher_suites(void) {
+  char *overridden = gpr_getenv("GRPC_SSL_CIPHER_SUITES");
+  cipher_suites = overridden != NULL ? overridden : GRPC_SSL_CIPHER_SUITES;
+}
+
+static const char *ssl_cipher_suites(void) {
+  gpr_once_init(&cipher_suites_once, init_cipher_suites);
+  return cipher_suites;
+}
+
+/* -- 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) {
+  size_t i;
+  if (peer == NULL) return NULL;
+  for (i = 0; i < peer->property_count; i++) {
+    const tsi_peer_property *property = &peer->properties[i];
+    if (name == NULL && property->name == NULL) {
+      return property;
+    }
+    if (name != NULL && property->name != NULL &&
+        strcmp(property->name, name) == 0) {
+      return property;
+    }
+  }
+  return NULL;
+}
+
+void grpc_server_security_connector_shutdown(
+    grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector) {
+  grpc_security_connector_handshake_list *tmp;
+  gpr_mu_lock(&connector->mu);
+  while (connector->handshaking_handshakes) {
+    tmp = connector->handshaking_handshakes;
+    grpc_security_handshake_shutdown(
+        exec_ctx, connector->handshaking_handshakes->handshake);
+    connector->handshaking_handshakes = tmp->next;
+    gpr_free(tmp);
+  }
+  gpr_mu_unlock(&connector->mu);
+}
+
+void grpc_channel_security_connector_do_handshake(
+    grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
+    grpc_endpoint *nonsecure_endpoint, grpc_security_handshake_done_cb cb,
+    void *user_data) {
+  if (sc == NULL || nonsecure_endpoint == NULL) {
+    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
+  } else {
+    sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, cb, user_data);
+  }
+}
+
+void grpc_server_security_connector_do_handshake(
+    grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
+    grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
+    grpc_security_handshake_done_cb cb, void *user_data) {
+  if (sc == NULL || nonsecure_endpoint == NULL) {
+    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
+  } else {
+    sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, cb, user_data);
+  }
+}
+
+void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
+                                        grpc_security_connector *sc,
+                                        tsi_peer peer,
+                                        grpc_security_peer_check_cb cb,
+                                        void *user_data) {
+  if (sc == NULL) {
+    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL);
+    tsi_peer_destruct(&peer);
+  } else {
+    sc->vtable->check_peer(exec_ctx, sc, peer, cb, user_data);
+  }
+}
+
+void grpc_channel_security_connector_check_call_host(
+    grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
+    const char *host, grpc_auth_context *auth_context,
+    grpc_security_call_host_check_cb cb, void *user_data) {
+  if (sc == NULL || sc->check_call_host == NULL) {
+    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR);
+  } else {
+    sc->check_call_host(exec_ctx, sc, host, auth_context, cb, user_data);
+  }
+}
+
+#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, "connector_pointer_arg");
+}
+
+static void *connector_pointer_arg_copy(void *p) {
+  return GRPC_SECURITY_CONNECTOR_REF(p, "connector_pointer_arg");
+}
+
+static int connector_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); }
+
+static const grpc_arg_pointer_vtable connector_pointer_vtable = {
+    connector_pointer_arg_copy, connector_pointer_arg_destroy,
+    connector_pointer_cmp};
+
+grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) {
+  grpc_arg result;
+  result.type = GRPC_ARG_POINTER;
+  result.key = GRPC_SECURITY_CONNECTOR_ARG;
+  result.value.pointer.vtable = &connector_pointer_vtable;
+  result.value.pointer.p = sc;
+  return result;
+}
+
+grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) {
+  if (strcmp(arg->key, GRPC_SECURITY_CONNECTOR_ARG)) return NULL;
+  if (arg->type != GRPC_ARG_POINTER) {
+    gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
+            GRPC_SECURITY_CONNECTOR_ARG);
+    return NULL;
+  }
+  return arg->value.pointer.p;
+}
+
+grpc_security_connector *grpc_find_security_connector_in_args(
+    const grpc_channel_args *args) {
+  size_t i;
+  if (args == NULL) return NULL;
+  for (i = 0; i < args->num_args; i++) {
+    grpc_security_connector *sc =
+        grpc_security_connector_from_arg(&args->args[i]);
+    if (sc != NULL) return sc;
+  }
+  return NULL;
+}
+
+/* -- Fake implementation. -- */
+
+static void fake_channel_destroy(grpc_security_connector *sc) {
+  grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
+  grpc_call_credentials_unref(c->request_metadata_creds);
+  gpr_free(sc);
+}
+
+static void fake_server_destroy(grpc_security_connector *sc) {
+  grpc_server_security_connector *c = (grpc_server_security_connector *)sc;
+  gpr_mu_destroy(&c->mu);
+  gpr_free(sc);
+}
+
+static void fake_check_peer(grpc_exec_ctx *exec_ctx,
+                            grpc_security_connector *sc, tsi_peer peer,
+                            grpc_security_peer_check_cb cb, void *user_data) {
+  const char *prop_name;
+  grpc_security_status status = GRPC_SECURITY_OK;
+  grpc_auth_context *auth_context = NULL;
+  if (peer.property_count != 1) {
+    gpr_log(GPR_ERROR, "Fake peers should only have 1 property.");
+    status = GRPC_SECURITY_ERROR;
+    goto end;
+  }
+  prop_name = peer.properties[0].name;
+  if (prop_name == NULL ||
+      strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) {
+    gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.",
+            prop_name == NULL ? "<EMPTY>" : prop_name);
+    status = GRPC_SECURITY_ERROR;
+    goto end;
+  }
+  if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE,
+              peer.properties[0].value.length)) {
+    gpr_log(GPR_ERROR, "Invalid value for cert type property.");
+    status = GRPC_SECURITY_ERROR;
+    goto end;
+  }
+  auth_context = grpc_auth_context_create(NULL);
+  grpc_auth_context_add_cstring_property(
+      auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+      GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
+
+end:
+  cb(exec_ctx, user_data, status, auth_context);
+  grpc_auth_context_unref(auth_context);
+  tsi_peer_destruct(&peer);
+}
+
+static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx,
+                                         grpc_channel_security_connector *sc,
+                                         const char *host,
+                                         grpc_auth_context *auth_context,
+                                         grpc_security_call_host_check_cb cb,
+                                         void *user_data) {
+  cb(exec_ctx, user_data, GRPC_SECURITY_OK);
+}
+
+static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx,
+                                      grpc_channel_security_connector *sc,
+                                      grpc_endpoint *nonsecure_endpoint,
+                                      grpc_security_handshake_done_cb cb,
+                                      void *user_data) {
+  grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(1), &sc->base,
+                             true, nonsecure_endpoint, cb, user_data);
+}
+
+static void fake_server_do_handshake(grpc_exec_ctx *exec_ctx,
+                                     grpc_server_security_connector *sc,
+                                     grpc_tcp_server_acceptor *acceptor,
+                                     grpc_endpoint *nonsecure_endpoint,
+                                     grpc_security_handshake_done_cb cb,
+                                     void *user_data) {
+  grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), &sc->base,
+                             false, nonsecure_endpoint, cb, user_data);
+}
+
+static grpc_security_connector_vtable fake_channel_vtable = {
+    fake_channel_destroy, fake_check_peer};
+
+static grpc_security_connector_vtable fake_server_vtable = {fake_server_destroy,
+                                                            fake_check_peer};
+
+grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
+    grpc_call_credentials *request_metadata_creds) {
+  grpc_channel_security_connector *c = gpr_malloc(sizeof(*c));
+  memset(c, 0, sizeof(*c));
+  gpr_ref_init(&c->base.refcount, 1);
+  c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
+  c->base.vtable = &fake_channel_vtable;
+  c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds);
+  c->check_call_host = fake_channel_check_call_host;
+  c->do_handshake = fake_channel_do_handshake;
+  return c;
+}
+
+grpc_server_security_connector *grpc_fake_server_security_connector_create(
+    void) {
+  grpc_server_security_connector *c =
+      gpr_malloc(sizeof(grpc_server_security_connector));
+  memset(c, 0, sizeof(*c));
+  gpr_ref_init(&c->base.refcount, 1);
+  c->base.vtable = &fake_server_vtable;
+  c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
+  c->do_handshake = fake_server_do_handshake;
+  gpr_mu_init(&c->mu);
+  return c;
+}
+
+/* --- Ssl implementation. --- */
+
+typedef struct {
+  grpc_channel_security_connector base;
+  tsi_ssl_handshaker_factory *handshaker_factory;
+  char *target_name;
+  char *overridden_target_name;
+} grpc_ssl_channel_security_connector;
+
+typedef struct {
+  grpc_server_security_connector base;
+  tsi_ssl_handshaker_factory *handshaker_factory;
+} grpc_ssl_server_security_connector;
+
+static void ssl_channel_destroy(grpc_security_connector *sc) {
+  grpc_ssl_channel_security_connector *c =
+      (grpc_ssl_channel_security_connector *)sc;
+  grpc_call_credentials_unref(c->base.request_metadata_creds);
+  if (c->handshaker_factory != NULL) {
+    tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
+  }
+  if (c->target_name != NULL) gpr_free(c->target_name);
+  if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name);
+  gpr_free(sc);
+}
+
+static void ssl_server_destroy(grpc_security_connector *sc) {
+  grpc_ssl_server_security_connector *c =
+      (grpc_ssl_server_security_connector *)sc;
+
+  if (c->handshaker_factory != NULL) {
+    tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
+  }
+  gpr_mu_destroy(&c->base.mu);
+  gpr_free(sc);
+}
+
+static grpc_security_status ssl_create_handshaker(
+    tsi_ssl_handshaker_factory *handshaker_factory, bool is_client,
+    const char *peer_name, tsi_handshaker **handshaker) {
+  tsi_result result = TSI_OK;
+  if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
+  result = tsi_ssl_handshaker_factory_create_handshaker(
+      handshaker_factory, is_client ? peer_name : NULL, handshaker);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
+            tsi_result_to_string(result));
+    return GRPC_SECURITY_ERROR;
+  }
+  return GRPC_SECURITY_OK;
+}
+
+static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_security_connector *sc,
+                                     grpc_endpoint *nonsecure_endpoint,
+                                     grpc_security_handshake_done_cb cb,
+                                     void *user_data) {
+  grpc_ssl_channel_security_connector *c =
+      (grpc_ssl_channel_security_connector *)sc;
+  tsi_handshaker *handshaker;
+  grpc_security_status status = ssl_create_handshaker(
+      c->handshaker_factory, true,
+      c->overridden_target_name != NULL ? c->overridden_target_name
+                                        : c->target_name,
+      &handshaker);
+  if (status != GRPC_SECURITY_OK) {
+    cb(exec_ctx, user_data, status, NULL, NULL);
+  } else {
+    grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
+                               nonsecure_endpoint, cb, user_data);
+  }
+}
+
+static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx,
+                                    grpc_server_security_connector *sc,
+                                    grpc_tcp_server_acceptor *acceptor,
+                                    grpc_endpoint *nonsecure_endpoint,
+                                    grpc_security_handshake_done_cb cb,
+                                    void *user_data) {
+  grpc_ssl_server_security_connector *c =
+      (grpc_ssl_server_security_connector *)sc;
+  tsi_handshaker *handshaker;
+  grpc_security_status status =
+      ssl_create_handshaker(c->handshaker_factory, false, NULL, &handshaker);
+  if (status != GRPC_SECURITY_OK) {
+    cb(exec_ctx, user_data, status, NULL, NULL);
+  } else {
+    grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, false,
+                               nonsecure_endpoint, cb, user_data);
+  }
+}
+
+static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
+  char *allocated_name = NULL;
+  int r;
+
+  if (strchr(peer_name, ':') != NULL) {
+    char *ignored_port;
+    gpr_split_host_port(peer_name, &allocated_name, &ignored_port);
+    gpr_free(ignored_port);
+    peer_name = allocated_name;
+    if (!peer_name) return 0;
+  }
+  r = tsi_ssl_peer_matches_name(peer, peer_name);
+  gpr_free(allocated_name);
+  return r;
+}
+
+grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
+  size_t i;
+  grpc_auth_context *ctx = NULL;
+  const char *peer_identity_property_name = NULL;
+
+  /* The caller has checked the certificate type property. */
+  GPR_ASSERT(peer->property_count >= 1);
+  ctx = grpc_auth_context_create(NULL);
+  grpc_auth_context_add_cstring_property(
+      ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+      GRPC_SSL_TRANSPORT_SECURITY_TYPE);
+  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) {
+      /* If there is no subject alt name, have the CN as the identity. */
+      if (peer_identity_property_name == NULL) {
+        peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME;
+      }
+      grpc_auth_context_add_property(ctx, GRPC_X509_CN_PROPERTY_NAME,
+                                     prop->value.data, prop->value.length);
+    } else if (strcmp(prop->name,
+                      TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
+      peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME;
+      grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME,
+                                     prop->value.data, prop->value.length);
+    } else if (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0) {
+      grpc_auth_context_add_property(ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME,
+                                     prop->value.data, prop->value.length);
+    }
+  }
+  if (peer_identity_property_name != NULL) {
+    GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
+                   ctx, peer_identity_property_name) == 1);
+  }
+  return ctx;
+}
+
+static grpc_security_status ssl_check_peer(grpc_security_connector *sc,
+                                           const char *peer_name,
+                                           const tsi_peer *peer,
+                                           grpc_auth_context **auth_context) {
+  /* Check the ALPN. */
+  const tsi_peer_property *p =
+      tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
+  if (p == NULL) {
+    gpr_log(GPR_ERROR, "Missing selected ALPN property.");
+    return GRPC_SECURITY_ERROR;
+  }
+  if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) {
+    gpr_log(GPR_ERROR, "Invalid ALPN value.");
+    return GRPC_SECURITY_ERROR;
+  }
+
+  /* Check the peer name if specified. */
+  if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) {
+    gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
+    return GRPC_SECURITY_ERROR;
+  }
+  *auth_context = tsi_ssl_peer_to_auth_context(peer);
+  return GRPC_SECURITY_OK;
+}
+
+static void ssl_channel_check_peer(grpc_exec_ctx *exec_ctx,
+                                   grpc_security_connector *sc, tsi_peer peer,
+                                   grpc_security_peer_check_cb cb,
+                                   void *user_data) {
+  grpc_ssl_channel_security_connector *c =
+      (grpc_ssl_channel_security_connector *)sc;
+  grpc_security_status status;
+  grpc_auth_context *auth_context = NULL;
+  status = ssl_check_peer(sc, c->overridden_target_name != NULL
+                                  ? c->overridden_target_name
+                                  : c->target_name,
+                          &peer, &auth_context);
+  cb(exec_ctx, user_data, status, auth_context);
+  grpc_auth_context_unref(auth_context);
+  tsi_peer_destruct(&peer);
+}
+
+static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx,
+                                  grpc_security_connector *sc, tsi_peer peer,
+                                  grpc_security_peer_check_cb cb,
+                                  void *user_data) {
+  grpc_auth_context *auth_context = NULL;
+  grpc_security_status status = ssl_check_peer(sc, NULL, &peer, &auth_context);
+  tsi_peer_destruct(&peer);
+  cb(exec_ctx, user_data, status, auth_context);
+  grpc_auth_context_unref(auth_context);
+}
+
+static void add_shallow_auth_property_to_peer(tsi_peer *peer,
+                                              const grpc_auth_property *prop,
+                                              const char *tsi_prop_name) {
+  tsi_peer_property *tsi_prop = &peer->properties[peer->property_count++];
+  tsi_prop->name = (char *)tsi_prop_name;
+  tsi_prop->value.data = prop->value;
+  tsi_prop->value.length = prop->value_length;
+}
+
+tsi_peer tsi_shallow_peer_from_ssl_auth_context(
+    const grpc_auth_context *auth_context) {
+  size_t max_num_props = 0;
+  grpc_auth_property_iterator it;
+  const grpc_auth_property *prop;
+  tsi_peer peer;
+  memset(&peer, 0, sizeof(peer));
+
+  it = grpc_auth_context_property_iterator(auth_context);
+  while (grpc_auth_property_iterator_next(&it) != NULL) max_num_props++;
+
+  if (max_num_props > 0) {
+    peer.properties = gpr_malloc(max_num_props * sizeof(tsi_peer_property));
+    it = grpc_auth_context_property_iterator(auth_context);
+    while ((prop = grpc_auth_property_iterator_next(&it)) != NULL) {
+      if (strcmp(prop->name, GRPC_X509_SAN_PROPERTY_NAME) == 0) {
+        add_shallow_auth_property_to_peer(
+            &peer, prop, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY);
+      } else if (strcmp(prop->name, GRPC_X509_CN_PROPERTY_NAME) == 0) {
+        add_shallow_auth_property_to_peer(
+            &peer, prop, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY);
+      } else if (strcmp(prop->name, GRPC_X509_PEM_CERT_PROPERTY_NAME) == 0) {
+        add_shallow_auth_property_to_peer(&peer, prop,
+                                          TSI_X509_PEM_CERT_PROPERTY);
+      }
+    }
+  }
+  return peer;
+}
+
+void tsi_shallow_peer_destruct(tsi_peer *peer) {
+  if (peer->properties != NULL) gpr_free(peer->properties);
+}
+
+static void ssl_channel_check_call_host(grpc_exec_ctx *exec_ctx,
+                                        grpc_channel_security_connector *sc,
+                                        const char *host,
+                                        grpc_auth_context *auth_context,
+                                        grpc_security_call_host_check_cb cb,
+                                        void *user_data) {
+  grpc_ssl_channel_security_connector *c =
+      (grpc_ssl_channel_security_connector *)sc;
+  grpc_security_status status = GRPC_SECURITY_ERROR;
+  tsi_peer peer = tsi_shallow_peer_from_ssl_auth_context(auth_context);
+  if (ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK;
+
+  /* If the target name was overridden, then the original target_name was
+     'checked' transitively during the previous peer check at the end of the
+     handshake. */
+  if (c->overridden_target_name != NULL && strcmp(host, c->target_name) == 0) {
+    status = GRPC_SECURITY_OK;
+  }
+  cb(exec_ctx, user_data, status);
+  tsi_shallow_peer_destruct(&peer);
+}
+
+static grpc_security_connector_vtable ssl_channel_vtable = {
+    ssl_channel_destroy, ssl_channel_check_peer};
+
+static grpc_security_connector_vtable ssl_server_vtable = {
+    ssl_server_destroy, ssl_server_check_peer};
+
+static gpr_slice compute_default_pem_root_certs_once(void) {
+  gpr_slice result = gpr_empty_slice();
+
+  /* First try to load the roots from the environment. */
+  char *default_root_certs_path =
+      gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
+  if (default_root_certs_path != NULL) {
+    result = gpr_load_file(default_root_certs_path, 0, NULL);
+    gpr_free(default_root_certs_path);
+  }
+
+  /* Try overridden roots if needed. */
+  grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL;
+  if (GPR_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != NULL) {
+    char *pem_root_certs = NULL;
+    ovrd_res = ssl_roots_override_cb(&pem_root_certs);
+    if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) {
+      GPR_ASSERT(pem_root_certs != NULL);
+      result = gpr_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free);
+    }
+  }
+
+  /* Fall back to installed certs if needed. */
+  if (GPR_SLICE_IS_EMPTY(result) &&
+      ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
+    result = gpr_load_file(installed_roots_path, 0, NULL);
+  }
+  return result;
+}
+
+static gpr_slice default_pem_root_certs;
+
+static void init_default_pem_root_certs(void) {
+  default_pem_root_certs = compute_default_pem_root_certs_once();
+}
+
+gpr_slice grpc_get_default_ssl_roots_for_testing(void) {
+  return compute_default_pem_root_certs_once();
+}
+
+size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
+  /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in
+     loading all the roots once for the lifetime of the process. */
+  static gpr_once once = GPR_ONCE_INIT;
+  gpr_once_init(&once, init_default_pem_root_certs);
+  *pem_root_certs = GPR_SLICE_START_PTR(default_pem_root_certs);
+  return GPR_SLICE_LENGTH(default_pem_root_certs);
+}
+
+grpc_security_status grpc_ssl_channel_security_connector_create(
+    grpc_call_credentials *request_metadata_creds,
+    const grpc_ssl_config *config, const char *target_name,
+    const char *overridden_target_name, grpc_channel_security_connector **sc) {
+  size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
+  const unsigned char **alpn_protocol_strings =
+      gpr_malloc(sizeof(const char *) * num_alpn_protocols);
+  unsigned char *alpn_protocol_string_lengths =
+      gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
+  tsi_result result = TSI_OK;
+  grpc_ssl_channel_security_connector *c;
+  size_t i;
+  const unsigned char *pem_root_certs;
+  size_t pem_root_certs_size;
+  char *port;
+
+  for (i = 0; i < num_alpn_protocols; i++) {
+    alpn_protocol_strings[i] =
+        (const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
+    alpn_protocol_string_lengths[i] =
+        (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i));
+  }
+
+  if (config == NULL || target_name == NULL) {
+    gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name.");
+    goto error;
+  }
+  if (config->pem_root_certs == NULL) {
+    pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
+    if (pem_root_certs == NULL || pem_root_certs_size == 0) {
+      gpr_log(GPR_ERROR, "Could not get default pem root certs.");
+      goto error;
+    }
+  } else {
+    pem_root_certs = config->pem_root_certs;
+    pem_root_certs_size = config->pem_root_certs_size;
+  }
+
+  c = gpr_malloc(sizeof(grpc_ssl_channel_security_connector));
+  memset(c, 0, sizeof(grpc_ssl_channel_security_connector));
+
+  gpr_ref_init(&c->base.base.refcount, 1);
+  c->base.base.vtable = &ssl_channel_vtable;
+  c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
+  c->base.request_metadata_creds =
+      grpc_call_credentials_ref(request_metadata_creds);
+  c->base.check_call_host = ssl_channel_check_call_host;
+  c->base.do_handshake = ssl_channel_do_handshake;
+  gpr_split_host_port(target_name, &c->target_name, &port);
+  gpr_free(port);
+  if (overridden_target_name != NULL) {
+    c->overridden_target_name = gpr_strdup(overridden_target_name);
+  }
+  result = tsi_create_ssl_client_handshaker_factory(
+      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, (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));
+    ssl_channel_destroy(&c->base.base);
+    *sc = NULL;
+    goto error;
+  }
+  *sc = &c->base;
+  gpr_free((void *)alpn_protocol_strings);
+  gpr_free(alpn_protocol_string_lengths);
+  return GRPC_SECURITY_OK;
+
+error:
+  gpr_free((void *)alpn_protocol_strings);
+  gpr_free(alpn_protocol_string_lengths);
+  return GRPC_SECURITY_ERROR;
+}
+
+grpc_security_status grpc_ssl_server_security_connector_create(
+    const grpc_ssl_server_config *config, grpc_server_security_connector **sc) {
+  size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
+  const unsigned char **alpn_protocol_strings =
+      gpr_malloc(sizeof(const char *) * num_alpn_protocols);
+  unsigned char *alpn_protocol_string_lengths =
+      gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
+  tsi_result result = TSI_OK;
+  grpc_ssl_server_security_connector *c;
+  size_t i;
+
+  for (i = 0; i < num_alpn_protocols; i++) {
+    alpn_protocol_strings[i] =
+        (const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
+    alpn_protocol_string_lengths[i] =
+        (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i));
+  }
+
+  if (config == NULL || config->num_key_cert_pairs == 0) {
+    gpr_log(GPR_ERROR, "An SSL server needs a key and a cert.");
+    goto error;
+  }
+  c = gpr_malloc(sizeof(grpc_ssl_server_security_connector));
+  memset(c, 0, sizeof(grpc_ssl_server_security_connector));
+
+  gpr_ref_init(&c->base.base.refcount, 1);
+  c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
+  c->base.base.vtable = &ssl_server_vtable;
+  result = tsi_create_ssl_server_handshaker_factory(
+      (const unsigned char **)config->pem_private_keys,
+      config->pem_private_keys_sizes,
+      (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,
+      config->force_client_auth, ssl_cipher_suites(), 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));
+    ssl_server_destroy(&c->base.base);
+    *sc = NULL;
+    goto error;
+  }
+  gpr_mu_init(&c->base.mu);
+  c->base.do_handshake = ssl_server_do_handshake;
+  *sc = &c->base;
+  gpr_free((void *)alpn_protocol_strings);
+  gpr_free(alpn_protocol_string_lengths);
+  return GRPC_SECURITY_OK;
+
+error:
+  gpr_free((void *)alpn_protocol_strings);
+  gpr_free(alpn_protocol_string_lengths);
+  return GRPC_SECURITY_ERROR;
+}
diff --git a/src/core/lib/security/security_connector.h b/src/core/lib/security/security_connector.h
new file mode 100644
index 0000000..d50091c
--- /dev/null
+++ b/src/core/lib/security/security_connector.h
@@ -0,0 +1,266 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_H
+#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_H
+
+#include <grpc/grpc_security.h>
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/tsi/transport_security_interface.h"
+
+/* --- status enum. --- */
+
+typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_ERROR } grpc_security_status;
+
+/* --- URL schemes. --- */
+
+#define GRPC_SSL_URL_SCHEME "https"
+#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security"
+
+/* --- security_connector object. ---
+
+    A security connector object represents away to configure the underlying
+    transport security mechanism and check the resulting trusted peer.  */
+
+typedef struct grpc_security_connector grpc_security_connector;
+
+#define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector"
+
+typedef void (*grpc_security_peer_check_cb)(grpc_exec_ctx *exec_ctx,
+                                            void *user_data,
+                                            grpc_security_status status,
+                                            grpc_auth_context *auth_context);
+
+/* Ownership of the secure_endpoint is transfered. */
+typedef void (*grpc_security_handshake_done_cb)(
+    grpc_exec_ctx *exec_ctx, void *user_data, grpc_security_status status,
+    grpc_endpoint *secure_endpoint, grpc_auth_context *auth_context);
+
+typedef struct {
+  void (*destroy)(grpc_security_connector *sc);
+  void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc,
+                     tsi_peer peer, grpc_security_peer_check_cb cb,
+                     void *user_data);
+} grpc_security_connector_vtable;
+
+typedef struct grpc_security_connector_handshake_list {
+  void *handshake;
+  struct grpc_security_connector_handshake_list *next;
+} grpc_security_connector_handshake_list;
+
+struct grpc_security_connector {
+  const grpc_security_connector_vtable *vtable;
+  gpr_refcount refcount;
+  const char *url_scheme;
+};
+
+/* 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 *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
+
+/* Check the peer. Callee takes ownership of the peer object.
+   The callback will include the resulting auth_context. */
+void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
+                                        grpc_security_connector *sc,
+                                        tsi_peer peer,
+                                        grpc_security_peer_check_cb cb,
+                                        void *user_data);
+
+/* Util to encapsulate the connector in a channel arg. */
+grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc);
+
+/* Util to get the connector from a channel arg. */
+grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg);
+
+/* Util to find the connector from channel args. */
+grpc_security_connector *grpc_find_security_connector_in_args(
+    const grpc_channel_args *args);
+
+/* --- channel_security_connector object. ---
+
+    A channel security connector object represents away to configure the
+    underlying transport security mechanism on the client side.  */
+
+typedef struct grpc_channel_security_connector grpc_channel_security_connector;
+
+typedef void (*grpc_security_call_host_check_cb)(grpc_exec_ctx *exec_ctx,
+                                                 void *user_data,
+                                                 grpc_security_status status);
+
+struct grpc_channel_security_connector {
+  grpc_security_connector base;
+  grpc_call_credentials *request_metadata_creds;
+  void (*check_call_host)(grpc_exec_ctx *exec_ctx,
+                          grpc_channel_security_connector *sc, const char *host,
+                          grpc_auth_context *auth_context,
+                          grpc_security_call_host_check_cb cb, void *user_data);
+  void (*do_handshake)(grpc_exec_ctx *exec_ctx,
+                       grpc_channel_security_connector *sc,
+                       grpc_endpoint *nonsecure_endpoint,
+                       grpc_security_handshake_done_cb cb, void *user_data);
+};
+
+/* Checks that the host that will be set for a call is acceptable. */
+void grpc_channel_security_connector_check_call_host(
+    grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
+    const char *host, grpc_auth_context *auth_context,
+    grpc_security_call_host_check_cb cb, void *user_data);
+
+/* Handshake. */
+void grpc_channel_security_connector_do_handshake(
+    grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector,
+    grpc_endpoint *nonsecure_endpoint, grpc_security_handshake_done_cb cb,
+    void *user_data);
+
+/* --- server_security_connector object. ---
+
+    A server security connector object represents away to configure the
+    underlying transport security mechanism on the server side.  */
+
+typedef struct grpc_server_security_connector grpc_server_security_connector;
+
+struct grpc_server_security_connector {
+  grpc_security_connector base;
+  gpr_mu mu;
+  grpc_security_connector_handshake_list *handshaking_handshakes;
+  const grpc_channel_args *channel_args;
+  void (*do_handshake)(grpc_exec_ctx *exec_ctx,
+                       grpc_server_security_connector *sc,
+                       grpc_tcp_server_acceptor *acceptor,
+                       grpc_endpoint *nonsecure_endpoint,
+                       grpc_security_handshake_done_cb cb, void *user_data);
+};
+
+void grpc_server_security_connector_do_handshake(
+    grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
+    grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
+    grpc_security_handshake_done_cb cb, void *user_data);
+
+void grpc_server_security_connector_shutdown(
+    grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector);
+
+/* --- Creation security connectors. --- */
+
+/* For TESTING ONLY!
+   Creates a fake connector that emulates real channel security.  */
+grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
+    grpc_call_credentials *request_metadata_creds);
+
+/* For TESTING ONLY!
+   Creates a fake connector that emulates real server security.  */
+grpc_server_security_connector *grpc_fake_server_security_connector_create(
+    void);
+
+/* Config for ssl clients. */
+typedef struct {
+  unsigned char *pem_private_key;
+  size_t pem_private_key_size;
+  unsigned char *pem_cert_chain;
+  size_t pem_cert_chain_size;
+  unsigned char *pem_root_certs;
+  size_t pem_root_certs_size;
+} grpc_ssl_config;
+
+/* Creates an SSL channel_security_connector.
+   - request_metadata_creds is the credentials object which metadata
+     will be sent with each request. This parameter can be NULL.
+   - config is the SSL config to be used for the SSL channel establishment.
+   - is_client should be 0 for a server or a non-0 value for a client.
+   - secure_peer_name is the secure peer name that should be checked in
+     grpc_channel_security_connector_check_peer. This parameter may be NULL in
+     which case the peer name will not be checked. Note that if this parameter
+     is not NULL, then, pem_root_certs should not be NULL either.
+   - sc is a pointer on the connector to be created.
+  This function returns GRPC_SECURITY_OK in case of success or a
+  specific error code otherwise.
+*/
+grpc_security_status grpc_ssl_channel_security_connector_create(
+    grpc_call_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);
+
+/* Exposed for TESTING ONLY!. */
+gpr_slice grpc_get_default_ssl_roots_for_testing(void);
+
+/* Config for ssl servers. */
+typedef struct {
+  unsigned char **pem_private_keys;
+  size_t *pem_private_keys_sizes;
+  unsigned char **pem_cert_chains;
+  size_t *pem_cert_chains_sizes;
+  size_t num_key_cert_pairs;
+  unsigned char *pem_root_certs;
+  size_t pem_root_certs_size;
+  int force_client_auth;
+} grpc_ssl_server_config;
+
+/* Creates an SSL server_security_connector.
+   - config is the SSL config to be used for the SSL channel establishment.
+   - sc is a pointer on the connector to be created.
+  This function returns GRPC_SECURITY_OK in case of success or a
+  specific error code otherwise.
+*/
+grpc_security_status grpc_ssl_server_security_connector_create(
+    const grpc_ssl_server_config *config, grpc_server_security_connector **sc);
+
+/* Util. */
+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);
+tsi_peer tsi_shallow_peer_from_ssl_auth_context(
+    const grpc_auth_context *auth_context);
+void tsi_shallow_peer_destruct(tsi_peer *peer);
+
+#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_H */
diff --git a/src/core/lib/security/security_context.c b/src/core/lib/security/security_context.c
new file mode 100644
index 0000000..0e66373
--- /dev/null
+++ b/src/core/lib/security/security_context.c
@@ -0,0 +1,347 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+
+#include "src/core/lib/security/security_context.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/call.h"
+
+#include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+/* --- grpc_call --- */
+
+grpc_call_error grpc_call_set_credentials(grpc_call *call,
+                                          grpc_call_credentials *creds) {
+  grpc_client_security_context *ctx = NULL;
+  GRPC_API_TRACE("grpc_call_set_credentials(call=%p, creds=%p)", 2,
+                 (call, creds));
+  if (!grpc_call_is_client(call)) {
+    gpr_log(GPR_ERROR, "Method is client-side only.");
+    return GRPC_CALL_ERROR_NOT_ON_SERVER;
+  }
+  ctx = (grpc_client_security_context *)grpc_call_context_get(
+      call, GRPC_CONTEXT_SECURITY);
+  if (ctx == NULL) {
+    ctx = grpc_client_security_context_create();
+    ctx->creds = grpc_call_credentials_ref(creds);
+    grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx,
+                          grpc_client_security_context_destroy);
+  } else {
+    grpc_call_credentials_unref(ctx->creds);
+    ctx->creds = grpc_call_credentials_ref(creds);
+  }
+  return GRPC_CALL_OK;
+}
+
+grpc_auth_context *grpc_call_auth_context(grpc_call *call) {
+  void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY);
+  GRPC_API_TRACE("grpc_call_auth_context(call=%p)", 1, (call));
+  if (sec_ctx == NULL) return NULL;
+  return grpc_call_is_client(call)
+             ? 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_API_TRACE("grpc_auth_context_release(context=%p)", 1, (context));
+  GRPC_AUTH_CONTEXT_UNREF(context, "grpc_auth_context_unref");
+}
+
+/* --- grpc_client_security_context --- */
+
+grpc_client_security_context *grpc_client_security_context_create(void) {
+  grpc_client_security_context *ctx =
+      gpr_malloc(sizeof(grpc_client_security_context));
+  memset(ctx, 0, sizeof(grpc_client_security_context));
+  return ctx;
+}
+
+void grpc_client_security_context_destroy(void *ctx) {
+  grpc_client_security_context *c = (grpc_client_security_context *)ctx;
+  grpc_call_credentials_unref(c->creds);
+  GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context");
+  gpr_free(ctx);
+}
+
+/* --- grpc_server_security_context --- */
+
+grpc_server_security_context *grpc_server_security_context_create(void) {
+  grpc_server_security_context *ctx =
+      gpr_malloc(sizeof(grpc_server_security_context));
+  memset(ctx, 0, sizeof(grpc_server_security_context));
+  return ctx;
+}
+
+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, "server_security_context");
+  gpr_free(ctx);
+}
+
+/* --- grpc_auth_context --- */
+
+static grpc_auth_property_iterator empty_iterator = {NULL, 0, NULL};
+
+grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained) {
+  grpc_auth_context *ctx = gpr_malloc(sizeof(grpc_auth_context));
+  memset(ctx, 0, sizeof(grpc_auth_context));
+  gpr_ref_init(&ctx->refcount, 1);
+  if (chained != NULL) {
+    ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained");
+    ctx->peer_identity_property_name =
+        ctx->chained->peer_identity_property_name;
+  }
+  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, "chained");
+    if (ctx->properties.array != NULL) {
+      for (i = 0; i < ctx->properties.count; i++) {
+        grpc_auth_property_reset(&ctx->properties.array[i]);
+      }
+      gpr_free(ctx->properties.array);
+    }
+    gpr_free(ctx);
+  }
+}
+
+const char *grpc_auth_context_peer_identity_property_name(
+    const grpc_auth_context *ctx) {
+  GRPC_API_TRACE("grpc_auth_context_peer_identity_property_name(ctx=%p)", 1,
+                 (ctx));
+  return ctx->peer_identity_property_name;
+}
+
+int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx,
+                                                      const char *name) {
+  grpc_auth_property_iterator it =
+      grpc_auth_context_find_properties_by_name(ctx, name);
+  const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it);
+  GRPC_API_TRACE(
+      "grpc_auth_context_set_peer_identity_property_name(ctx=%p, name=%s)", 2,
+      (ctx, name));
+  if (prop == NULL) {
+    gpr_log(GPR_ERROR, "Property name %s not found in auth context.",
+            name != NULL ? name : "NULL");
+    return 0;
+  }
+  ctx->peer_identity_property_name = prop->name;
+  return 1;
+}
+
+int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx) {
+  GRPC_API_TRACE("grpc_auth_context_peer_is_authenticated(ctx=%p)", 1, (ctx));
+  return ctx->peer_identity_property_name == NULL ? 0 : 1;
+}
+
+grpc_auth_property_iterator grpc_auth_context_property_iterator(
+    const grpc_auth_context *ctx) {
+  grpc_auth_property_iterator it = empty_iterator;
+  GRPC_API_TRACE("grpc_auth_context_property_iterator(ctx=%p)", 1, (ctx));
+  if (ctx == NULL) return it;
+  it.ctx = ctx;
+  return it;
+}
+
+const grpc_auth_property *grpc_auth_property_iterator_next(
+    grpc_auth_property_iterator *it) {
+  GRPC_API_TRACE("grpc_auth_property_iterator_next(it=%p)", 1, (it));
+  if (it == NULL || it->ctx == NULL) return NULL;
+  while (it->index == it->ctx->properties.count) {
+    if (it->ctx->chained == NULL) return NULL;
+    it->ctx = it->ctx->chained;
+    it->index = 0;
+  }
+  if (it->name == NULL) {
+    return &it->ctx->properties.array[it->index++];
+  } else {
+    while (it->index < it->ctx->properties.count) {
+      const grpc_auth_property *prop = &it->ctx->properties.array[it->index++];
+      GPR_ASSERT(prop->name != NULL);
+      if (strcmp(it->name, prop->name) == 0) {
+        return prop;
+      }
+    }
+    /* We could not find the name, try another round. */
+    return grpc_auth_property_iterator_next(it);
+  }
+}
+
+grpc_auth_property_iterator grpc_auth_context_find_properties_by_name(
+    const grpc_auth_context *ctx, const char *name) {
+  grpc_auth_property_iterator it = empty_iterator;
+  GRPC_API_TRACE("grpc_auth_context_find_properties_by_name(ctx=%p, name=%s)",
+                 2, (ctx, name));
+  if (ctx == NULL || name == NULL) return empty_iterator;
+  it.ctx = ctx;
+  it.name = name;
+  return it;
+}
+
+grpc_auth_property_iterator grpc_auth_context_peer_identity(
+    const grpc_auth_context *ctx) {
+  GRPC_API_TRACE("grpc_auth_context_peer_identity(ctx=%p)", 1, (ctx));
+  if (ctx == NULL) return empty_iterator;
+  return grpc_auth_context_find_properties_by_name(
+      ctx, ctx->peer_identity_property_name);
+}
+
+static void ensure_auth_context_capacity(grpc_auth_context *ctx) {
+  if (ctx->properties.count == ctx->properties.capacity) {
+    ctx->properties.capacity =
+        GPR_MAX(ctx->properties.capacity + 8, ctx->properties.capacity * 2);
+    ctx->properties.array =
+        gpr_realloc(ctx->properties.array,
+                    ctx->properties.capacity * sizeof(grpc_auth_property));
+  }
+}
+
+void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name,
+                                    const char *value, size_t value_length) {
+  grpc_auth_property *prop;
+  GRPC_API_TRACE(
+      "grpc_auth_context_add_property(ctx=%p, name=%s, value=%*.*s, "
+      "value_length=%lu)",
+      6, (ctx, name, (int)value_length, (int)value_length, value,
+          (unsigned long)value_length));
+  ensure_auth_context_capacity(ctx);
+  prop = &ctx->properties.array[ctx->properties.count++];
+  prop->name = gpr_strdup(name);
+  prop->value = gpr_malloc(value_length + 1);
+  memcpy(prop->value, value, value_length);
+  prop->value[value_length] = '\0';
+  prop->value_length = value_length;
+}
+
+void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx,
+                                            const char *name,
+                                            const char *value) {
+  grpc_auth_property *prop;
+  GRPC_API_TRACE(
+      "grpc_auth_context_add_cstring_property(ctx=%p, name=%s, value=%s)", 3,
+      (ctx, name, value));
+  ensure_auth_context_capacity(ctx);
+  prop = &ctx->properties.array[ctx->properties.count++];
+  prop->name = gpr_strdup(name);
+  prop->value = gpr_strdup(value);
+  prop->value_length = strlen(value);
+}
+
+void grpc_auth_property_reset(grpc_auth_property *property) {
+  gpr_free(property->name);
+  gpr_free(property->value);
+  memset(property, 0, sizeof(grpc_auth_property));
+}
+
+static void auth_context_pointer_arg_destroy(void *p) {
+  GRPC_AUTH_CONTEXT_UNREF(p, "auth_context_pointer_arg");
+}
+
+static void *auth_context_pointer_arg_copy(void *p) {
+  return GRPC_AUTH_CONTEXT_REF(p, "auth_context_pointer_arg");
+}
+
+static int auth_context_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); }
+
+static const grpc_arg_pointer_vtable auth_context_pointer_vtable = {
+    auth_context_pointer_arg_copy, auth_context_pointer_arg_destroy,
+    auth_context_pointer_cmp};
+
+grpc_arg grpc_auth_context_to_arg(grpc_auth_context *p) {
+  grpc_arg arg;
+  memset(&arg, 0, sizeof(grpc_arg));
+  arg.type = GRPC_ARG_POINTER;
+  arg.key = GRPC_AUTH_CONTEXT_ARG;
+  arg.value.pointer.p = p;
+  arg.value.pointer.vtable = &auth_context_pointer_vtable;
+  return arg;
+}
+
+grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg) {
+  if (strcmp(arg->key, GRPC_AUTH_CONTEXT_ARG) != 0) return NULL;
+  if (arg->type != GRPC_ARG_POINTER) {
+    gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
+            GRPC_AUTH_CONTEXT_ARG);
+    return NULL;
+  }
+  return arg->value.pointer.p;
+}
+
+grpc_auth_context *grpc_find_auth_context_in_args(
+    const grpc_channel_args *args) {
+  size_t i;
+  if (args == NULL) return NULL;
+  for (i = 0; i < args->num_args; i++) {
+    grpc_auth_context *p = grpc_auth_context_from_arg(&args->args[i]);
+    if (p != NULL) return p;
+  }
+  return NULL;
+}
diff --git a/src/core/lib/security/security_context.h b/src/core/lib/security/security_context.h
new file mode 100644
index 0000000..e9e4e50
--- /dev/null
+++ b/src/core/lib/security/security_context.h
@@ -0,0 +1,114 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONTEXT_H
+#define GRPC_CORE_LIB_SECURITY_SECURITY_CONTEXT_H
+
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/security/credentials.h"
+
+/* --- grpc_auth_context ---
+
+   High level authentication context object. Can optionally be chained. */
+
+/* Property names are always NULL terminated. */
+
+typedef struct {
+  grpc_auth_property *array;
+  size_t count;
+  size_t capacity;
+} grpc_auth_property_array;
+
+struct grpc_auth_context {
+  struct grpc_auth_context *chained;
+  grpc_auth_property_array properties;
+  gpr_refcount refcount;
+  const char *peer_identity_property_name;
+  grpc_pollset *pollset;
+};
+
+/* Creation. */
+grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained);
+
+/* Refcounting. */
+#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
+
+void grpc_auth_property_reset(grpc_auth_property *property);
+
+/* --- grpc_client_security_context ---
+
+   Internal client-side security context. */
+
+typedef struct {
+  grpc_call_credentials *creds;
+  grpc_auth_context *auth_context;
+} grpc_client_security_context;
+
+grpc_client_security_context *grpc_client_security_context_create(void);
+void grpc_client_security_context_destroy(void *ctx);
+
+/* --- grpc_server_security_context ---
+
+   Internal server-side security context. */
+
+typedef struct {
+  grpc_auth_context *auth_context;
+} grpc_server_security_context;
+
+grpc_server_security_context *grpc_server_security_context_create(void);
+void grpc_server_security_context_destroy(void *ctx);
+
+/* --- Channel args for auth context --- */
+#define GRPC_AUTH_CONTEXT_ARG "grpc.auth_context"
+
+grpc_arg grpc_auth_context_to_arg(grpc_auth_context *c);
+grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg);
+grpc_auth_context *grpc_find_auth_context_in_args(
+    const grpc_channel_args *args);
+
+#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONTEXT_H */
diff --git a/src/core/lib/security/server_auth_filter.c b/src/core/lib/security/server_auth_filter.c
new file mode 100644
index 0000000..158cde0
--- /dev/null
+++ b/src/core/lib/security/server_auth_filter.c
@@ -0,0 +1,264 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+
+#include "src/core/lib/security/auth_filters.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/security/security_context.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+typedef struct call_data {
+  grpc_metadata_batch *recv_initial_metadata;
+  /* Closure to call when finished with the auth_on_recv hook. */
+  grpc_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_closure auth_on_recv;
+  grpc_transport_stream_op transport_op;
+  grpc_metadata_array md;
+  const grpc_metadata *consumed_md;
+  size_t num_consumed_md;
+  grpc_auth_context *auth_context;
+} call_data;
+
+typedef struct channel_data {
+  grpc_auth_context *auth_context;
+  grpc_server_credentials *creds;
+} channel_data;
+
+static grpc_metadata_array metadata_batch_to_md_array(
+    const grpc_metadata_batch *batch) {
+  grpc_linked_mdelem *l;
+  grpc_metadata_array result;
+  grpc_metadata_array_init(&result);
+  for (l = batch->list.head; l != NULL; l = l->next) {
+    grpc_metadata *usr_md = NULL;
+    grpc_mdelem *md = l->md;
+    grpc_mdstr *key = md->key;
+    grpc_mdstr *value = md->value;
+    if (result.count == result.capacity) {
+      result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2);
+      result.metadata =
+          gpr_realloc(result.metadata, result.capacity * sizeof(grpc_metadata));
+    }
+    usr_md = &result.metadata[result.count++];
+    usr_md->key = grpc_mdstr_as_c_string(key);
+    usr_md->value = grpc_mdstr_as_c_string(value);
+    usr_md->value_length = GPR_SLICE_LENGTH(value->slice);
+  }
+  return result;
+}
+
+static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) {
+  grpc_call_element *elem = user_data;
+  call_data *calld = elem->call_data;
+  size_t i;
+  for (i = 0; i < calld->num_consumed_md; i++) {
+    const grpc_metadata *consumed_md = &calld->consumed_md[i];
+    /* Maybe we could do a pointer comparison but we do not have any guarantee
+       that the metadata processor used the same pointers for consumed_md in the
+       callback. */
+    if (GPR_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) ||
+        GPR_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) {
+      continue;
+    }
+    if (memcmp(GPR_SLICE_START_PTR(md->key->slice), consumed_md->key,
+               GPR_SLICE_LENGTH(md->key->slice)) == 0 &&
+        memcmp(GPR_SLICE_START_PTR(md->value->slice), consumed_md->value,
+               GPR_SLICE_LENGTH(md->value->slice)) == 0) {
+      return NULL; /* Delete. */
+    }
+  }
+  return md;
+}
+
+/* called from application code */
+static void on_md_processing_done(
+    void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md,
+    const grpc_metadata *response_md, size_t num_response_md,
+    grpc_status_code status, const char *error_details) {
+  grpc_call_element *elem = user_data;
+  call_data *calld = elem->call_data;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  /* TODO(jboeuf): Implement support for response_md. */
+  if (response_md != NULL && num_response_md > 0) {
+    gpr_log(GPR_INFO,
+            "response_md in auth metadata processing not supported for now. "
+            "Ignoring...");
+  }
+
+  if (status == GRPC_STATUS_OK) {
+    calld->consumed_md = consumed_md;
+    calld->num_consumed_md = num_consumed_md;
+    grpc_metadata_batch_filter(calld->recv_initial_metadata, remove_consumed_md,
+                               elem);
+    grpc_metadata_array_destroy(&calld->md);
+    calld->on_done_recv->cb(&exec_ctx, calld->on_done_recv->cb_arg, 1);
+  } else {
+    gpr_slice message;
+    grpc_transport_stream_op close_op;
+    memset(&close_op, 0, sizeof(close_op));
+    grpc_metadata_array_destroy(&calld->md);
+    error_details = error_details != NULL
+                        ? error_details
+                        : "Authentication metadata processing failed.";
+    message = gpr_slice_from_copied_string(error_details);
+    calld->transport_op.send_initial_metadata = NULL;
+    if (calld->transport_op.send_message != NULL) {
+      grpc_byte_stream_destroy(&exec_ctx, calld->transport_op.send_message);
+      calld->transport_op.send_message = NULL;
+    }
+    calld->transport_op.send_trailing_metadata = NULL;
+    grpc_transport_stream_op_add_close(&close_op, status, &message);
+    grpc_call_next_op(&exec_ctx, elem, &close_op);
+    calld->on_done_recv->cb(&exec_ctx, calld->on_done_recv->cb_arg, 0);
+  }
+
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void auth_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
+                         bool success) {
+  grpc_call_element *elem = user_data;
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  if (success) {
+    if (chand->creds->processor.process != NULL) {
+      calld->md = metadata_batch_to_md_array(calld->recv_initial_metadata);
+      chand->creds->processor.process(
+          chand->creds->processor.state, calld->auth_context,
+          calld->md.metadata, calld->md.count, on_md_processing_done, elem);
+      return;
+    }
+  }
+  calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success);
+}
+
+static void set_recv_ops_md_callbacks(grpc_call_element *elem,
+                                      grpc_transport_stream_op *op) {
+  call_data *calld = elem->call_data;
+
+  if (op->recv_initial_metadata != NULL) {
+    /* substitute our callback for the higher callback */
+    calld->recv_initial_metadata = op->recv_initial_metadata;
+    calld->on_done_recv = op->recv_initial_metadata_ready;
+    op->recv_initial_metadata_ready = &calld->auth_on_recv;
+    calld->transport_op = *op;
+  }
+}
+
+/* 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 auth_start_transport_op(grpc_exec_ctx *exec_ctx,
+                                    grpc_call_element *elem,
+                                    grpc_transport_stream_op *op) {
+  set_recv_ops_md_callbacks(elem, op);
+  grpc_call_next_op(exec_ctx, elem, op);
+}
+
+/* Constructor for call_data */
+static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                           grpc_call_element_args *args) {
+  /* grab pointers to our data from the call element */
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  grpc_server_security_context *server_ctx = NULL;
+
+  /* initialize members */
+  memset(calld, 0, sizeof(*calld));
+  grpc_closure_init(&calld->auth_on_recv, auth_on_recv, elem);
+
+  if (args->context[GRPC_CONTEXT_SECURITY].value != NULL) {
+    args->context[GRPC_CONTEXT_SECURITY].destroy(
+        args->context[GRPC_CONTEXT_SECURITY].value);
+  }
+
+  server_ctx = grpc_server_security_context_create();
+  server_ctx->auth_context = grpc_auth_context_create(chand->auth_context);
+  calld->auth_context = server_ctx->auth_context;
+
+  args->context[GRPC_CONTEXT_SECURITY].value = server_ctx;
+  args->context[GRPC_CONTEXT_SECURITY].destroy =
+      grpc_server_security_context_destroy;
+}
+
+static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                        grpc_pollset *pollset) {}
+
+/* Destructor for call_data */
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_call_element *elem) {}
+
+/* Constructor for channel_data */
+static void init_channel_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_channel_element *elem,
+                              grpc_channel_element_args *args) {
+  grpc_auth_context *auth_context =
+      grpc_find_auth_context_in_args(args->channel_args);
+  grpc_server_credentials *creds =
+      grpc_find_server_credentials_in_args(args->channel_args);
+  /* grab pointers to our data from the channel element */
+  channel_data *chand = elem->channel_data;
+
+  GPR_ASSERT(!args->is_last);
+  GPR_ASSERT(auth_context != NULL);
+  GPR_ASSERT(creds != NULL);
+
+  /* initialize members */
+  chand->auth_context =
+      GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter");
+  chand->creds = grpc_server_credentials_ref(creds);
+}
+
+/* Destructor for channel data */
+static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem) {
+  /* grab pointers to our data from the channel element */
+  channel_data *chand = elem->channel_data;
+  GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter");
+  grpc_server_credentials_unref(chand->creds);
+}
+
+const grpc_channel_filter grpc_server_auth_filter = {
+    auth_start_transport_op, grpc_channel_next_op, sizeof(call_data),
+    init_call_elem,          set_pollset,          destroy_call_elem,
+    sizeof(channel_data),    init_channel_elem,    destroy_channel_elem,
+    grpc_call_next_get_peer, "server-auth"};
diff --git a/src/core/lib/statistics/census_init.c b/src/core/lib/statistics/census_init.c
new file mode 100644
index 0000000..bbecd62
--- /dev/null
+++ b/src/core/lib/statistics/census_init.c
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/statistics/census_interface.h"
+
+#include <grpc/support/log.h>
+#include "src/core/lib/statistics/census_rpc_stats.h"
+#include "src/core/lib/statistics/census_tracing.h"
+
+void census_init(void) {
+  census_tracing_init();
+  census_stats_store_init();
+}
+
+void census_shutdown(void) {
+  census_stats_store_shutdown();
+  census_tracing_shutdown();
+}
diff --git a/src/core/lib/statistics/census_interface.h b/src/core/lib/statistics/census_interface.h
new file mode 100644
index 0000000..b3b3439
--- /dev/null
+++ b/src/core/lib/statistics/census_interface.h
@@ -0,0 +1,76 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_STATISTICS_CENSUS_INTERFACE_H
+#define GRPC_CORE_LIB_STATISTICS_CENSUS_INTERFACE_H
+
+#include <grpc/support/port_platform.h>
+
+/* Maximum length of an individual census trace annotation. */
+#define CENSUS_MAX_ANNOTATION_LENGTH 200
+
+/* Structure of a census op id. Define as structure because 64bit integer is not
+   available on every platform for C89. */
+typedef struct census_op_id {
+  uint32_t upper;
+  uint32_t lower;
+} census_op_id;
+
+typedef struct census_rpc_stats census_rpc_stats;
+
+/* Initializes Census library. No-op if Census is already initialized. */
+void census_init(void);
+
+/* Shutdown Census Library. */
+void census_shutdown(void);
+
+/* Annotates grpc method name on a census_op_id. The method name has the format
+   of <full quantified rpc service name>/<rpc function name>. Returns 0 iff
+   op_id and method_name are all valid. op_id is valid after its creation and
+   before calling census_tracing_end_op().
+
+   TODO(hongyu): Figure out valid characters set for service name and command
+   name and document requirements here.*/
+int census_add_method_tag(census_op_id op_id, const char *method_name);
+
+/* Annotates tracing information to a specific op_id.
+   Up to CENSUS_MAX_ANNOTATION_LENGTH bytes are recorded. */
+void census_tracing_print(census_op_id op_id, const char *annotation);
+
+/* Starts tracing for an RPC. Returns a locally unique census_op_id */
+census_op_id census_tracing_start_op(void);
+
+/* Ends tracing. Calling this function will invalidate the input op_id. */
+void census_tracing_end_op(census_op_id op_id);
+
+#endif /* GRPC_CORE_LIB_STATISTICS_CENSUS_INTERFACE_H */
diff --git a/src/core/lib/statistics/census_log.c b/src/core/lib/statistics/census_log.c
new file mode 100644
index 0000000..1fb942a
--- /dev/null
+++ b/src/core/lib/statistics/census_log.c
@@ -0,0 +1,603 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Available log space is divided up in blocks of
+   CENSUS_LOG_2_MAX_RECORD_SIZE bytes. A block can be in one of the
+   following three data structures:
+   - Free blocks (free_block_list)
+   - Blocks with unread data (dirty_block_list)
+   - Blocks currently attached to cores (core_local_blocks[])
+
+   census_log_start_write() moves a block from core_local_blocks[] to the
+   end of dirty_block_list when block:
+   - is out-of-space OR
+   - has an incomplete record (an incomplete record occurs when a thread calls
+     census_log_start_write() and is context-switched before calling
+     census_log_end_write()
+   So, blocks in dirty_block_list are ordered, from oldest to newest, by time
+   when block is detached from the core.
+
+   census_log_read_next() first iterates over dirty_block_list and then
+   core_local_blocks[]. It moves completely read blocks from dirty_block_list
+   to free_block_list. Blocks in core_local_blocks[] are not freed, even when
+   completely read.
+
+   If log is configured to discard old records and free_block_list is empty,
+   census_log_start_write() iterates over dirty_block_list to allocate a
+   new block. It moves the oldest available block (no pending read/write) to
+   core_local_blocks[].
+
+   core_local_block_struct is used to implement a map from core id to the block
+   associated with that core. This mapping is advisory. It is possible that the
+   block returned by this mapping is no longer associated with that core. This
+   mapping is updated, lazily, by census_log_start_write().
+
+   Locking in block struct:
+
+   Exclusive g_log.lock must be held before calling any functions operatong on
+   block structs except census_log_start_write() and
+   census_log_end_write().
+
+   Writes to a block are serialized via writer_lock.
+   census_log_start_write() acquires this lock and
+   census_log_end_write() releases it. On failure to acquire the lock,
+   writer allocates a new block for the current core and updates
+   core_local_block accordingly.
+
+   Simultaneous read and write access is allowed. Reader can safely read up to
+   committed bytes (bytes_committed).
+
+   reader_lock protects the block, currently being read, from getting recycled.
+   start_read() acquires reader_lock and end_read() releases the lock.
+
+   Read/write access to a block is disabled via try_disable_access(). It returns
+   with both writer_lock and reader_lock held. These locks are subsequently
+   released by enable_access() to enable access to the block.
+
+   A note on naming: Most function/struct names are prepended by cl_
+   (shorthand for census_log). Further, functions that manipulate structures
+   include the name of the structure, which will be passed as the first
+   argument. E.g. cl_block_initialize() will initialize a cl_block.
+*/
+#include "src/core/lib/statistics/census_log.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/cpu.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/useful.h>
+#include <string.h>
+
+/* End of platform specific code */
+
+typedef struct census_log_block_list_struct {
+  struct census_log_block_list_struct *next;
+  struct census_log_block_list_struct *prev;
+  struct census_log_block *block;
+} cl_block_list_struct;
+
+typedef struct census_log_block {
+  /* Pointer to underlying buffer */
+  char *buffer;
+  gpr_atm writer_lock;
+  gpr_atm reader_lock;
+  /* Keeps completely written bytes. Declared atomic because accessed
+     simultaneously by reader and writer. */
+  gpr_atm bytes_committed;
+  /* Bytes already read */
+  int32_t bytes_read;
+  /* Links for list */
+  cl_block_list_struct link;
+/* We want this structure to be cacheline aligned. We assume the following
+   sizes for the various parts on 32/64bit systems:
+   type                 32b size    64b size
+   char*                   4           8
+   3x gpr_atm             12          24
+   int32_t               4           8 (assumes padding)
+   cl_block_list_struct   12          24
+   TOTAL                  32          64
+
+   Depending on the size of our cacheline and the architecture, we
+   selectively add char buffering to this structure. The size is checked
+   via assert in census_log_initialize(). */
+#if defined(GPR_ARCH_64)
+#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 64)
+#else
+#if defined(GPR_ARCH_32)
+#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 32)
+#else
+#error "Unknown architecture"
+#endif
+#endif
+#if CL_BLOCK_PAD_SIZE > 0
+  char padding[CL_BLOCK_PAD_SIZE];
+#endif
+} cl_block;
+
+/* A list of cl_blocks, doubly-linked through cl_block::link. */
+typedef struct census_log_block_list {
+  int32_t count;           /* Number of items in list. */
+  cl_block_list_struct ht; /* head/tail of linked list. */
+} cl_block_list;
+
+/* Cacheline aligned block pointers to avoid false sharing. Block pointer must
+   be initialized via set_block(), before calling other functions */
+typedef struct census_log_core_local_block {
+  gpr_atm block;
+/* Ensure cachline alignment: we assume sizeof(gpr_atm) == 4 or 8 */
+#if defined(GPR_ARCH_64)
+#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 8)
+#else
+#if defined(GPR_ARCH_32)
+#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 4)
+#else
+#error "Unknown architecture"
+#endif
+#endif
+#if CL_CORE_LOCAL_BLOCK_PAD_SIZE > 0
+  char padding[CL_CORE_LOCAL_BLOCK_PAD_SIZE];
+#endif
+} cl_core_local_block;
+
+struct census_log {
+  int discard_old_records;
+  /* Number of cores (aka hardware-contexts) */
+  unsigned num_cores;
+  /* number of CENSUS_LOG_2_MAX_RECORD_SIZE blocks in log */
+  int32_t num_blocks;
+  cl_block *blocks;                       /* Block metadata. */
+  cl_core_local_block *core_local_blocks; /* Keeps core to block mappings. */
+  gpr_mu lock;
+  int initialized; /* has log been initialized? */
+  /* Keeps the state of the reader iterator. A value of 0 indicates that
+     iterator has reached the end. census_log_init_reader() resets the
+     value to num_core to restart iteration. */
+  uint32_t read_iterator_state;
+  /* Points to the block being read. If non-NULL, the block is locked for
+     reading (block_being_read_->reader_lock is held). */
+  cl_block *block_being_read;
+  /* A non-zero value indicates that log is full. */
+  gpr_atm is_full;
+  char *buffer;
+  cl_block_list free_block_list;
+  cl_block_list dirty_block_list;
+  gpr_atm out_of_space_count;
+};
+
+/* Single internal log */
+static struct census_log g_log;
+
+/* Functions that operate on an atomic memory location used as a lock */
+
+/* Returns non-zero if lock is acquired */
+static int cl_try_lock(gpr_atm *lock) { return gpr_atm_acq_cas(lock, 0, 1); }
+
+static void cl_unlock(gpr_atm *lock) { gpr_atm_rel_store(lock, 0); }
+
+/* Functions that operate on cl_core_local_block's */
+
+static void cl_core_local_block_set_block(cl_core_local_block *clb,
+                                          cl_block *block) {
+  gpr_atm_rel_store(&clb->block, (gpr_atm)block);
+}
+
+static cl_block *cl_core_local_block_get_block(cl_core_local_block *clb) {
+  return (cl_block *)gpr_atm_acq_load(&clb->block);
+}
+
+/* Functions that operate on cl_block_list_struct's */
+
+static void cl_block_list_struct_initialize(cl_block_list_struct *bls,
+                                            cl_block *block) {
+  bls->next = bls->prev = bls;
+  bls->block = block;
+}
+
+/* Functions that operate on cl_block_list's */
+
+static void cl_block_list_initialize(cl_block_list *list) {
+  list->count = 0;
+  cl_block_list_struct_initialize(&list->ht, NULL);
+}
+
+/* Returns head of *this, or NULL if empty. */
+static cl_block *cl_block_list_head(cl_block_list *list) {
+  return list->ht.next->block;
+}
+
+/* Insert element *e after *pos. */
+static void cl_block_list_insert(cl_block_list *list, cl_block_list_struct *pos,
+                                 cl_block_list_struct *e) {
+  list->count++;
+  e->next = pos->next;
+  e->prev = pos;
+  e->next->prev = e;
+  e->prev->next = e;
+}
+
+/* Insert block at the head of the list */
+static void cl_block_list_insert_at_head(cl_block_list *list, cl_block *block) {
+  cl_block_list_insert(list, &list->ht, &block->link);
+}
+
+/* Insert block at the tail of the list */
+static void cl_block_list_insert_at_tail(cl_block_list *list, cl_block *block) {
+  cl_block_list_insert(list, list->ht.prev, &block->link);
+}
+
+/* Removes block *b. Requires *b be in the list. */
+static void cl_block_list_remove(cl_block_list *list, cl_block *b) {
+  list->count--;
+  b->link.next->prev = b->link.prev;
+  b->link.prev->next = b->link.next;
+}
+
+/* Functions that operate on cl_block's */
+
+static void cl_block_initialize(cl_block *block, char *buffer) {
+  block->buffer = buffer;
+  gpr_atm_rel_store(&block->writer_lock, 0);
+  gpr_atm_rel_store(&block->reader_lock, 0);
+  gpr_atm_rel_store(&block->bytes_committed, 0);
+  block->bytes_read = 0;
+  cl_block_list_struct_initialize(&block->link, block);
+}
+
+/* Guards against exposing partially written buffer to the reader. */
+static void cl_block_set_bytes_committed(cl_block *block,
+                                         int32_t bytes_committed) {
+  gpr_atm_rel_store(&block->bytes_committed, bytes_committed);
+}
+
+static int32_t cl_block_get_bytes_committed(cl_block *block) {
+  return gpr_atm_acq_load(&block->bytes_committed);
+}
+
+/* Tries to disable future read/write access to this block. Succeeds if:
+   - no in-progress write AND
+   - no in-progress read AND
+   - 'discard_data' set to true OR no unread data
+   On success, clears the block state and returns with writer_lock_ and
+   reader_lock_ held. These locks are released by a subsequent
+   cl_block_access_enable() call. */
+static int cl_block_try_disable_access(cl_block *block, int discard_data) {
+  if (!cl_try_lock(&block->writer_lock)) {
+    return 0;
+  }
+  if (!cl_try_lock(&block->reader_lock)) {
+    cl_unlock(&block->writer_lock);
+    return 0;
+  }
+  if (!discard_data &&
+      (block->bytes_read != cl_block_get_bytes_committed(block))) {
+    cl_unlock(&block->reader_lock);
+    cl_unlock(&block->writer_lock);
+    return 0;
+  }
+  cl_block_set_bytes_committed(block, 0);
+  block->bytes_read = 0;
+  return 1;
+}
+
+static void cl_block_enable_access(cl_block *block) {
+  cl_unlock(&block->reader_lock);
+  cl_unlock(&block->writer_lock);
+}
+
+/* Returns with writer_lock held. */
+static void *cl_block_start_write(cl_block *block, size_t size) {
+  int32_t bytes_committed;
+  if (!cl_try_lock(&block->writer_lock)) {
+    return NULL;
+  }
+  bytes_committed = cl_block_get_bytes_committed(block);
+  if (bytes_committed + size > CENSUS_LOG_MAX_RECORD_SIZE) {
+    cl_unlock(&block->writer_lock);
+    return NULL;
+  }
+  return block->buffer + bytes_committed;
+}
+
+/* Releases writer_lock and increments committed bytes by 'bytes_written'.
+  'bytes_written' must be <= 'size' specified in the corresponding
+  StartWrite() call. This function is thread-safe. */
+static void cl_block_end_write(cl_block *block, size_t bytes_written) {
+  cl_block_set_bytes_committed(
+      block, cl_block_get_bytes_committed(block) + bytes_written);
+  cl_unlock(&block->writer_lock);
+}
+
+/* Returns a pointer to the first unread byte in buffer. The number of bytes
+   available are returned in 'bytes_available'. Acquires reader lock that is
+   released by a subsequent cl_block_end_read() call. Returns NULL if:
+   - read in progress
+   - no data available */
+static void *cl_block_start_read(cl_block *block, size_t *bytes_available) {
+  void *record;
+  if (!cl_try_lock(&block->reader_lock)) {
+    return NULL;
+  }
+  /* bytes_committed may change from under us. Use bytes_available to update
+     bytes_read below. */
+  *bytes_available = cl_block_get_bytes_committed(block) - block->bytes_read;
+  if (*bytes_available == 0) {
+    cl_unlock(&block->reader_lock);
+    return NULL;
+  }
+  record = block->buffer + block->bytes_read;
+  block->bytes_read += *bytes_available;
+  return record;
+}
+
+static void cl_block_end_read(cl_block *block) {
+  cl_unlock(&block->reader_lock);
+}
+
+/* Internal functions operating on g_log */
+
+/* Allocates a new free block (or recycles an available dirty block if log is
+   configured to discard old records). Returns NULL if out-of-space. */
+static cl_block *cl_allocate_block(void) {
+  cl_block *block = cl_block_list_head(&g_log.free_block_list);
+  if (block != NULL) {
+    cl_block_list_remove(&g_log.free_block_list, block);
+    return block;
+  }
+  if (!g_log.discard_old_records) {
+    /* No free block and log is configured to keep old records. */
+    return NULL;
+  }
+  /* Recycle dirty block. Start from the oldest. */
+  for (block = cl_block_list_head(&g_log.dirty_block_list); block != NULL;
+       block = block->link.next->block) {
+    if (cl_block_try_disable_access(block, 1 /* discard data */)) {
+      cl_block_list_remove(&g_log.dirty_block_list, block);
+      return block;
+    }
+  }
+  return NULL;
+}
+
+/* Allocates a new block and updates core id => block mapping. 'old_block'
+   points to the block that the caller thinks is attached to
+   'core_id'. 'old_block' may be NULL. Returns non-zero if:
+   - allocated a new block OR
+   - 'core_id' => 'old_block' mapping changed (another thread allocated a
+     block before lock was acquired). */
+static int cl_allocate_core_local_block(int32_t core_id, cl_block *old_block) {
+  /* Now that we have the lock, check if core-local mapping has changed. */
+  cl_core_local_block *core_local_block = &g_log.core_local_blocks[core_id];
+  cl_block *block = cl_core_local_block_get_block(core_local_block);
+  if ((block != NULL) && (block != old_block)) {
+    return 1;
+  }
+  if (block != NULL) {
+    cl_core_local_block_set_block(core_local_block, NULL);
+    cl_block_list_insert_at_tail(&g_log.dirty_block_list, block);
+  }
+  block = cl_allocate_block();
+  if (block == NULL) {
+    gpr_atm_rel_store(&g_log.is_full, 1);
+    return 0;
+  }
+  cl_core_local_block_set_block(core_local_block, block);
+  cl_block_enable_access(block);
+  return 1;
+}
+
+static cl_block *cl_get_block(void *record) {
+  uintptr_t p = (uintptr_t)((char *)record - g_log.buffer);
+  uintptr_t index = p >> CENSUS_LOG_2_MAX_RECORD_SIZE;
+  return &g_log.blocks[index];
+}
+
+/* Gets the next block to read and tries to free 'prev' block (if not NULL).
+   Returns NULL if reached the end. */
+static cl_block *cl_next_block_to_read(cl_block *prev) {
+  cl_block *block = NULL;
+  if (g_log.read_iterator_state == g_log.num_cores) {
+    /* We are traversing dirty list; find the next dirty block. */
+    if (prev != NULL) {
+      /* Try to free the previous block if there is no unread data. This block
+         may have unread data if previously incomplete record completed between
+         read_next() calls. */
+      block = prev->link.next->block;
+      if (cl_block_try_disable_access(prev, 0 /* do not discard data */)) {
+        cl_block_list_remove(&g_log.dirty_block_list, prev);
+        cl_block_list_insert_at_head(&g_log.free_block_list, prev);
+        gpr_atm_rel_store(&g_log.is_full, 0);
+      }
+    } else {
+      block = cl_block_list_head(&g_log.dirty_block_list);
+    }
+    if (block != NULL) {
+      return block;
+    }
+    /* We are done with the dirty list; moving on to core-local blocks. */
+  }
+  while (g_log.read_iterator_state > 0) {
+    g_log.read_iterator_state--;
+    block = cl_core_local_block_get_block(
+        &g_log.core_local_blocks[g_log.read_iterator_state]);
+    if (block != NULL) {
+      return block;
+    }
+  }
+  return NULL;
+}
+
+/* External functions: primary stats_log interface */
+void census_log_initialize(size_t size_in_mb, int discard_old_records) {
+  int32_t ix;
+  /* Check cacheline alignment. */
+  GPR_ASSERT(sizeof(cl_block) % GPR_CACHELINE_SIZE == 0);
+  GPR_ASSERT(sizeof(cl_core_local_block) % GPR_CACHELINE_SIZE == 0);
+  GPR_ASSERT(!g_log.initialized);
+  g_log.discard_old_records = discard_old_records;
+  g_log.num_cores = gpr_cpu_num_cores();
+  /* Ensure at least as many blocks as there are cores. */
+  g_log.num_blocks = GPR_MAX(
+      g_log.num_cores, (size_in_mb << 20) >> CENSUS_LOG_2_MAX_RECORD_SIZE);
+  gpr_mu_init(&g_log.lock);
+  g_log.read_iterator_state = 0;
+  g_log.block_being_read = NULL;
+  gpr_atm_rel_store(&g_log.is_full, 0);
+  g_log.core_local_blocks = (cl_core_local_block *)gpr_malloc_aligned(
+      g_log.num_cores * sizeof(cl_core_local_block), GPR_CACHELINE_SIZE_LOG);
+  memset(g_log.core_local_blocks, 0,
+         g_log.num_cores * sizeof(cl_core_local_block));
+  g_log.blocks = (cl_block *)gpr_malloc_aligned(
+      g_log.num_blocks * sizeof(cl_block), GPR_CACHELINE_SIZE_LOG);
+  memset(g_log.blocks, 0, g_log.num_blocks * sizeof(cl_block));
+  g_log.buffer = gpr_malloc(g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE);
+  memset(g_log.buffer, 0, g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE);
+  cl_block_list_initialize(&g_log.free_block_list);
+  cl_block_list_initialize(&g_log.dirty_block_list);
+  for (ix = 0; ix < g_log.num_blocks; ++ix) {
+    cl_block *block = g_log.blocks + ix;
+    cl_block_initialize(block,
+                        g_log.buffer + (CENSUS_LOG_MAX_RECORD_SIZE * ix));
+    cl_block_try_disable_access(block, 1 /* discard data */);
+    cl_block_list_insert_at_tail(&g_log.free_block_list, block);
+  }
+  gpr_atm_rel_store(&g_log.out_of_space_count, 0);
+  g_log.initialized = 1;
+}
+
+void census_log_shutdown(void) {
+  GPR_ASSERT(g_log.initialized);
+  gpr_mu_destroy(&g_log.lock);
+  gpr_free_aligned(g_log.core_local_blocks);
+  g_log.core_local_blocks = NULL;
+  gpr_free_aligned(g_log.blocks);
+  g_log.blocks = NULL;
+  gpr_free(g_log.buffer);
+  g_log.buffer = NULL;
+  g_log.initialized = 0;
+}
+
+void *census_log_start_write(size_t size) {
+  /* Used to bound number of times block allocation is attempted. */
+  int32_t attempts_remaining = g_log.num_blocks;
+  /* TODO(aveitch): move this inside the do loop when current_cpu is fixed */
+  int32_t core_id = gpr_cpu_current_cpu();
+  GPR_ASSERT(g_log.initialized);
+  if (size > CENSUS_LOG_MAX_RECORD_SIZE) {
+    return NULL;
+  }
+  do {
+    int allocated;
+    void *record = NULL;
+    cl_block *block =
+        cl_core_local_block_get_block(&g_log.core_local_blocks[core_id]);
+    if (block && (record = cl_block_start_write(block, size))) {
+      return record;
+    }
+    /* Need to allocate a new block. We are here if:
+       - No block associated with the core OR
+       - Write in-progress on the block OR
+       - block is out of space */
+    if (gpr_atm_acq_load(&g_log.is_full)) {
+      gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
+      return NULL;
+    }
+    gpr_mu_lock(&g_log.lock);
+    allocated = cl_allocate_core_local_block(core_id, block);
+    gpr_mu_unlock(&g_log.lock);
+    if (!allocated) {
+      gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
+      return NULL;
+    }
+  } while (attempts_remaining--);
+  /* Give up. */
+  gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
+  return NULL;
+}
+
+void census_log_end_write(void *record, size_t bytes_written) {
+  GPR_ASSERT(g_log.initialized);
+  cl_block_end_write(cl_get_block(record), bytes_written);
+}
+
+void census_log_init_reader(void) {
+  GPR_ASSERT(g_log.initialized);
+  gpr_mu_lock(&g_log.lock);
+  /* If a block is locked for reading unlock it. */
+  if (g_log.block_being_read != NULL) {
+    cl_block_end_read(g_log.block_being_read);
+    g_log.block_being_read = NULL;
+  }
+  g_log.read_iterator_state = g_log.num_cores;
+  gpr_mu_unlock(&g_log.lock);
+}
+
+const void *census_log_read_next(size_t *bytes_available) {
+  GPR_ASSERT(g_log.initialized);
+  gpr_mu_lock(&g_log.lock);
+  if (g_log.block_being_read != NULL) {
+    cl_block_end_read(g_log.block_being_read);
+  }
+  do {
+    g_log.block_being_read = cl_next_block_to_read(g_log.block_being_read);
+    if (g_log.block_being_read != NULL) {
+      void *record =
+          cl_block_start_read(g_log.block_being_read, bytes_available);
+      if (record != NULL) {
+        gpr_mu_unlock(&g_log.lock);
+        return record;
+      }
+    }
+  } while (g_log.block_being_read != NULL);
+  gpr_mu_unlock(&g_log.lock);
+  return NULL;
+}
+
+size_t census_log_remaining_space(void) {
+  size_t space;
+  GPR_ASSERT(g_log.initialized);
+  gpr_mu_lock(&g_log.lock);
+  if (g_log.discard_old_records) {
+    /* Remaining space is not meaningful; just return the entire log space. */
+    space = g_log.num_blocks << CENSUS_LOG_2_MAX_RECORD_SIZE;
+  } else {
+    space = g_log.free_block_list.count * CENSUS_LOG_MAX_RECORD_SIZE;
+  }
+  gpr_mu_unlock(&g_log.lock);
+  return space;
+}
+
+int census_log_out_of_space_count(void) {
+  GPR_ASSERT(g_log.initialized);
+  return gpr_atm_acq_load(&g_log.out_of_space_count);
+}
diff --git a/src/core/lib/statistics/census_log.h b/src/core/lib/statistics/census_log.h
new file mode 100644
index 0000000..c3fbd55
--- /dev/null
+++ b/src/core/lib/statistics/census_log.h
@@ -0,0 +1,91 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_STATISTICS_CENSUS_LOG_H
+#define GRPC_CORE_LIB_STATISTICS_CENSUS_LOG_H
+
+#include <stddef.h>
+
+/* Maximum record size, in bytes. */
+#define CENSUS_LOG_2_MAX_RECORD_SIZE 14 /* 2^14 = 16KB */
+#define CENSUS_LOG_MAX_RECORD_SIZE (1 << CENSUS_LOG_2_MAX_RECORD_SIZE)
+
+/* Initialize the statistics logging subsystem with the given log size. A log
+   size of 0 will result in the smallest possible log for the platform
+   (approximately CENSUS_LOG_MAX_RECORD_SIZE * gpr_cpu_num_cores()). If
+   discard_old_records is non-zero, then new records will displace older ones
+   when the log is full. This function must be called before any other
+   census_log functions.
+*/
+void census_log_initialize(size_t size_in_mb, int discard_old_records);
+
+/* Shutdown the logging subsystem. Caller must ensure that:
+   - no in progress or future call to any census_log functions
+   - no incomplete records
+*/
+void census_log_shutdown(void);
+
+/* Allocates and returns a 'size' bytes record and marks it in use. A
+   subsequent census_log_end_write() marks the record complete. The
+   'bytes_written' census_log_end_write() argument must be <=
+   'size'. Returns NULL if out-of-space AND:
+       - log is configured to keep old records OR
+       - all blocks are pinned by incomplete records.
+*/
+void *census_log_start_write(size_t size);
+
+void census_log_end_write(void *record, size_t bytes_written);
+
+/* census_log_read_next() iterates over blocks with data and for each block
+   returns a pointer to the first unread byte. The number of bytes that can be
+   read are returned in 'bytes_available'. Reader is expected to read all
+   available data. Reading the data consumes it i.e. it cannot be read again.
+   census_log_read_next() returns NULL if the end is reached i.e last block
+   is read. census_log_init_reader() starts the iteration or aborts the
+   current iteration.
+*/
+void census_log_init_reader(void);
+const void *census_log_read_next(size_t *bytes_available);
+
+/* Returns estimated remaining space across all blocks, in bytes. If log is
+   configured to discard old records, returns total log space. Otherwise,
+   returns space available in empty blocks (partially filled blocks are
+   treated as full).
+*/
+size_t census_log_remaining_space(void);
+
+/* Returns the number of times gprc_stats_log_start_write() failed due to
+   out-of-space. */
+int census_log_out_of_space_count(void);
+
+#endif /* GRPC_CORE_LIB_STATISTICS_CENSUS_LOG_H */
diff --git a/src/core/lib/statistics/census_rpc_stats.c b/src/core/lib/statistics/census_rpc_stats.c
new file mode 100644
index 0000000..2182561
--- /dev/null
+++ b/src/core/lib/statistics/census_rpc_stats.c
@@ -0,0 +1,253 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include "src/core/lib/statistics/census_interface.h"
+#include "src/core/lib/statistics/census_rpc_stats.h"
+#include "src/core/lib/statistics/census_tracing.h"
+#include "src/core/lib/statistics/hash_table.h"
+#include "src/core/lib/statistics/window_stats.h"
+#include "src/core/lib/support/murmur_hash.h"
+#include "src/core/lib/support/string.h"
+
+#define NUM_INTERVALS 3
+#define MINUTE_INTERVAL 0
+#define HOUR_INTERVAL 1
+#define TOTAL_INTERVAL 2
+
+/* for easier typing */
+typedef census_per_method_rpc_stats per_method_stats;
+
+/* Ensure mu is only initialized once. */
+static gpr_once g_stats_store_mu_init = GPR_ONCE_INIT;
+/* Guards two stats stores. */
+static gpr_mu g_mu;
+static census_ht *g_client_stats_store = NULL;
+static census_ht *g_server_stats_store = NULL;
+
+static void init_mutex(void) { gpr_mu_init(&g_mu); }
+
+static void init_mutex_once(void) {
+  gpr_once_init(&g_stats_store_mu_init, init_mutex);
+}
+
+static int cmp_str_keys(const void *k1, const void *k2) {
+  return strcmp((const char *)k1, (const char *)k2);
+}
+
+/* TODO(hongyu): replace it with cityhash64 */
+static uint64_t simple_hash(const void *k) {
+  size_t len = strlen(k);
+  uint64_t higher = gpr_murmur_hash3((const char *)k, len / 2, 0);
+  return higher << 32 |
+         gpr_murmur_hash3((const char *)k + len / 2, len - len / 2, 0);
+}
+
+static void delete_stats(void *stats) {
+  census_window_stats_destroy((struct census_window_stats *)stats);
+}
+
+static void delete_key(void *key) { gpr_free(key); }
+
+static const census_ht_option ht_opt = {
+    CENSUS_HT_POINTER /* key type */, 1999 /* n_of_buckets */,
+    simple_hash /* hash function */,  cmp_str_keys /* key comparator */,
+    delete_stats /* data deleter */,  delete_key /* key deleter */
+};
+
+static void init_rpc_stats(void *stats) {
+  memset(stats, 0, sizeof(census_rpc_stats));
+}
+
+static void stat_add_proportion(double p, void *base, const void *addme) {
+  census_rpc_stats *b = (census_rpc_stats *)base;
+  census_rpc_stats *a = (census_rpc_stats *)addme;
+  b->cnt += p * a->cnt;
+  b->rpc_error_cnt += p * a->rpc_error_cnt;
+  b->app_error_cnt += p * a->app_error_cnt;
+  b->elapsed_time_ms += p * a->elapsed_time_ms;
+  b->api_request_bytes += p * a->api_request_bytes;
+  b->wire_request_bytes += p * a->wire_request_bytes;
+  b->api_response_bytes += p * a->api_response_bytes;
+  b->wire_response_bytes += p * a->wire_response_bytes;
+}
+
+static void stat_add(void *base, const void *addme) {
+  stat_add_proportion(1.0, base, addme);
+}
+
+static gpr_timespec min_hour_total_intervals[3] = {
+    {60, 0}, {3600, 0}, {36000000, 0}};
+
+static const census_window_stats_stat_info window_stats_settings = {
+    sizeof(census_rpc_stats), init_rpc_stats, stat_add, stat_add_proportion};
+
+census_rpc_stats *census_rpc_stats_create_empty(void) {
+  census_rpc_stats *ret =
+      (census_rpc_stats *)gpr_malloc(sizeof(census_rpc_stats));
+  memset(ret, 0, sizeof(census_rpc_stats));
+  return ret;
+}
+
+void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats *data) {
+  int i = 0;
+  for (i = 0; i < data->num_entries; i++) {
+    if (data->stats[i].method != NULL) {
+      gpr_free((void *)data->stats[i].method);
+    }
+  }
+  if (data->stats != NULL) {
+    gpr_free(data->stats);
+  }
+  data->num_entries = 0;
+  data->stats = NULL;
+}
+
+static void record_stats(census_ht *store, census_op_id op_id,
+                         const census_rpc_stats *stats) {
+  gpr_mu_lock(&g_mu);
+  if (store != NULL) {
+    census_trace_obj *trace = NULL;
+    census_internal_lock_trace_store();
+    trace = census_get_trace_obj_locked(op_id);
+    if (trace != NULL) {
+      const char *method_name = census_get_trace_method_name(trace);
+      struct census_window_stats *window_stats = NULL;
+      census_ht_key key;
+      key.ptr = (void *)method_name;
+      window_stats = census_ht_find(store, key);
+      census_internal_unlock_trace_store();
+      if (window_stats == NULL) {
+        window_stats = census_window_stats_create(3, min_hour_total_intervals,
+                                                  30, &window_stats_settings);
+        key.ptr = gpr_strdup(key.ptr);
+        census_ht_insert(store, key, (void *)window_stats);
+      }
+      census_window_stats_add(window_stats, gpr_now(GPR_CLOCK_REALTIME), stats);
+    } else {
+      census_internal_unlock_trace_store();
+    }
+  }
+  gpr_mu_unlock(&g_mu);
+}
+
+void census_record_rpc_client_stats(census_op_id op_id,
+                                    const census_rpc_stats *stats) {
+  record_stats(g_client_stats_store, op_id, stats);
+}
+
+void census_record_rpc_server_stats(census_op_id op_id,
+                                    const census_rpc_stats *stats) {
+  record_stats(g_server_stats_store, op_id, stats);
+}
+
+/* Get stats from input stats store */
+static void get_stats(census_ht *store, census_aggregated_rpc_stats *data) {
+  GPR_ASSERT(data != NULL);
+  if (data->num_entries != 0) {
+    census_aggregated_rpc_stats_set_empty(data);
+  }
+  gpr_mu_lock(&g_mu);
+  if (store != NULL) {
+    size_t n;
+    unsigned i, j;
+    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;
+      data->stats =
+          (per_method_stats *)gpr_malloc(sizeof(per_method_stats) * n);
+      for (i = 0; i < n; i++) {
+        census_window_stats_sums sums[NUM_INTERVALS];
+        for (j = 0; j < NUM_INTERVALS; j++) {
+          sums[j].statistic = (void *)census_rpc_stats_create_empty();
+        }
+        data->stats[i].method = gpr_strdup(kv[i].k.ptr);
+        census_window_stats_get_sums(kv[i].v, now, sums);
+        data->stats[i].minute_stats =
+            *(census_rpc_stats *)sums[MINUTE_INTERVAL].statistic;
+        data->stats[i].hour_stats =
+            *(census_rpc_stats *)sums[HOUR_INTERVAL].statistic;
+        data->stats[i].total_stats =
+            *(census_rpc_stats *)sums[TOTAL_INTERVAL].statistic;
+        for (j = 0; j < NUM_INTERVALS; j++) {
+          gpr_free(sums[j].statistic);
+        }
+      }
+      gpr_free(kv);
+    }
+  }
+  gpr_mu_unlock(&g_mu);
+}
+
+void census_get_client_stats(census_aggregated_rpc_stats *data) {
+  get_stats(g_client_stats_store, data);
+}
+
+void census_get_server_stats(census_aggregated_rpc_stats *data) {
+  get_stats(g_server_stats_store, data);
+}
+
+void census_stats_store_init(void) {
+  init_mutex_once();
+  gpr_mu_lock(&g_mu);
+  if (g_client_stats_store == NULL && g_server_stats_store == NULL) {
+    g_client_stats_store = census_ht_create(&ht_opt);
+    g_server_stats_store = census_ht_create(&ht_opt);
+  } else {
+    gpr_log(GPR_ERROR, "Census stats store already initialized.");
+  }
+  gpr_mu_unlock(&g_mu);
+}
+
+void census_stats_store_shutdown(void) {
+  init_mutex_once();
+  gpr_mu_lock(&g_mu);
+  if (g_client_stats_store != NULL) {
+    census_ht_destroy(g_client_stats_store);
+    g_client_stats_store = NULL;
+  } else {
+    gpr_log(GPR_ERROR, "Census server stats store not initialized.");
+  }
+  if (g_server_stats_store != NULL) {
+    census_ht_destroy(g_server_stats_store);
+    g_server_stats_store = NULL;
+  } else {
+    gpr_log(GPR_ERROR, "Census client stats store not initialized.");
+  }
+  gpr_mu_unlock(&g_mu);
+}
diff --git a/src/core/lib/statistics/census_rpc_stats.h b/src/core/lib/statistics/census_rpc_stats.h
new file mode 100644
index 0000000..00bb482
--- /dev/null
+++ b/src/core/lib/statistics/census_rpc_stats.h
@@ -0,0 +1,101 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_STATISTICS_CENSUS_RPC_STATS_H
+#define GRPC_CORE_LIB_STATISTICS_CENSUS_RPC_STATS_H
+
+#include <grpc/support/port_platform.h>
+#include "src/core/lib/statistics/census_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct census_rpc_stats {
+  uint64_t cnt;
+  uint64_t rpc_error_cnt;
+  uint64_t app_error_cnt;
+  double elapsed_time_ms;
+  double api_request_bytes;
+  double wire_request_bytes;
+  double api_response_bytes;
+  double wire_response_bytes;
+};
+
+/* Creates an empty rpc stats object on heap. */
+census_rpc_stats *census_rpc_stats_create_empty(void);
+
+typedef struct census_per_method_rpc_stats {
+  const char *method;
+  census_rpc_stats minute_stats; /* cumulative stats in the past minute */
+  census_rpc_stats hour_stats;   /* cumulative stats in the past hour */
+  census_rpc_stats total_stats;  /* cumulative stats from last gc */
+} census_per_method_rpc_stats;
+
+typedef struct census_aggregated_rpc_stats {
+  int num_entries;
+  census_per_method_rpc_stats *stats;
+} census_aggregated_rpc_stats;
+
+/* Initializes an aggregated rpc stats object to an empty state. */
+void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats *data);
+
+/* Records client side stats of a rpc. */
+void census_record_rpc_client_stats(census_op_id op_id,
+                                    const census_rpc_stats *stats);
+
+/* Records server side stats of a rpc. */
+void census_record_rpc_server_stats(census_op_id op_id,
+                                    const census_rpc_stats *stats);
+
+/* The following two functions are intended for inprocess query of
+   per-service per-method stats from grpc implementations. */
+
+/* Populates *data_map with server side aggregated per-service per-method
+   stats.
+   DO NOT CALL from outside of grpc code. */
+void census_get_server_stats(census_aggregated_rpc_stats *data_map);
+
+/* Populates *data_map with client side aggregated per-service per-method
+   stats.
+   DO NOT CALL from outside of grpc code. */
+void census_get_client_stats(census_aggregated_rpc_stats *data_map);
+
+void census_stats_store_init(void);
+void census_stats_store_shutdown(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_STATISTICS_CENSUS_RPC_STATS_H */
diff --git a/src/core/lib/statistics/census_tracing.c b/src/core/lib/statistics/census_tracing.c
new file mode 100644
index 0000000..b58ae73
--- /dev/null
+++ b/src/core/lib/statistics/census_tracing.c
@@ -0,0 +1,241 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/statistics/census_tracing.h"
+#include "src/core/lib/statistics/census_interface.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/sync.h>
+#include "src/core/lib/statistics/hash_table.h"
+#include "src/core/lib/support/string.h"
+
+void census_trace_obj_destroy(census_trace_obj *obj) {
+  census_trace_annotation *p = obj->annotations;
+  while (p != NULL) {
+    census_trace_annotation *next = p->next;
+    gpr_free(p);
+    p = next;
+  }
+  gpr_free(obj->method);
+  gpr_free(obj);
+}
+
+static void delete_trace_obj(void *obj) {
+  census_trace_obj_destroy((census_trace_obj *)obj);
+}
+
+static const census_ht_option ht_opt = {
+    CENSUS_HT_UINT64 /* key type */,
+    571 /* n_of_buckets */,
+    NULL /* hash */,
+    NULL /* compare_keys */,
+    delete_trace_obj /* delete data */,
+    NULL /* delete key */
+};
+
+static gpr_once g_init_mutex_once = GPR_ONCE_INIT;
+static gpr_mu g_mu; /* Guards following two static variables. */
+static census_ht *g_trace_store = NULL;
+static uint64_t g_id = 0;
+
+static census_ht_key op_id_as_key(census_op_id *id) {
+  return *(census_ht_key *)id;
+}
+
+static uint64_t op_id_2_uint64(census_op_id *id) {
+  uint64_t ret;
+  memcpy(&ret, id, sizeof(census_op_id));
+  return ret;
+}
+
+static void init_mutex(void) { gpr_mu_init(&g_mu); }
+
+static void init_mutex_once(void) {
+  gpr_once_init(&g_init_mutex_once, init_mutex);
+}
+
+census_op_id census_tracing_start_op(void) {
+  gpr_mu_lock(&g_mu);
+  {
+    census_trace_obj *ret = gpr_malloc(sizeof(census_trace_obj));
+    memset(ret, 0, sizeof(census_trace_obj));
+    g_id++;
+    memcpy(&ret->id, &g_id, sizeof(census_op_id));
+    ret->rpc_stats.cnt = 1;
+    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);
+    return ret->id;
+  }
+}
+
+int census_add_method_tag(census_op_id op_id, const char *method) {
+  int ret = 0;
+  census_trace_obj *trace = NULL;
+  gpr_mu_lock(&g_mu);
+  trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
+  if (trace == NULL) {
+    ret = 1;
+  } else {
+    trace->method = gpr_strdup(method);
+  }
+  gpr_mu_unlock(&g_mu);
+  return ret;
+}
+
+void census_tracing_print(census_op_id op_id, const char *anno_txt) {
+  census_trace_obj *trace = NULL;
+  gpr_mu_lock(&g_mu);
+  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(GPR_CLOCK_REALTIME);
+    {
+      char *d = anno->txt;
+      const char *s = anno_txt;
+      int n = 0;
+      for (; n < CENSUS_MAX_ANNOTATION_LENGTH && *s != '\0'; ++n) {
+        *d++ = *s++;
+      }
+      *d = '\0';
+    }
+    anno->next = trace->annotations;
+    trace->annotations = anno;
+  }
+  gpr_mu_unlock(&g_mu);
+}
+
+void census_tracing_end_op(census_op_id op_id) {
+  census_trace_obj *trace = NULL;
+  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(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);
+    census_ht_erase(g_trace_store, op_id_as_key(&op_id));
+  }
+  gpr_mu_unlock(&g_mu);
+}
+
+void census_tracing_init(void) {
+  init_mutex_once();
+  gpr_mu_lock(&g_mu);
+  if (g_trace_store == NULL) {
+    g_id = 1;
+    g_trace_store = census_ht_create(&ht_opt);
+  } else {
+    gpr_log(GPR_ERROR, "Census trace store already initialized.");
+  }
+  gpr_mu_unlock(&g_mu);
+}
+
+void census_tracing_shutdown(void) {
+  gpr_mu_lock(&g_mu);
+  if (g_trace_store != NULL) {
+    census_ht_destroy(g_trace_store);
+    g_trace_store = NULL;
+  } else {
+    gpr_log(GPR_ERROR, "Census trace store is not initialized.");
+  }
+  gpr_mu_unlock(&g_mu);
+}
+
+void census_internal_lock_trace_store(void) { gpr_mu_lock(&g_mu); }
+
+void census_internal_unlock_trace_store(void) { gpr_mu_unlock(&g_mu); }
+
+census_trace_obj *census_get_trace_obj_locked(census_op_id op_id) {
+  if (g_trace_store == NULL) {
+    gpr_log(GPR_ERROR, "Census trace store is not initialized.");
+    return NULL;
+  }
+  return (census_trace_obj *)census_ht_find(g_trace_store,
+                                            op_id_as_key(&op_id));
+}
+
+const char *census_get_trace_method_name(const census_trace_obj *trace) {
+  return trace->method;
+}
+
+static census_trace_annotation *dup_annotation_chain(
+    census_trace_annotation *from) {
+  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));
+    to = &(*to)->next;
+  }
+  return ret;
+}
+
+static census_trace_obj *trace_obj_dup(census_trace_obj *from) {
+  census_trace_obj *to = NULL;
+  GPR_ASSERT(from != NULL);
+  to = gpr_malloc(sizeof(census_trace_obj));
+  to->id = from->id;
+  to->ts = from->ts;
+  to->rpc_stats = from->rpc_stats;
+  to->method = gpr_strdup(from->method);
+  to->annotations = dup_annotation_chain(from->annotations);
+  return to;
+}
+
+census_trace_obj **census_get_active_ops(int *num_active_ops) {
+  census_trace_obj **ret = NULL;
+  gpr_mu_lock(&g_mu);
+  if (g_trace_store != NULL) {
+    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) {
+      size_t i = 0;
+      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);
+      }
+    }
+    gpr_free(all_kvs);
+  }
+  gpr_mu_unlock(&g_mu);
+  return ret;
+}
diff --git a/src/core/lib/statistics/census_tracing.h b/src/core/lib/statistics/census_tracing.h
new file mode 100644
index 0000000..a101abf
--- /dev/null
+++ b/src/core/lib/statistics/census_tracing.h
@@ -0,0 +1,96 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_STATISTICS_CENSUS_TRACING_H
+#define GRPC_CORE_LIB_STATISTICS_CENSUS_TRACING_H
+
+#include <grpc/support/time.h>
+#include "src/core/lib/statistics/census_rpc_stats.h"
+
+/* WARNING: The data structures and APIs provided by this file are for GRPC
+   library's internal use ONLY. They might be changed in backward-incompatible
+   ways and are not subject to any deprecation policy.
+   They are not recommended for external use.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Struct for a trace annotation. */
+typedef struct census_trace_annotation {
+  gpr_timespec ts;                            /* timestamp of the annotation */
+  char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */
+  struct census_trace_annotation *next;
+} census_trace_annotation;
+
+typedef struct census_trace_obj {
+  census_op_id id;
+  gpr_timespec ts;
+  census_rpc_stats rpc_stats;
+  char *method;
+  census_trace_annotation *annotations;
+} census_trace_obj;
+
+/* Deletes trace object. */
+void census_trace_obj_destroy(census_trace_obj *obj);
+
+/* Initializes trace store. This function is thread safe. */
+void census_tracing_init(void);
+
+/* Shutsdown trace store. This function is thread safe. */
+void census_tracing_shutdown(void);
+
+/* Gets trace obj corresponding to the input op_id. Returns NULL if trace store
+   is not initialized or trace obj is not found. Requires trace store being
+   locked before calling this function. */
+census_trace_obj *census_get_trace_obj_locked(census_op_id op_id);
+
+/* The following two functions acquire and release the trace store global lock.
+   They are for census internal use only. */
+void census_internal_lock_trace_store(void);
+void census_internal_unlock_trace_store(void);
+
+/* Gets method name associated with the input trace object. */
+const char *census_get_trace_method_name(const census_trace_obj *trace);
+
+/* Returns an array of pointers to trace objects of currently active operations
+   and fills in number of active operations. Returns NULL if there are no active
+   operations.
+   Caller owns the returned objects. */
+census_trace_obj **census_get_active_ops(int *num_active_ops);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_STATISTICS_CENSUS_TRACING_H */
diff --git a/src/core/lib/statistics/hash_table.c b/src/core/lib/statistics/hash_table.c
new file mode 100644
index 0000000..18b7442
--- /dev/null
+++ b/src/core/lib/statistics/hash_table.c
@@ -0,0 +1,303 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/statistics/hash_table.h"
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+
+#define CENSUS_HT_NUM_BUCKETS 1999
+
+/* A single hash table data entry */
+typedef struct ht_entry {
+  census_ht_key key;
+  void *data;
+  struct ht_entry *next;
+} ht_entry;
+
+/* hash table bucket */
+typedef struct bucket {
+  /* NULL if bucket is empty */
+  ht_entry *next;
+  /* -1 if all buckets are empty. */
+  int32_t prev_non_empty_bucket;
+  /* -1 if all buckets are empty. */
+  int32_t next_non_empty_bucket;
+} bucket;
+
+struct unresizable_hash_table {
+  /* Number of entries in the table */
+  size_t size;
+  /* Number of buckets */
+  uint32_t num_buckets;
+  /* Array of buckets initialized at creation time. Memory consumption is
+     16 bytes per bucket on a 64-bit platform. */
+  bucket *buckets;
+  /* Index of the first non-empty bucket. -1 iff size == 0. */
+  int32_t first_non_empty_bucket;
+  /* Index of the last non_empty bucket. -1 iff size == 0. */
+  int32_t last_non_empty_bucket;
+  /* Immutable options of this hash table, initialized at creation time. */
+  census_ht_option options;
+};
+
+typedef struct entry_locator {
+  int32_t bucket_idx;
+  int is_first_in_chain;
+  int found;
+  ht_entry *prev_entry;
+} entry_locator;
+
+/* Asserts if option is not valid. */
+void check_options(const census_ht_option *option) {
+  GPR_ASSERT(option != NULL);
+  GPR_ASSERT(option->num_buckets > 0);
+  GPR_ASSERT(option->key_type == CENSUS_HT_UINT64 ||
+             option->key_type == CENSUS_HT_POINTER);
+  if (option->key_type == CENSUS_HT_UINT64) {
+    GPR_ASSERT(option->hash == NULL);
+  } else if (option->key_type == CENSUS_HT_POINTER) {
+    GPR_ASSERT(option->hash != NULL);
+    GPR_ASSERT(option->compare_keys != NULL);
+  }
+}
+
+#define REMOVE_NEXT(options, ptr) \
+  do {                            \
+    ht_entry *tmp = (ptr)->next;  \
+    (ptr)->next = tmp->next;      \
+    delete_entry(options, tmp);   \
+  } while (0)
+
+static void delete_entry(const census_ht_option *opt, ht_entry *p) {
+  if (opt->delete_data != NULL) {
+    opt->delete_data(p->data);
+  }
+  if (opt->delete_key != NULL) {
+    opt->delete_key(p->key.ptr);
+  }
+  gpr_free(p);
+}
+
+static uint64_t hash(const census_ht_option *opt, census_ht_key key) {
+  return opt->key_type == CENSUS_HT_UINT64 ? key.val : opt->hash(key.ptr);
+}
+
+census_ht *census_ht_create(const census_ht_option *option) {
+  int i;
+  census_ht *ret = NULL;
+  check_options(option);
+  ret = (census_ht *)gpr_malloc(sizeof(census_ht));
+  ret->size = 0;
+  ret->num_buckets = option->num_buckets;
+  ret->buckets = (bucket *)gpr_malloc(sizeof(bucket) * ret->num_buckets);
+  ret->options = *option;
+  /* initialize each bucket */
+  for (i = 0; i < ret->options.num_buckets; i++) {
+    ret->buckets[i].prev_non_empty_bucket = -1;
+    ret->buckets[i].next_non_empty_bucket = -1;
+    ret->buckets[i].next = NULL;
+  }
+  return ret;
+}
+
+static int32_t find_bucket_idx(const census_ht *ht, census_ht_key key) {
+  return hash(&ht->options, key) % ht->num_buckets;
+}
+
+static int keys_match(const census_ht_option *opt, const ht_entry *p,
+                      const census_ht_key key) {
+  GPR_ASSERT(opt->key_type == CENSUS_HT_UINT64 ||
+             opt->key_type == CENSUS_HT_POINTER);
+  if (opt->key_type == CENSUS_HT_UINT64) return p->key.val == key.val;
+  return !opt->compare_keys((p->key).ptr, key.ptr);
+}
+
+static entry_locator ht_find(const census_ht *ht, census_ht_key key) {
+  entry_locator loc = {0, 0, 0, NULL};
+  int32_t idx = 0;
+  ht_entry *ptr = NULL;
+  GPR_ASSERT(ht != NULL);
+  idx = find_bucket_idx(ht, key);
+  ptr = ht->buckets[idx].next;
+  if (ptr == NULL) {
+    /* bucket is empty */
+    return loc;
+  }
+  if (keys_match(&ht->options, ptr, key)) {
+    loc.bucket_idx = idx;
+    loc.is_first_in_chain = 1;
+    loc.found = 1;
+    return loc;
+  } else {
+    for (; ptr->next != NULL; ptr = ptr->next) {
+      if (keys_match(&ht->options, ptr->next, key)) {
+        loc.bucket_idx = idx;
+        loc.is_first_in_chain = 0;
+        loc.found = 1;
+        loc.prev_entry = ptr;
+        return loc;
+      }
+    }
+  }
+  /* Could not find the key */
+  return loc;
+}
+
+void *census_ht_find(const census_ht *ht, census_ht_key key) {
+  entry_locator loc = ht_find(ht, key);
+  if (loc.found == 0) {
+    return NULL;
+  }
+  return loc.is_first_in_chain ? ht->buckets[loc.bucket_idx].next->data
+                               : loc.prev_entry->next->data;
+}
+
+void census_ht_insert(census_ht *ht, census_ht_key key, void *data) {
+  int32_t idx = find_bucket_idx(ht, key);
+  ht_entry *ptr = NULL;
+  entry_locator loc = ht_find(ht, key);
+  if (loc.found) {
+    /* Replace old value with new value. */
+    ptr = loc.is_first_in_chain ? ht->buckets[loc.bucket_idx].next
+                                : loc.prev_entry->next;
+    if (ht->options.delete_data != NULL) {
+      ht->options.delete_data(ptr->data);
+    }
+    ptr->data = data;
+    return;
+  }
+
+  /* first entry in the table. */
+  if (ht->size == 0) {
+    ht->buckets[idx].next_non_empty_bucket = -1;
+    ht->buckets[idx].prev_non_empty_bucket = -1;
+    ht->first_non_empty_bucket = idx;
+    ht->last_non_empty_bucket = idx;
+  } else if (ht->buckets[idx].next == NULL) {
+    /* first entry in the bucket. */
+    ht->buckets[ht->last_non_empty_bucket].next_non_empty_bucket = idx;
+    ht->buckets[idx].prev_non_empty_bucket = ht->last_non_empty_bucket;
+    ht->buckets[idx].next_non_empty_bucket = -1;
+    ht->last_non_empty_bucket = idx;
+  }
+  ptr = (ht_entry *)gpr_malloc(sizeof(ht_entry));
+  ptr->key = key;
+  ptr->data = data;
+  ptr->next = ht->buckets[idx].next;
+  ht->buckets[idx].next = ptr;
+  ht->size++;
+}
+
+void census_ht_erase(census_ht *ht, census_ht_key key) {
+  entry_locator loc = ht_find(ht, key);
+  if (loc.found == 0) {
+    /* noop if not found */
+    return;
+  }
+  ht->size--;
+  if (loc.is_first_in_chain) {
+    bucket *b = &ht->buckets[loc.bucket_idx];
+    GPR_ASSERT(b->next != NULL);
+    /* The only entry in the bucket */
+    if (b->next->next == NULL) {
+      int prev = b->prev_non_empty_bucket;
+      int next = b->next_non_empty_bucket;
+      if (prev != -1) {
+        ht->buckets[prev].next_non_empty_bucket = next;
+      } else {
+        ht->first_non_empty_bucket = next;
+      }
+      if (next != -1) {
+        ht->buckets[next].prev_non_empty_bucket = prev;
+      } else {
+        ht->last_non_empty_bucket = prev;
+      }
+    }
+    REMOVE_NEXT(&ht->options, b);
+  } else {
+    GPR_ASSERT(loc.prev_entry->next != NULL);
+    REMOVE_NEXT(&ht->options, loc.prev_entry);
+  }
+}
+
+/* Returns NULL if input table is empty. */
+census_ht_kv *census_ht_get_all_elements(const census_ht *ht, size_t *num) {
+  census_ht_kv *ret = NULL;
+  int i = 0;
+  int32_t idx = -1;
+  GPR_ASSERT(ht != NULL && num != NULL);
+  *num = ht->size;
+  if (*num == 0) {
+    return NULL;
+  }
+
+  ret = (census_ht_kv *)gpr_malloc(sizeof(census_ht_kv) * ht->size);
+  idx = ht->first_non_empty_bucket;
+  while (idx >= 0) {
+    ht_entry *ptr = ht->buckets[idx].next;
+    for (; ptr != NULL; ptr = ptr->next) {
+      ret[i].k = ptr->key;
+      ret[i].v = ptr->data;
+      i++;
+    }
+    idx = ht->buckets[idx].next_non_empty_bucket;
+  }
+  return ret;
+}
+
+static void ht_delete_entry_chain(const census_ht_option *options,
+                                  ht_entry *first) {
+  if (first == NULL) {
+    return;
+  }
+  if (first->next != NULL) {
+    ht_delete_entry_chain(options, first->next);
+  }
+  delete_entry(options, first);
+}
+
+void census_ht_destroy(census_ht *ht) {
+  unsigned i;
+  for (i = 0; i < ht->num_buckets; ++i) {
+    ht_delete_entry_chain(&ht->options, ht->buckets[i].next);
+  }
+  gpr_free(ht->buckets);
+  gpr_free(ht);
+}
+
+size_t census_ht_get_size(const census_ht *ht) { return ht->size; }
diff --git a/src/core/lib/statistics/hash_table.h b/src/core/lib/statistics/hash_table.h
new file mode 100644
index 0000000..8f74ec8
--- /dev/null
+++ b/src/core/lib/statistics/hash_table.h
@@ -0,0 +1,131 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_STATISTICS_HASH_TABLE_H
+#define GRPC_CORE_LIB_STATISTICS_HASH_TABLE_H
+
+#include <stddef.h>
+
+#include <grpc/support/port_platform.h>
+
+/* A chain based hash table with fixed number of buckets.
+   Your probably shouldn't use this code directly. It is implemented for the
+   use case in census trace store and stats store, where number of entries in
+   the table is in the scale of upto several thousands, entries are added and
+   removed from the table very frequently (~100k/s), the frequency of find()
+   operations is roughly several times of the frequency of insert() and erase()
+   Comparing to find(), the insert(), erase() and get_all_entries() operations
+   are much less freqent (<1/s).
+
+   Per bucket memory overhead is about (8 + sizeof(intptr_t) bytes.
+   Per entry memory overhead is about (8 + 2 * sizeof(intptr_t) bytes.
+
+   All functions are not thread-safe. Synchronization will be provided in the
+   upper layer (in trace store and stats store).
+*/
+
+/* Opaque hash table struct */
+typedef struct unresizable_hash_table census_ht;
+
+/* Currently, the hash_table can take two types of keys. (uint64 for trace
+   store and const char* for stats store). */
+typedef union {
+  uint64_t val;
+  void *ptr;
+} census_ht_key;
+
+typedef enum census_ht_key_type {
+  CENSUS_HT_UINT64 = 0,
+  CENSUS_HT_POINTER = 1
+} census_ht_key_type;
+
+typedef struct census_ht_option {
+  /* Type of hash key */
+  census_ht_key_type key_type;
+  /* Desired number of buckets, preferably a prime number */
+  int32_t num_buckets;
+  /* Fucntion to calculate uint64 hash value of the key. Only takes effect if
+     key_type is POINTER. */
+  uint64_t (*hash)(const void *);
+  /* Function to compare two keys, returns 0 iff equal. Only takes effect if
+     key_type is POINTER */
+  int (*compare_keys)(const void *k1, const void *k2);
+  /* Value deleter. NULL if no specialized delete function is needed. */
+  void (*delete_data)(void *);
+  /* Key deleter. NULL if table does not own the key. (e.g. key is part of the
+     value or key is not owned by the table.) */
+  void (*delete_key)(void *);
+} census_ht_option;
+
+/* Creates a hashtable with fixed number of buckets according to the settings
+   specified in 'options' arg. Function pointers "hash" and "compare_keys" must
+   be provided if key_type is POINTER. Asserts if fail to create. */
+census_ht *census_ht_create(const census_ht_option *options);
+
+/* Deletes hash table instance. Frees all dynamic memory owned by ht.*/
+void census_ht_destroy(census_ht *ht);
+
+/* Inserts the input key-val pair into hash_table. If an entry with the same key
+   exists in the table, the corresponding value will be overwritten by the input
+   val. */
+void census_ht_insert(census_ht *ht, census_ht_key key, void *val);
+
+/* Returns pointer to data, returns NULL if not found. */
+void *census_ht_find(const census_ht *ht, census_ht_key key);
+
+/* Erase hash table entry with input key. Noop if key is not found. */
+void census_ht_erase(census_ht *ht, census_ht_key key);
+
+typedef struct census_ht_kv {
+  census_ht_key k;
+  void *v;
+} census_ht_kv;
+
+/* Returns an array of pointers to all values in the hash table. Order of the
+   elements can be arbitrary. Sets 'num' to the size of returned array. Caller
+   owns returned array. */
+census_ht_kv *census_ht_get_all_elements(const census_ht *ht, size_t *num);
+
+/* Returns number of elements kept. */
+size_t census_ht_get_size(const census_ht *ht);
+
+/* Functor applied on each key-value pair while iterating through entries in the
+   table. The functor should not mutate data. */
+typedef void (*census_ht_itr_cb)(census_ht_key key, const void *val_ptr,
+                                 void *state);
+
+/* Iterates through all key-value pairs in the hash_table. The callback function
+   should not invalidate data entries. */
+uint64_t census_ht_for_all(const census_ht *ht, census_ht_itr_cb);
+
+#endif /* GRPC_CORE_LIB_STATISTICS_HASH_TABLE_H */
diff --git a/src/core/lib/statistics/window_stats.c b/src/core/lib/statistics/window_stats.c
new file mode 100644
index 0000000..53427a2
--- /dev/null
+++ b/src/core/lib/statistics/window_stats.c
@@ -0,0 +1,316 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/statistics/window_stats.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+#include <math.h>
+#include <stddef.h>
+#include <string.h>
+
+/* typedefs make typing long names easier. Use cws (for census_window_stats) */
+typedef census_window_stats_stat_info cws_stat_info;
+typedef struct census_window_stats_sum cws_sum;
+
+/* Each interval is composed of a number of buckets, which hold a count of
+   entries and a single statistic */
+typedef struct census_window_stats_bucket {
+  int64_t count;
+  void *statistic;
+} cws_bucket;
+
+/* Each interval has a set of buckets, and the variables needed to keep
+   track of their current state */
+typedef struct census_window_stats_interval_stats {
+  /* The buckets. There will be 'granularity' + 1 of these. */
+  cws_bucket *buckets;
+  /* Index of the bucket containing the smallest time interval. */
+  int bottom_bucket;
+  /* The smallest time storable in the current window. */
+  int64_t bottom;
+  /* The largest time storable in the current window + 1ns */
+  int64_t top;
+  /* The width of each bucket in ns. */
+  int64_t width;
+} cws_interval_stats;
+
+typedef struct census_window_stats {
+  /* Number of intervals. */
+  int nintervals;
+  /* Number of buckets in each interval. 'granularity' + 1. */
+  int nbuckets;
+  /* Record of stat_info. */
+  cws_stat_info stat_info;
+  /* Stats for each interval. */
+  cws_interval_stats *interval_stats;
+  /* The time the newset stat was recorded. */
+  int64_t newest_time;
+} window_stats;
+
+/* Calculate an actual bucket index from a logical index 'IDX'. Other
+   parameters supply information on the interval struct and overall stats. */
+#define BUCKET_IDX(IS, IDX, WSTATS) \
+  ((IS->bottom_bucket + (IDX)) % WSTATS->nbuckets)
+
+/* The maximum seconds value we can have in a valid timespec. More than this
+   will result in overflow in timespec_to_ns(). This works out to ~292 years.
+   TODO: consider using doubles instead of int64. */
+static int64_t max_seconds = (GPR_INT64_MAX - GPR_NS_PER_SEC) / GPR_NS_PER_SEC;
+
+static int64_t timespec_to_ns(const gpr_timespec ts) {
+  if (ts.tv_sec > max_seconds) {
+    return GPR_INT64_MAX - 1;
+  }
+  return ts.tv_sec * GPR_NS_PER_SEC + ts.tv_nsec;
+}
+
+static void cws_initialize_statistic(void *statistic,
+                                     const cws_stat_info *stat_info) {
+  if (stat_info->stat_initialize == NULL) {
+    memset(statistic, 0, stat_info->stat_size);
+  } else {
+    stat_info->stat_initialize(statistic);
+  }
+}
+
+/* Create and initialize a statistic */
+static void *cws_create_statistic(const cws_stat_info *stat_info) {
+  void *stat = gpr_malloc(stat_info->stat_size);
+  cws_initialize_statistic(stat, stat_info);
+  return stat;
+}
+
+window_stats *census_window_stats_create(int nintervals,
+                                         const gpr_timespec intervals[],
+                                         int granularity,
+                                         const cws_stat_info *stat_info) {
+  window_stats *ret;
+  int i;
+  /* validate inputs */
+  GPR_ASSERT(nintervals > 0 && granularity > 2 && intervals != NULL &&
+             stat_info != NULL);
+  for (i = 0; i < nintervals; i++) {
+    int64_t ns = timespec_to_ns(intervals[i]);
+    GPR_ASSERT(intervals[i].tv_sec >= 0 && intervals[i].tv_nsec >= 0 &&
+               intervals[i].tv_nsec < GPR_NS_PER_SEC && ns >= 100 &&
+               granularity * 10 <= ns);
+  }
+  /* Allocate and initialize relevant data structures */
+  ret = (window_stats *)gpr_malloc(sizeof(window_stats));
+  ret->nintervals = nintervals;
+  ret->nbuckets = granularity + 1;
+  ret->stat_info = *stat_info;
+  ret->interval_stats =
+      (cws_interval_stats *)gpr_malloc(nintervals * sizeof(cws_interval_stats));
+  for (i = 0; i < nintervals; i++) {
+    int64_t size_ns = timespec_to_ns(intervals[i]);
+    cws_interval_stats *is = ret->interval_stats + i;
+    cws_bucket *buckets = is->buckets =
+        (cws_bucket *)gpr_malloc(ret->nbuckets * sizeof(cws_bucket));
+    int b;
+    for (b = 0; b < ret->nbuckets; b++) {
+      buckets[b].statistic = cws_create_statistic(stat_info);
+      buckets[b].count = 0;
+    }
+    is->bottom_bucket = 0;
+    is->bottom = 0;
+    is->width = size_ns / granularity;
+    /* Check for possible overflow issues, and maximize interval size if the
+       user requested something large enough. */
+    if ((GPR_INT64_MAX - is->width) > size_ns) {
+      is->top = size_ns + is->width;
+    } else {
+      is->top = GPR_INT64_MAX;
+      is->width = GPR_INT64_MAX / (granularity + 1);
+    }
+    /* If size doesn't divide evenly, we can have a width slightly too small;
+       better to have it slightly large. */
+    if ((size_ns - (granularity + 1) * is->width) > 0) {
+      is->width += 1;
+    }
+  }
+  ret->newest_time = 0;
+  return ret;
+}
+
+/* When we try adding a measurement above the current interval range, we
+   need to "shift" the buckets sufficiently to cover the new range. */
+static void cws_shift_buckets(const window_stats *wstats,
+                              cws_interval_stats *is, int64_t when_ns) {
+  int i;
+  /* number of bucket time widths to "shift" */
+  int shift;
+  /* number of buckets to clear */
+  int nclear;
+  GPR_ASSERT(when_ns >= is->top);
+  /* number of bucket time widths to "shift" */
+  shift = ((when_ns - is->top) / is->width) + 1;
+  /* number of buckets to clear - limited by actual number of buckets */
+  nclear = GPR_MIN(shift, wstats->nbuckets);
+  for (i = 0; i < nclear; i++) {
+    int b = BUCKET_IDX(is, i, wstats);
+    is->buckets[b].count = 0;
+    cws_initialize_statistic(is->buckets[b].statistic, &wstats->stat_info);
+  }
+  /* adjust top/bottom times and current bottom bucket */
+  is->bottom_bucket = BUCKET_IDX(is, shift, wstats);
+  is->top += shift * is->width;
+  is->bottom += shift * is->width;
+}
+
+void census_window_stats_add(window_stats *wstats, const gpr_timespec when,
+                             const void *stat_value) {
+  int i;
+  int64_t when_ns = timespec_to_ns(when);
+  GPR_ASSERT(wstats->interval_stats != NULL);
+  for (i = 0; i < wstats->nintervals; i++) {
+    cws_interval_stats *is = wstats->interval_stats + i;
+    cws_bucket *bucket;
+    if (when_ns < is->bottom) { /* Below smallest time in interval: drop */
+      continue;
+    }
+    if (when_ns >= is->top) { /* above limit: shift buckets */
+      cws_shift_buckets(wstats, is, when_ns);
+    }
+    /* Add the stat. */
+    GPR_ASSERT(is->bottom <= when_ns && when_ns < is->top);
+    bucket = is->buckets +
+             BUCKET_IDX(is, (when_ns - is->bottom) / is->width, wstats);
+    bucket->count++;
+    wstats->stat_info.stat_add(bucket->statistic, stat_value);
+  }
+  if (when_ns > wstats->newest_time) {
+    wstats->newest_time = when_ns;
+  }
+}
+
+/* Add a specific bucket contents to an accumulating total. */
+static void cws_add_bucket_to_sum(cws_sum *sum, const cws_bucket *bucket,
+                                  const cws_stat_info *stat_info) {
+  sum->count += bucket->count;
+  stat_info->stat_add(sum->statistic, bucket->statistic);
+}
+
+/* Add a proportion to an accumulating sum. */
+static void cws_add_proportion_to_sum(double p, cws_sum *sum,
+                                      const cws_bucket *bucket,
+                                      const cws_stat_info *stat_info) {
+  sum->count += p * bucket->count;
+  stat_info->stat_add_proportion(p, sum->statistic, bucket->statistic);
+}
+
+void census_window_stats_get_sums(const window_stats *wstats,
+                                  const gpr_timespec when, cws_sum sums[]) {
+  int i;
+  int64_t when_ns = timespec_to_ns(when);
+  GPR_ASSERT(wstats->interval_stats != NULL);
+  for (i = 0; i < wstats->nintervals; i++) {
+    int when_bucket;
+    int new_bucket;
+    double last_proportion = 1.0;
+    double bottom_proportion;
+    cws_interval_stats *is = wstats->interval_stats + i;
+    cws_sum *sum = sums + i;
+    sum->count = 0;
+    cws_initialize_statistic(sum->statistic, &wstats->stat_info);
+    if (when_ns < is->bottom) {
+      continue;
+    }
+    if (when_ns >= is->top) {
+      cws_shift_buckets(wstats, is, when_ns);
+    }
+    /* Calculating the appropriate amount of which buckets to use can get
+       complicated. Essentially there are two cases:
+       1) if the "top" bucket (new_bucket, where the newest additions to the
+       stats recorded are entered) corresponds to 'when', then we need
+       to take a proportion of it - (if when < newest_time) or the full
+       thing. We also (possibly) need to take a corresponding
+       proportion of the bottom bucket.
+       2) Other cases, we just take a straight proportion.
+     */
+    when_bucket = (when_ns - is->bottom) / is->width;
+    new_bucket = (wstats->newest_time - is->bottom) / is->width;
+    if (new_bucket == when_bucket) {
+      int64_t bottom_bucket_time = is->bottom + when_bucket * is->width;
+      if (when_ns < wstats->newest_time) {
+        last_proportion = (double)(when_ns - bottom_bucket_time) /
+                          (double)(wstats->newest_time - bottom_bucket_time);
+        bottom_proportion =
+            (double)(is->width - (when_ns - bottom_bucket_time)) / is->width;
+      } else {
+        bottom_proportion =
+            (double)(is->width - (wstats->newest_time - bottom_bucket_time)) /
+            is->width;
+      }
+    } else {
+      last_proportion =
+          (double)(when_ns + 1 - is->bottom - when_bucket * is->width) /
+          is->width;
+      bottom_proportion = 1.0 - last_proportion;
+    }
+    cws_add_proportion_to_sum(last_proportion, sum,
+                              is->buckets + BUCKET_IDX(is, when_bucket, wstats),
+                              &wstats->stat_info);
+    if (when_bucket != 0) { /* last bucket isn't also bottom bucket */
+      int b;
+      /* Add all of "bottom" bucket if we are looking at a subset of the
+         full interval, or a proportion if we are adding full interval. */
+      cws_add_proportion_to_sum(
+          (when_bucket == wstats->nbuckets - 1 ? bottom_proportion : 1.0), sum,
+          is->buckets + is->bottom_bucket, &wstats->stat_info);
+      /* Add all the remaining buckets (everything but top and bottom). */
+      for (b = 1; b < when_bucket; b++) {
+        cws_add_bucket_to_sum(sum, is->buckets + BUCKET_IDX(is, b, wstats),
+                              &wstats->stat_info);
+      }
+    }
+  }
+}
+
+void census_window_stats_destroy(window_stats *wstats) {
+  int i;
+  GPR_ASSERT(wstats->interval_stats != NULL);
+  for (i = 0; i < wstats->nintervals; i++) {
+    int b;
+    for (b = 0; b < wstats->nbuckets; b++) {
+      gpr_free(wstats->interval_stats[i].buckets[b].statistic);
+    }
+    gpr_free(wstats->interval_stats[i].buckets);
+  }
+  gpr_free(wstats->interval_stats);
+  /* Ensure any use-after free triggers assert. */
+  wstats->interval_stats = NULL;
+  gpr_free(wstats);
+}
diff --git a/src/core/lib/statistics/window_stats.h b/src/core/lib/statistics/window_stats.h
new file mode 100644
index 0000000..8dec50d
--- /dev/null
+++ b/src/core/lib/statistics/window_stats.h
@@ -0,0 +1,173 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_STATISTICS_WINDOW_STATS_H
+#define GRPC_CORE_LIB_STATISTICS_WINDOW_STATS_H
+
+#include <grpc/support/time.h>
+
+/* Keep rolling sums of a user-defined statistic (containing a number of
+   measurements) over a a number of time intervals ("windows"). For example,
+   you can use a window_stats object to answer questions such as
+   "Approximately how many RPCs/s did I receive over the past minute, and
+   approximately how many bytes did I send out over that period?".
+
+   The type of data to record, and the time intervals to keep are specified
+   when creating the object via a call to census_window_stats_create().
+
+   A window's interval is divided into one or more "buckets"; the interval
+   must be divisible by the number of buckets. Internally, these buckets
+   control the granularity of window_stats' measurements. Increasing the
+   number of buckets lets the object respond more quickly to changes in the
+   overall rate of data added into the object, at the cost of additional
+   memory usage.
+
+   Here's some code which keeps one minute/hour measurements for two values
+   (latency in seconds and bytes transferred), with each interval divided into
+   4 buckets.
+
+    typedef struct my_stat {
+      double latency;
+      int bytes;
+    } my_stat;
+
+    void add_my_stat(void* base, const void* addme) {
+      my_stat* b = (my_stat*)base;
+      const my_stat* a = (const my_stat*)addme;
+      b->latency += a->latency;
+      b->bytes += a->bytes;
+    }
+
+    void add_proportion_my_stat(double p, void* base, const void* addme) {
+      (my_stat*)result->latency += p * (const my_stat*)base->latency;
+      (my_stat*)result->bytes += p * (const my_stat*)base->bytes;
+    }
+
+    #define kNumIntervals 2
+    #define kMinInterval 0
+    #define kHourInterval 1
+    #define kNumBuckets 4
+
+    const struct census_window_stats_stat_info kMyStatInfo
+        = { sizeof(my_stat), NULL, add_my_stat, add_proportion_my_stat };
+    gpr_timespec intervals[kNumIntervals] = {{60, 0}, {3600, 0}};
+    my_stat stat;
+    my_stat sums[kNumIntervals];
+    census_window_stats_sums result[kNumIntervals];
+    struct census_window_stats* stats
+        = census_window_stats_create(kNumIntervals, intervals, kNumBuckets,
+                                     &kMyStatInfo);
+    // Record a new event, taking 15.3ms, transferring 1784 bytes.
+    stat.latency = 0.153;
+    stat.bytes = 1784;
+    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(GPR_CLOCK_REALTIME), result);
+    printf("%d events/min, average time %gs, average bytes %g\n",
+           result[kMinInterval].count,
+           (my_stat*)result[kMinInterval].statistic->latency /
+             result[kMinInterval].count,
+           (my_stat*)result[kMinInterval].statistic->bytes /
+             result[kMinInterval].count
+          );
+    printf("%d events/hr, average time %gs, average bytes %g\n",
+           result[kHourInterval].count,
+           (my_stat*)result[kHourInterval].statistic->latency /
+             result[kHourInterval].count,
+           (my_stat*)result[kHourInterval].statistic->bytes /
+             result[kHourInterval].count
+          );
+*/
+
+/* Opaque structure for representing window_stats object */
+struct census_window_stats;
+
+/* Information provided by API user on the information they want to record */
+typedef struct census_window_stats_stat_info {
+  /* Number of bytes in user-defined object. */
+  size_t stat_size;
+  /* Function to initialize a user-defined statistics object. If this is set
+   * to NULL, then the object will be zero-initialized. */
+  void (*stat_initialize)(void *stat);
+  /* Function to add one user-defined statistics object ('addme') to 'base' */
+  void (*stat_add)(void *base, const void *addme);
+  /* As for previous function, but only add a proportion 'p'. This API will
+     currently only use 'p' values in the range [0,1], but other values are
+     possible in the future, and should be supported. */
+  void (*stat_add_proportion)(double p, void *base, const void *addme);
+} census_window_stats_stat_info;
+
+/* Create a new window_stats object. 'nintervals' is the number of
+   'intervals', and must be >=1. 'granularity' is the number of buckets, with
+   a larger number using more memory, but providing greater accuracy of
+   results. 'granularity should be > 2. We also require that each interval be
+   at least 10 * 'granularity' nanoseconds in size. 'stat_info' contains
+   information about the statistic to be gathered. Intervals greater than ~192
+   years will be treated as essentially infinite in size. This function will
+   GPR_ASSERT() if the object cannot be created or any of the parameters have
+   invalid values. This function is thread-safe. */
+struct census_window_stats *census_window_stats_create(
+    int nintervals, const gpr_timespec intervals[], int granularity,
+    const census_window_stats_stat_info *stat_info);
+
+/* Add a new measurement (in 'stat_value'), as of a given time ('when').
+   This function is thread-compatible. */
+void census_window_stats_add(struct census_window_stats *wstats,
+                             const gpr_timespec when, const void *stat_value);
+
+/* Structure used to record a single intervals sum for a given statistic */
+typedef struct census_window_stats_sum {
+  /* Total count of samples. Note that because some internal interpolation
+     is performed, the count of samples returned for each interval may not be an
+     integral value. */
+  double count;
+  /* Sum for statistic */
+  void *statistic;
+} census_window_stats_sums;
+
+/* Retrieve a set of all values stored in a window_stats object 'wstats'. The
+   number of 'sums' MUST be the same as the number 'nintervals' used in
+   census_window_stats_create(). This function is thread-compatible. */
+void census_window_stats_get_sums(const struct census_window_stats *wstats,
+                                  const gpr_timespec when,
+                                  struct census_window_stats_sum sums[]);
+
+/* Destroy a window_stats object. Once this function has been called, the
+   object will no longer be usable from any of the above functions (and
+   calling them will most likely result in a NULL-pointer dereference or
+   assertion failure). This function is thread-compatible. */
+void census_window_stats_destroy(struct census_window_stats *wstats);
+
+#endif /* GRPC_CORE_LIB_STATISTICS_WINDOW_STATS_H */
diff --git a/src/core/lib/support/alloc.c b/src/core/lib/support/alloc.c
new file mode 100644
index 0000000..27fa6a9
--- /dev/null
+++ b/src/core/lib/support/alloc.c
@@ -0,0 +1,90 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/alloc.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <stdlib.h>
+#include "src/core/lib/profiling/timers.h"
+
+static gpr_allocation_functions g_alloc_functions = {malloc, realloc, free};
+
+gpr_allocation_functions gpr_get_allocation_functions() {
+  return g_alloc_functions;
+}
+
+void gpr_set_allocation_functions(gpr_allocation_functions functions) {
+  GPR_ASSERT(functions.malloc_fn != NULL);
+  GPR_ASSERT(functions.realloc_fn != NULL);
+  GPR_ASSERT(functions.free_fn != NULL);
+  g_alloc_functions = functions;
+}
+
+void *gpr_malloc(size_t size) {
+  void *p;
+  GPR_TIMER_BEGIN("gpr_malloc", 0);
+  p = g_alloc_functions.malloc_fn(size);
+  if (!p) {
+    abort();
+  }
+  GPR_TIMER_END("gpr_malloc", 0);
+  return p;
+}
+
+void gpr_free(void *p) {
+  GPR_TIMER_BEGIN("gpr_free", 0);
+  g_alloc_functions.free_fn(p);
+  GPR_TIMER_END("gpr_free", 0);
+}
+
+void *gpr_realloc(void *p, size_t size) {
+  GPR_TIMER_BEGIN("gpr_realloc", 0);
+  p = g_alloc_functions.realloc_fn(p, size);
+  if (!p) {
+    abort();
+  }
+  GPR_TIMER_END("gpr_realloc", 0);
+  return p;
+}
+
+void *gpr_malloc_aligned(size_t size, size_t alignment_log) {
+  size_t alignment = ((size_t)1) << alignment_log;
+  size_t extra = alignment - 1 + sizeof(void *);
+  void *p = gpr_malloc(size + extra);
+  void **ret = (void **)(((uintptr_t)p + extra) & ~(alignment - 1));
+  ret[-1] = p;
+  return (void *)ret;
+}
+
+void gpr_free_aligned(void *ptr) { gpr_free(((void **)ptr)[-1]); }
diff --git a/src/core/support/avl.c b/src/core/lib/support/avl.c
similarity index 100%
rename from src/core/support/avl.c
rename to src/core/lib/support/avl.c
diff --git a/src/core/lib/support/backoff.c b/src/core/lib/support/backoff.c
new file mode 100644
index 0000000..e89ef47
--- /dev/null
+++ b/src/core/lib/support/backoff.c
@@ -0,0 +1,76 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/support/backoff.h"
+
+#include <grpc/support/useful.h>
+
+void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter,
+                      int64_t min_timeout_millis, int64_t max_timeout_millis) {
+  backoff->multiplier = multiplier;
+  backoff->jitter = jitter;
+  backoff->min_timeout_millis = min_timeout_millis;
+  backoff->max_timeout_millis = max_timeout_millis;
+  backoff->rng_state = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
+}
+
+gpr_timespec gpr_backoff_begin(gpr_backoff *backoff, gpr_timespec now) {
+  backoff->current_timeout_millis = backoff->min_timeout_millis;
+  return gpr_time_add(
+      now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN));
+}
+
+/* Generate a random number between 0 and 1. */
+static double generate_uniform_random_number(uint32_t *rng_state) {
+  *rng_state = (1103515245 * *rng_state + 12345) % ((uint32_t)1 << 31);
+  return *rng_state / (double)((uint32_t)1 << 31);
+}
+
+gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now) {
+  double new_timeout_millis =
+      backoff->multiplier * (double)backoff->current_timeout_millis;
+  double jitter_range = backoff->jitter * new_timeout_millis;
+  double jitter =
+      (2 * generate_uniform_random_number(&backoff->rng_state) - 1) *
+      jitter_range;
+  backoff->current_timeout_millis =
+      GPR_CLAMP((int64_t)(new_timeout_millis + jitter),
+                backoff->min_timeout_millis, backoff->max_timeout_millis);
+  return gpr_time_add(
+      now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN));
+}
+
+void gpr_backoff_reset(gpr_backoff *backoff) {
+  // forces step() to return a timeout of min_timeout_millis
+  backoff->current_timeout_millis = 0;
+}
diff --git a/src/core/lib/support/backoff.h b/src/core/lib/support/backoff.h
new file mode 100644
index 0000000..6d40c15
--- /dev/null
+++ b/src/core/lib/support/backoff.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_BACKOFF_H
+#define GRPC_CORE_LIB_SUPPORT_BACKOFF_H
+
+#include <grpc/support/time.h>
+
+typedef struct {
+  /// const: multiplier between retry attempts
+  double multiplier;
+  /// const: amount to randomize backoffs
+  double jitter;
+  /// const: minimum time between retries in milliseconds
+  int64_t min_timeout_millis;
+  /// const: maximum time between retries in milliseconds
+  int64_t max_timeout_millis;
+
+  /// random number generator
+  uint32_t rng_state;
+
+  /// current retry timeout in milliseconds
+  int64_t current_timeout_millis;
+} gpr_backoff;
+
+/// Initialize backoff machinery - does not need to be destroyed
+void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter,
+                      int64_t min_timeout_millis, int64_t max_timeout_millis);
+
+/// Begin retry loop: returns a timespec for the NEXT retry
+gpr_timespec gpr_backoff_begin(gpr_backoff *backoff, gpr_timespec now);
+/// Step a retry loop: returns a timespec for the NEXT retry
+gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now);
+/// Reset the backoff, so the next gpr_backoff_step will be a gpr_backoff_begin
+/// instead
+void gpr_backoff_reset(gpr_backoff *backoff);
+
+#endif /* GRPC_CORE_LIB_SUPPORT_BACKOFF_H */
diff --git a/src/core/lib/support/block_annotate.h b/src/core/lib/support/block_annotate.h
new file mode 100644
index 0000000..bd30716
--- /dev/null
+++ b/src/core/lib/support/block_annotate.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_BLOCK_ANNOTATE_H
+#define GRPC_CORE_LIB_SUPPORT_BLOCK_ANNOTATE_H
+
+/* These annotations identify the beginning and end of regions where
+   the code may block for reasons other than synchronization functions.
+   These include poll, epoll, and getaddrinfo. */
+
+#define GRPC_SCHEDULING_START_BLOCKING_REGION \
+  do {                                        \
+  } while (0)
+#define GRPC_SCHEDULING_END_BLOCKING_REGION \
+  do {                                      \
+  } while (0)
+
+#endif /* GRPC_CORE_LIB_SUPPORT_BLOCK_ANNOTATE_H */
diff --git a/src/core/lib/support/cmdline.c b/src/core/lib/support/cmdline.c
new file mode 100644
index 0000000..35c4990
--- /dev/null
+++ b/src/core/lib/support/cmdline.c
@@ -0,0 +1,347 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/cmdline.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include "src/core/lib/support/string.h"
+
+typedef enum { ARGTYPE_INT, ARGTYPE_BOOL, ARGTYPE_STRING } argtype;
+
+typedef struct arg {
+  const char *name;
+  const char *help;
+  argtype type;
+  void *value;
+  struct arg *next;
+} arg;
+
+struct gpr_cmdline {
+  const char *description;
+  arg *args;
+  const char *argv0;
+
+  const char *extra_arg_name;
+  const char *extra_arg_help;
+  void (*extra_arg)(void *user_data, const char *arg);
+  void *extra_arg_user_data;
+
+  int (*state)(gpr_cmdline *cl, char *arg);
+  arg *cur_arg;
+
+  int survive_failure;
+};
+
+static int normal_state(gpr_cmdline *cl, char *arg);
+
+gpr_cmdline *gpr_cmdline_create(const char *description) {
+  gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline));
+  memset(cl, 0, sizeof(gpr_cmdline));
+
+  cl->description = description;
+  cl->state = normal_state;
+
+  return cl;
+}
+
+void gpr_cmdline_set_survive_failure(gpr_cmdline *cl) {
+  cl->survive_failure = 1;
+}
+
+void gpr_cmdline_destroy(gpr_cmdline *cl) {
+  while (cl->args) {
+    arg *a = cl->args;
+    cl->args = a->next;
+    gpr_free(a);
+  }
+  gpr_free(cl);
+}
+
+static void add_arg(gpr_cmdline *cl, const char *name, const char *help,
+                    argtype type, void *value) {
+  arg *a;
+
+  for (a = cl->args; a; a = a->next) {
+    GPR_ASSERT(0 != strcmp(a->name, name));
+  }
+
+  a = gpr_malloc(sizeof(arg));
+  memset(a, 0, sizeof(arg));
+  a->name = name;
+  a->help = help;
+  a->type = type;
+  a->value = value;
+  a->next = cl->args;
+  cl->args = a;
+}
+
+void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name, const char *help,
+                         int *value) {
+  add_arg(cl, name, help, ARGTYPE_INT, value);
+}
+
+void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name, const char *help,
+                          int *value) {
+  add_arg(cl, name, help, ARGTYPE_BOOL, value);
+}
+
+void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help,
+                            char **value) {
+  add_arg(cl, name, help, ARGTYPE_STRING, value);
+}
+
+void gpr_cmdline_on_extra_arg(
+    gpr_cmdline *cl, const char *name, const char *help,
+    void (*on_extra_arg)(void *user_data, const char *arg), void *user_data) {
+  GPR_ASSERT(!cl->extra_arg);
+  GPR_ASSERT(on_extra_arg);
+
+  cl->extra_arg = on_extra_arg;
+  cl->extra_arg_user_data = user_data;
+  cl->extra_arg_name = name;
+  cl->extra_arg_help = help;
+}
+
+/* recursively descend argument list, adding the last element
+   to s first - so that arguments are added in the order they were
+   added to the list by api calls */
+static void add_args_to_usage(gpr_strvec *s, arg *a) {
+  char *tmp;
+
+  if (!a) return;
+  add_args_to_usage(s, a->next);
+
+  switch (a->type) {
+    case ARGTYPE_BOOL:
+      gpr_asprintf(&tmp, " [--%s|--no-%s]", a->name, a->name);
+      gpr_strvec_add(s, tmp);
+      break;
+    case ARGTYPE_STRING:
+      gpr_asprintf(&tmp, " [--%s=string]", a->name);
+      gpr_strvec_add(s, tmp);
+      break;
+    case ARGTYPE_INT:
+      gpr_asprintf(&tmp, " [--%s=int]", a->name);
+      gpr_strvec_add(s, tmp);
+      break;
+  }
+}
+
+char *gpr_cmdline_usage_string(gpr_cmdline *cl, const char *argv0) {
+  /* TODO(ctiller): make this prettier */
+  gpr_strvec s;
+  char *tmp;
+  const char *name = strrchr(argv0, '/');
+
+  if (name) {
+    name++;
+  } else {
+    name = argv0;
+  }
+
+  gpr_strvec_init(&s);
+
+  gpr_asprintf(&tmp, "Usage: %s", name);
+  gpr_strvec_add(&s, tmp);
+  add_args_to_usage(&s, cl->args);
+  if (cl->extra_arg) {
+    gpr_asprintf(&tmp, " [%s...]", cl->extra_arg_name);
+    gpr_strvec_add(&s, tmp);
+  }
+  gpr_strvec_add(&s, gpr_strdup("\n"));
+
+  tmp = gpr_strvec_flatten(&s, NULL);
+  gpr_strvec_destroy(&s);
+  return tmp;
+}
+
+static int print_usage_and_die(gpr_cmdline *cl) {
+  char *usage = gpr_cmdline_usage_string(cl, cl->argv0);
+  fprintf(stderr, "%s", usage);
+  gpr_free(usage);
+  if (!cl->survive_failure) {
+    exit(1);
+  }
+  return 0;
+}
+
+static int extra_state(gpr_cmdline *cl, char *str) {
+  if (!cl->extra_arg) {
+    return print_usage_and_die(cl);
+  }
+  cl->extra_arg(cl->extra_arg_user_data, str);
+  return 1;
+}
+
+static arg *find_arg(gpr_cmdline *cl, char *name) {
+  arg *a;
+
+  for (a = cl->args; a; a = a->next) {
+    if (0 == strcmp(a->name, name)) {
+      break;
+    }
+  }
+
+  if (!a) {
+    fprintf(stderr, "Unknown argument: %s\n", name);
+    return NULL;
+  }
+
+  return a;
+}
+
+static int value_state(gpr_cmdline *cl, char *str) {
+  long intval;
+  char *end;
+
+  GPR_ASSERT(cl->cur_arg);
+
+  switch (cl->cur_arg->type) {
+    case ARGTYPE_INT:
+      intval = strtol(str, &end, 0);
+      if (*end || intval < INT_MIN || intval > INT_MAX) {
+        fprintf(stderr, "expected integer, got '%s' for %s\n", str,
+                cl->cur_arg->name);
+        return print_usage_and_die(cl);
+      }
+      *(int *)cl->cur_arg->value = (int)intval;
+      break;
+    case ARGTYPE_BOOL:
+      if (0 == strcmp(str, "1") || 0 == strcmp(str, "true")) {
+        *(int *)cl->cur_arg->value = 1;
+      } else if (0 == strcmp(str, "0") || 0 == strcmp(str, "false")) {
+        *(int *)cl->cur_arg->value = 0;
+      } else {
+        fprintf(stderr, "expected boolean, got '%s' for %s\n", str,
+                cl->cur_arg->name);
+        return print_usage_and_die(cl);
+      }
+      break;
+    case ARGTYPE_STRING:
+      *(char **)cl->cur_arg->value = str;
+      break;
+  }
+
+  cl->state = normal_state;
+  return 1;
+}
+
+static int normal_state(gpr_cmdline *cl, char *str) {
+  char *eq = NULL;
+  char *tmp = NULL;
+  char *arg_name = NULL;
+  int r = 1;
+
+  if (0 == strcmp(str, "-help") || 0 == strcmp(str, "--help") ||
+      0 == strcmp(str, "-h")) {
+    return print_usage_and_die(cl);
+  }
+
+  cl->cur_arg = NULL;
+
+  if (str[0] == '-') {
+    if (str[1] == '-') {
+      if (str[2] == 0) {
+        /* handle '--' to move to just extra args */
+        cl->state = extra_state;
+        return 1;
+      }
+      str += 2;
+    } else {
+      str += 1;
+    }
+    /* first byte of str is now past the leading '-' or '--' */
+    if (str[0] == 'n' && str[1] == 'o' && str[2] == '-') {
+      /* str is of the form '--no-foo' - it's a flag disable */
+      str += 3;
+      cl->cur_arg = find_arg(cl, str);
+      if (cl->cur_arg == NULL) {
+        return print_usage_and_die(cl);
+      }
+      if (cl->cur_arg->type != ARGTYPE_BOOL) {
+        fprintf(stderr, "%s is not a flag argument\n", str);
+        return print_usage_and_die(cl);
+      }
+      *(int *)cl->cur_arg->value = 0;
+      return 1; /* early out */
+    }
+    eq = strchr(str, '=');
+    if (eq != NULL) {
+      /* copy the string into a temp buffer and extract the name */
+      tmp = arg_name = gpr_malloc((size_t)(eq - str + 1));
+      memcpy(arg_name, str, (size_t)(eq - str));
+      arg_name[eq - str] = 0;
+    } else {
+      arg_name = str;
+    }
+    cl->cur_arg = find_arg(cl, arg_name);
+    if (cl->cur_arg == NULL) {
+      return print_usage_and_die(cl);
+    }
+    if (eq != NULL) {
+      /* str was of the type --foo=value, parse the value */
+      r = value_state(cl, eq + 1);
+    } else if (cl->cur_arg->type != ARGTYPE_BOOL) {
+      /* flag types don't have a '--foo value' variant, other types do */
+      cl->state = value_state;
+    } else {
+      /* flag parameter: just set the value */
+      *(int *)cl->cur_arg->value = 1;
+    }
+  } else {
+    r = extra_state(cl, str);
+  }
+
+  gpr_free(tmp);
+  return r;
+}
+
+int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) {
+  int i;
+
+  GPR_ASSERT(argc >= 1);
+  cl->argv0 = argv[0];
+
+  for (i = 1; i < argc; i++) {
+    if (!cl->state(cl, argv[i])) {
+      return 0;
+    }
+  }
+  return 1;
+}
diff --git a/src/core/lib/support/cpu_iphone.c b/src/core/lib/support/cpu_iphone.c
new file mode 100644
index 0000000..e83191b
--- /dev/null
+++ b/src/core/lib/support/cpu_iphone.c
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_CPU_IPHONE
+
+/* Probably 2 instead of 1, but see comment on gpr_cpu_current_cpu. */
+unsigned gpr_cpu_num_cores(void) { return 1; }
+
+/* Most code that's using this is using it to shard across work queues. So
+   unless profiling shows it's a problem or there appears a way to detect the
+   currently running CPU core, let's have it shard the default way.
+   Note that the interface in cpu.h lets gpr_cpu_num_cores return 0, but doing
+   it makes it impossible for gpr_cpu_current_cpu to satisfy its stated range,
+   and some code might be relying on it. */
+unsigned gpr_cpu_current_cpu(void) { return 0; }
+
+#endif /* GPR_CPU_IPHONE */
diff --git a/src/core/lib/support/cpu_linux.c b/src/core/lib/support/cpu_linux.c
new file mode 100644
index 0000000..5597df2
--- /dev/null
+++ b/src/core/lib/support/cpu_linux.c
@@ -0,0 +1,78 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif /* _GNU_SOURCE */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_CPU_LINUX
+
+#include <errno.h>
+#include <sched.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/support/cpu.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+static int ncpus = 0;
+
+static void init_num_cpus() {
+  /* 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;
+  }
+}
+
+unsigned gpr_cpu_num_cores(void) {
+  static gpr_once once = GPR_ONCE_INIT;
+  gpr_once_init(&once, init_num_cpus);
+  return (unsigned)ncpus;
+}
+
+unsigned gpr_cpu_current_cpu(void) {
+  int cpu = sched_getcpu();
+  if (cpu < 0) {
+    gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno));
+    return 0;
+  }
+  return (unsigned)cpu;
+}
+
+#endif /* GPR_CPU_LINUX */
diff --git a/src/core/lib/support/cpu_posix.c b/src/core/lib/support/cpu_posix.c
new file mode 100644
index 0000000..e508ddd
--- /dev/null
+++ b/src/core/lib/support/cpu_posix.c
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_CPU_POSIX
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+static __thread char magic_thread_local;
+
+static long ncpus = 0;
+
+static void init_ncpus() {
+  ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+  if (ncpus < 1 || ncpus > INT32_MAX) {
+    gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1");
+    ncpus = 1;
+  }
+}
+
+unsigned gpr_cpu_num_cores(void) {
+  static gpr_once once = GPR_ONCE_INIT;
+  gpr_once_init(&once, init_ncpus);
+  return (unsigned)ncpus;
+}
+
+/* This is a cheap, but good enough, pointer hash for sharding things: */
+static size_t shard_ptr(const void *info) {
+  size_t x = (size_t)info;
+  return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) % gpr_cpu_num_cores();
+}
+
+unsigned gpr_cpu_current_cpu(void) {
+  /* NOTE: there's no way I know to return the actual cpu index portably...
+     most code that's using this is using it to shard across work queues though,
+     so here we use thread identity instead to achieve a similar though not
+     identical effect */
+  return (unsigned)shard_ptr(&magic_thread_local);
+}
+
+#endif /* GPR_CPU_POSIX */
diff --git a/src/core/lib/support/cpu_windows.c b/src/core/lib/support/cpu_windows.c
new file mode 100644
index 0000000..0f84a9e
--- /dev/null
+++ b/src/core/lib/support/cpu_windows.c
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+#include <grpc/support/log.h>
+
+unsigned gpr_cpu_num_cores(void) {
+  SYSTEM_INFO si;
+  GetSystemInfo(&si);
+  return si.dwNumberOfProcessors;
+}
+
+unsigned gpr_cpu_current_cpu(void) { return GetCurrentProcessorNumber(); }
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/lib/support/env.h b/src/core/lib/support/env.h
new file mode 100644
index 0000000..ddc4ee3
--- /dev/null
+++ b/src/core/lib/support/env.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_ENV_H
+#define GRPC_CORE_LIB_SUPPORT_ENV_H
+
+#include <stdio.h>
+
+#include <grpc/support/slice.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Env utility functions */
+
+/* Gets the environment variable value with the specified name.
+   Returns a newly allocated string. It is the responsability of the caller to
+   gpr_free the return value if not NULL (which means that the environment
+   variable exists). */
+char *gpr_getenv(const char *name);
+
+/* Sets the the environment with the specified name to the specified value. */
+void gpr_setenv(const char *name, const char *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_SUPPORT_ENV_H */
diff --git a/src/core/lib/support/env_linux.c b/src/core/lib/support/env_linux.c
new file mode 100644
index 0000000..a86133e
--- /dev/null
+++ b/src/core/lib/support/env_linux.c
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* for secure_getenv. */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_LINUX_ENV
+
+#include "src/core/lib/support/env.h"
+
+#include <dlfcn.h>
+#include <features.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/support/string.h"
+
+char *gpr_getenv(const char *name) {
+#if defined(GPR_BACKWARDS_COMPATIBILITY_MODE)
+  typedef char *(*getenv_type)(const char *);
+  static getenv_type getenv_func = NULL;
+  /* Check to see which getenv variant is supported (go from most
+   * to least secure) */
+  const char *names[] = {"secure_getenv", "__secure_getenv", "getenv"};
+  for (size_t i = 0; getenv_func == NULL && i < GPR_ARRAY_SIZE(names); i++) {
+    getenv_func = (getenv_type)dlsym(RTLD_DEFAULT, names[i]);
+    if (getenv_func != NULL && strstr(names[i], "secure") == NULL) {
+      gpr_log(GPR_DEBUG,
+              "Warning: insecure environment read function '%s' used",
+              names[i]);
+    }
+  }
+  char *result = getenv_func(name);
+  return result == NULL ? result : gpr_strdup(result);
+#elif __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17)
+  char *result = secure_getenv(name);
+  return result == NULL ? result : gpr_strdup(result);
+#else
+  gpr_log(GPR_DEBUG, "Warning: insecure environment read function '%s' used",
+          "getenv");
+  char *result = getenv(name);
+  return result == NULL ? result : gpr_strdup(result);
+#endif
+}
+
+void gpr_setenv(const char *name, const char *value) {
+  int res = setenv(name, value, 1);
+  GPR_ASSERT(res == 0);
+}
+
+#endif /* GPR_LINUX_ENV */
diff --git a/src/core/lib/support/env_posix.c b/src/core/lib/support/env_posix.c
new file mode 100644
index 0000000..1b57b09
--- /dev/null
+++ b/src/core/lib/support/env_posix.c
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_ENV
+
+#include "src/core/lib/support/env.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/log.h>
+
+#include <grpc/support/string_util.h>
+#include "src/core/lib/support/string.h"
+
+char *gpr_getenv(const char *name) {
+  char *result = getenv(name);
+  return result == NULL ? result : gpr_strdup(result);
+}
+
+void gpr_setenv(const char *name, const char *value) {
+  int res = setenv(name, value, 1);
+  GPR_ASSERT(res == 0);
+}
+
+#endif /* GPR_POSIX_ENV */
diff --git a/src/core/lib/support/env_win32.c b/src/core/lib/support/env_win32.c
new file mode 100644
index 0000000..566feee
--- /dev/null
+++ b/src/core/lib/support/env_win32.c
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
+
+#ifdef __MINGW32__
+errno_t getenv_s(size_t *size_needed, char *buffer, size_t size,
+                 const char *varname);
+#else
+#include <stdlib.h>
+#endif
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+char *gpr_getenv(const char *name) {
+  size_t size;
+  char *result = NULL;
+  errno_t err;
+
+  err = getenv_s(&size, NULL, 0, name);
+  if (err || (size == 0)) return NULL;
+  result = gpr_malloc(size);
+  err = getenv_s(&size, result, size, name);
+  if (err) {
+    gpr_free(result);
+    return NULL;
+  }
+  return result;
+}
+
+void gpr_setenv(const char *name, const char *value) {
+  errno_t res = _putenv_s(name, value);
+  GPR_ASSERT(res == 0);
+}
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/lib/support/histogram.c b/src/core/lib/support/histogram.c
new file mode 100644
index 0000000..62227be
--- /dev/null
+++ b/src/core/lib/support/histogram.c
@@ -0,0 +1,244 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/histogram.h>
+
+#include <math.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/useful.h>
+
+/* Histograms are stored with exponentially increasing bucket sizes.
+   The first bucket is [0, m) where m = 1 + resolution
+   Bucket n (n>=1) contains [m**n, m**(n+1))
+   There are sufficient buckets to reach max_bucket_start */
+
+struct gpr_histogram {
+  /* Sum of all values seen so far */
+  double sum;
+  /* Sum of squares of all values seen so far */
+  double sum_of_squares;
+  /* number of values seen so far */
+  double count;
+  /* m in the description */
+  double multiplier;
+  double one_on_log_multiplier;
+  /* minimum value seen */
+  double min_seen;
+  /* maximum value seen */
+  double max_seen;
+  /* maximum representable value */
+  double max_possible;
+  /* number of buckets */
+  size_t num_buckets;
+  /* the buckets themselves */
+  uint32_t *buckets;
+};
+
+/* determine a bucket index given a value - does no bounds checking */
+static size_t bucket_for_unchecked(gpr_histogram *h, double x) {
+  return (size_t)(log(x) * h->one_on_log_multiplier);
+}
+
+/* bounds checked version of the above */
+static size_t bucket_for(gpr_histogram *h, double x) {
+  size_t bucket = bucket_for_unchecked(h, GPR_CLAMP(x, 1.0, h->max_possible));
+  GPR_ASSERT(bucket < h->num_buckets);
+  return bucket;
+}
+
+/* at what value does a bucket start? */
+static double bucket_start(gpr_histogram *h, double x) {
+  return pow(h->multiplier, x);
+}
+
+gpr_histogram *gpr_histogram_create(double resolution,
+                                    double max_bucket_start) {
+  gpr_histogram *h = gpr_malloc(sizeof(gpr_histogram));
+  GPR_ASSERT(resolution > 0.0);
+  GPR_ASSERT(max_bucket_start > resolution);
+  h->sum = 0.0;
+  h->sum_of_squares = 0.0;
+  h->multiplier = 1.0 + resolution;
+  h->one_on_log_multiplier = 1.0 / log(1.0 + resolution);
+  h->max_possible = max_bucket_start;
+  h->count = 0.0;
+  h->min_seen = max_bucket_start;
+  h->max_seen = 0.0;
+  h->num_buckets = bucket_for_unchecked(h, max_bucket_start) + 1;
+  GPR_ASSERT(h->num_buckets > 1);
+  GPR_ASSERT(h->num_buckets < 100000000);
+  h->buckets = gpr_malloc(sizeof(uint32_t) * h->num_buckets);
+  memset(h->buckets, 0, sizeof(uint32_t) * h->num_buckets);
+  return h;
+}
+
+void gpr_histogram_destroy(gpr_histogram *h) {
+  gpr_free(h->buckets);
+  gpr_free(h);
+}
+
+void gpr_histogram_add(gpr_histogram *h, double x) {
+  h->sum += x;
+  h->sum_of_squares += x * x;
+  h->count++;
+  if (x < h->min_seen) {
+    h->min_seen = x;
+  }
+  if (x > h->max_seen) {
+    h->max_seen = x;
+  }
+  h->buckets[bucket_for(h, x)]++;
+}
+
+int gpr_histogram_merge(gpr_histogram *dst, const gpr_histogram *src) {
+  if ((dst->num_buckets != src->num_buckets) ||
+      (dst->multiplier != src->multiplier)) {
+    /* Fail because these histograms don't match */
+    return 0;
+  }
+  gpr_histogram_merge_contents(dst, src->buckets, src->num_buckets,
+                               src->min_seen, src->max_seen, src->sum,
+                               src->sum_of_squares, src->count);
+  return 1;
+}
+
+void gpr_histogram_merge_contents(gpr_histogram *dst, const uint32_t *data,
+                                  size_t data_count, double min_seen,
+                                  double max_seen, double sum,
+                                  double sum_of_squares, double count) {
+  size_t i;
+  GPR_ASSERT(dst->num_buckets == data_count);
+  dst->sum += sum;
+  dst->sum_of_squares += sum_of_squares;
+  dst->count += count;
+  if (min_seen < dst->min_seen) {
+    dst->min_seen = min_seen;
+  }
+  if (max_seen > dst->max_seen) {
+    dst->max_seen = max_seen;
+  }
+  for (i = 0; i < dst->num_buckets; i++) {
+    dst->buckets[i] += data[i];
+  }
+}
+
+static double threshold_for_count_below(gpr_histogram *h, double count_below) {
+  double count_so_far;
+  double lower_bound;
+  double upper_bound;
+  size_t lower_idx;
+  size_t upper_idx;
+
+  if (h->count == 0) {
+    return 0.0;
+  }
+
+  if (count_below <= 0) {
+    return h->min_seen;
+  }
+  if (count_below >= h->count) {
+    return h->max_seen;
+  }
+
+  /* find the lowest bucket that gets us above count_below */
+  count_so_far = 0.0;
+  for (lower_idx = 0; lower_idx < h->num_buckets; lower_idx++) {
+    count_so_far += h->buckets[lower_idx];
+    if (count_so_far >= count_below) {
+      break;
+    }
+  }
+  if (count_so_far == count_below) {
+    /* this bucket hits the threshold exactly... we should be midway through
+       any run of zero values following the bucket */
+    for (upper_idx = lower_idx + 1; upper_idx < h->num_buckets; upper_idx++) {
+      if (h->buckets[upper_idx]) {
+        break;
+      }
+    }
+    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, (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],
+                     h->min_seen, h->max_seen);
+  }
+}
+
+double gpr_histogram_percentile(gpr_histogram *h, double percentile) {
+  return threshold_for_count_below(h, h->count * percentile / 100.0);
+}
+
+double gpr_histogram_mean(gpr_histogram *h) {
+  GPR_ASSERT(h->count != 0);
+  return h->sum / h->count;
+}
+
+double gpr_histogram_stddev(gpr_histogram *h) {
+  return sqrt(gpr_histogram_variance(h));
+}
+
+double gpr_histogram_variance(gpr_histogram *h) {
+  if (h->count == 0) return 0.0;
+  return (h->sum_of_squares * h->count - h->sum * h->sum) /
+         (h->count * h->count);
+}
+
+double gpr_histogram_maximum(gpr_histogram *h) { return h->max_seen; }
+
+double gpr_histogram_minimum(gpr_histogram *h) { return h->min_seen; }
+
+double gpr_histogram_count(gpr_histogram *h) { return h->count; }
+
+double gpr_histogram_sum(gpr_histogram *h) { return h->sum; }
+
+double gpr_histogram_sum_of_squares(gpr_histogram *h) {
+  return h->sum_of_squares;
+}
+
+const uint32_t *gpr_histogram_get_contents(gpr_histogram *h, size_t *size) {
+  *size = h->num_buckets;
+  return h->buckets;
+}
diff --git a/src/core/lib/support/host_port.c b/src/core/lib/support/host_port.c
new file mode 100644
index 0000000..e03f624
--- /dev/null
+++ b/src/core/lib/support/host_port.c
@@ -0,0 +1,110 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/host_port.h>
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include "src/core/lib/support/string.h"
+
+int gpr_join_host_port(char **out, const char *host, int port) {
+  if (host[0] != '[' && strchr(host, ':') != NULL) {
+    /* IPv6 literals must be enclosed in brackets. */
+    return gpr_asprintf(out, "[%s]:%d", host, port);
+  } else {
+    /* Ordinary non-bracketed host:port. */
+    return gpr_asprintf(out, "%s:%d", host, port);
+  }
+}
+
+int gpr_split_host_port(const char *name, char **host, char **port) {
+  const char *host_start;
+  size_t host_len;
+  const char *port_start;
+
+  *host = NULL;
+  *port = NULL;
+
+  if (name[0] == '[') {
+    /* Parse a bracketed host, typically an IPv6 literal. */
+    const char *rbracket = strchr(name, ']');
+    if (rbracket == NULL) {
+      /* Unmatched [ */
+      return 0;
+    }
+    if (rbracket[1] == '\0') {
+      /* ]<end> */
+      port_start = NULL;
+    } else if (rbracket[1] == ':') {
+      /* ]:<port?> */
+      port_start = rbracket + 2;
+    } else {
+      /* ]<invalid> */
+      return 0;
+    }
+    host_start = name + 1;
+    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. */
+      return 0;
+    }
+  } else {
+    const char *colon = strchr(name, ':');
+    if (colon != NULL && strchr(colon + 1, ':') == NULL) {
+      /* Exactly 1 colon.  Split into host:port. */
+      host_start = name;
+      host_len = (size_t)(colon - name);
+      port_start = colon + 1;
+    } else {
+      /* 0 or 2+ colons.  Bare hostname or IPv6 litearal. */
+      host_start = name;
+      host_len = strlen(name);
+      port_start = NULL;
+    }
+  }
+
+  /* Allocate return values. */
+  *host = gpr_malloc(host_len + 1);
+  memcpy(*host, host_start, host_len);
+  (*host)[host_len] = '\0';
+
+  if (port_start != NULL) {
+    *port = gpr_strdup(port_start);
+  }
+
+  return 1;
+}
diff --git a/src/core/lib/support/load_file.c b/src/core/lib/support/load_file.c
new file mode 100644
index 0000000..0cecd5e
--- /dev/null
+++ b/src/core/lib/support/load_file.c
@@ -0,0 +1,91 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/support/load_file.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/support/block_annotate.h"
+#include "src/core/lib/support/string.h"
+
+gpr_slice gpr_load_file(const char *filename, int add_null_terminator,
+                        int *success) {
+  unsigned char *contents = NULL;
+  size_t contents_size = 0;
+  char *error_msg = NULL;
+  gpr_slice result = gpr_empty_slice();
+  FILE *file;
+  size_t bytes_read = 0;
+
+  GRPC_SCHEDULING_START_BLOCKING_REGION;
+  file = fopen(filename, "rb");
+  if (file == NULL) {
+    gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename,
+                 strerror(errno));
+    GPR_ASSERT(error_msg != NULL);
+    goto end;
+  }
+  fseek(file, 0, SEEK_END);
+  /* 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);
+  if (bytes_read < contents_size) {
+    GPR_ASSERT(ferror(file));
+    gpr_asprintf(&error_msg, "Error %s occured while reading file %s.",
+                 strerror(errno), filename);
+    GPR_ASSERT(error_msg != NULL);
+    goto end;
+  }
+  if (success != NULL) *success = 1;
+  if (add_null_terminator) {
+    contents[contents_size++] = 0;
+  }
+  result = gpr_slice_new(contents, contents_size, gpr_free);
+
+end:
+  if (error_msg != NULL) {
+    gpr_log(GPR_ERROR, "%s", error_msg);
+    gpr_free(error_msg);
+    if (success != NULL) *success = 0;
+  }
+  if (file != NULL) fclose(file);
+  GRPC_SCHEDULING_END_BLOCKING_REGION;
+  return result;
+}
diff --git a/src/core/lib/support/load_file.h b/src/core/lib/support/load_file.h
new file mode 100644
index 0000000..fe030c9
--- /dev/null
+++ b/src/core/lib/support/load_file.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_LOAD_FILE_H
+#define GRPC_CORE_LIB_SUPPORT_LOAD_FILE_H
+
+#include <stdio.h>
+
+#include <grpc/support/slice.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Loads the content of a file into a slice. add_null_terminator will add
+   a NULL terminator if non-zero. The success parameter, if not NULL,
+   will be set to 1 in case of success and 0 in case of failure. */
+gpr_slice gpr_load_file(const char *filename, int add_null_terminator,
+                        int *success);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_SUPPORT_LOAD_FILE_H */
diff --git a/src/core/lib/support/log.c b/src/core/lib/support/log.c
new file mode 100644
index 0000000..cd6a072
--- /dev/null
+++ b/src/core/lib/support/log.c
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+
+#include <stdio.h>
+#include <string.h>
+
+extern void gpr_default_log(gpr_log_func_args *args);
+static gpr_log_func g_log_func = gpr_default_log;
+
+const char *gpr_log_severity_string(gpr_log_severity severity) {
+  switch (severity) {
+    case GPR_LOG_SEVERITY_DEBUG:
+      return "D";
+    case GPR_LOG_SEVERITY_INFO:
+      return "I";
+    case GPR_LOG_SEVERITY_ERROR:
+      return "E";
+  }
+  GPR_UNREACHABLE_CODE(return "UNKNOWN");
+}
+
+void gpr_log_message(const char *file, int line, gpr_log_severity severity,
+                     const char *message) {
+  gpr_log_func_args lfargs;
+  memset(&lfargs, 0, sizeof(lfargs));
+  lfargs.file = file;
+  lfargs.line = line;
+  lfargs.severity = severity;
+  lfargs.message = message;
+  g_log_func(&lfargs);
+}
+
+void gpr_set_log_function(gpr_log_func f) { g_log_func = f; }
diff --git a/src/core/lib/support/log_android.c b/src/core/lib/support/log_android.c
new file mode 100644
index 0000000..640c9d7
--- /dev/null
+++ b/src/core/lib/support/log_android.c
@@ -0,0 +1,87 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_ANDROID
+
+#include <android/log.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+static android_LogPriority severity_to_log_priority(gpr_log_severity severity) {
+  switch (severity) {
+    case GPR_LOG_SEVERITY_DEBUG:
+      return ANDROID_LOG_DEBUG;
+    case GPR_LOG_SEVERITY_INFO:
+      return ANDROID_LOG_INFO;
+    case GPR_LOG_SEVERITY_ERROR:
+      return ANDROID_LOG_ERROR;
+  }
+  return ANDROID_LOG_DEFAULT;
+}
+
+void gpr_log(const char *file, int line, gpr_log_severity severity,
+             const char *format, ...) {
+  char *message = NULL;
+  va_list args;
+  va_start(args, format);
+  vasprintf(&message, format, args);
+  va_end(args);
+  gpr_log_message(file, line, severity, message);
+  free(message);
+}
+
+void gpr_default_log(gpr_log_func_args *args) {
+  char *final_slash;
+  const char *display_file;
+  char *output = NULL;
+
+  final_slash = strrchr(args->file, '/');
+  if (final_slash == NULL)
+    display_file = args->file;
+  else
+    display_file = final_slash + 1;
+
+  asprintf(&output, "%s:%d] %s", display_file, args->line, args->message);
+
+  __android_log_write(severity_to_log_priority(args->severity), "GRPC", output);
+
+  /* allocated by asprintf => use free, not gpr_free */
+  free(output);
+}
+
+#endif /* GPR_ANDROID */
diff --git a/src/core/lib/support/log_linux.c b/src/core/lib/support/log_linux.c
new file mode 100644
index 0000000..e60512c
--- /dev/null
+++ b/src/core/lib/support/log_linux.c
@@ -0,0 +1,105 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _POSIX_SOURCE
+#define _POSIX_SOURCE
+#endif
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <grpc/support/port_platform.h>
+
+#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 <linux/unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <unistd.h>
+
+static long gettid(void) { return syscall(__NR_gettid); }
+
+void gpr_log(const char *file, int line, gpr_log_severity severity,
+             const char *format, ...) {
+  char *message = NULL;
+  va_list args;
+  va_start(args, format);
+  if (vasprintf(&message, format, args) == -1) {
+    va_end(args);
+    return;
+  }
+  va_end(args);
+  gpr_log_message(file, line, severity, message);
+  free(message);
+}
+
+void gpr_default_log(gpr_log_func_args *args) {
+  char *final_slash;
+  char *prefix;
+  const char *display_file;
+  char time_buffer[64];
+  time_t timer;
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
+  struct tm tm;
+
+  timer = (time_t)now.tv_sec;
+  final_slash = strrchr(args->file, '/');
+  if (final_slash == NULL)
+    display_file = args->file;
+  else
+    display_file = final_slash + 1;
+
+  if (!localtime_r(&timer, &tm)) {
+    strcpy(time_buffer, "error:localtime");
+  } else if (0 ==
+             strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
+    strcpy(time_buffer, "error:strftime");
+  }
+
+  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);
+
+  fprintf(stderr, "%-60s %s\n", prefix, args->message);
+  gpr_free(prefix);
+}
+
+#endif
diff --git a/src/core/lib/support/log_posix.c b/src/core/lib/support/log_posix.c
new file mode 100644
index 0000000..7429dd0
--- /dev/null
+++ b/src/core/lib/support/log_posix.c
@@ -0,0 +1,102 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#if defined(GPR_POSIX_LOG)
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+static intptr_t gettid(void) { return (intptr_t)pthread_self(); }
+
+void gpr_log(const char *file, int line, gpr_log_severity severity,
+             const char *format, ...) {
+  char buf[64];
+  char *allocated = NULL;
+  char *message = NULL;
+  int ret;
+  va_list args;
+  va_start(args, format);
+  ret = vsnprintf(buf, sizeof(buf), format, args);
+  va_end(args);
+  if (ret < 0) {
+    message = NULL;
+  } else if ((size_t)ret <= sizeof(buf) - 1) {
+    message = buf;
+  } else {
+    message = allocated = gpr_malloc((size_t)ret + 1);
+    va_start(args, format);
+    vsnprintf(message, (size_t)(ret + 1), format, args);
+    va_end(args);
+  }
+  gpr_log_message(file, line, severity, message);
+  gpr_free(allocated);
+}
+
+void gpr_default_log(gpr_log_func_args *args) {
+  char *final_slash;
+  const char *display_file;
+  char time_buffer[64];
+  time_t timer;
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
+  struct tm tm;
+
+  timer = (time_t)now.tv_sec;
+  final_slash = strrchr(args->file, '/');
+  if (final_slash == NULL)
+    display_file = args->file;
+  else
+    display_file = final_slash + 1;
+
+  if (!localtime_r(&timer, &tm)) {
+    strcpy(time_buffer, "error:localtime");
+  } else if (0 ==
+             strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
+    strcpy(time_buffer, "error:strftime");
+  }
+
+  fprintf(stderr, "%s%s.%09d %7tu %s:%d] %s\n",
+          gpr_log_severity_string(args->severity), time_buffer,
+          (int)(now.tv_nsec), gettid(), display_file, args->line,
+          args->message);
+}
+
+#endif /* defined(GPR_POSIX_LOG) */
diff --git a/src/core/lib/support/log_win32.c b/src/core/lib/support/log_win32.c
new file mode 100644
index 0000000..cec9944
--- /dev/null
+++ b/src/core/lib/support/log_win32.c
@@ -0,0 +1,126 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/log_win32.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/support/string_win32.h"
+
+void gpr_log(const char *file, int line, gpr_log_severity severity,
+             const char *format, ...) {
+  char *message = NULL;
+  va_list args;
+  int ret;
+
+  /* Determine the length. */
+  va_start(args, format);
+  ret = _vscprintf(format, args);
+  va_end(args);
+  if (ret < 0) {
+    message = NULL;
+  } else {
+    /* Allocate a new buffer, with space for the NUL terminator. */
+    size_t strp_buflen = (size_t)ret + 1;
+    message = gpr_malloc(strp_buflen);
+
+    /* Print to the buffer. */
+    va_start(args, format);
+    ret = vsnprintf_s(message, strp_buflen, _TRUNCATE, format, args);
+    va_end(args);
+    if ((size_t)ret != strp_buflen - 1) {
+      /* This should never happen. */
+      gpr_free(message);
+      message = NULL;
+    }
+  }
+
+  gpr_log_message(file, line, severity, message);
+  gpr_free(message);
+}
+
+/* Simple starter implementation */
+void gpr_default_log(gpr_log_func_args *args) {
+  char *final_slash;
+  const char *display_file;
+  char time_buffer[64];
+  time_t timer;
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
+  struct tm tm;
+
+  timer = (time_t)now.tv_sec;
+  final_slash = strrchr(args->file, '\\');
+  if (final_slash == NULL)
+    display_file = args->file;
+  else
+    display_file = final_slash + 1;
+
+  if (localtime_s(&tm, &timer)) {
+    strcpy(time_buffer, "error:localtime");
+  } else if (0 ==
+             strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
+    strcpy(time_buffer, "error:strftime");
+  }
+
+  fprintf(stderr, "%s%s.%09u %5lu %s:%d] %s\n",
+          gpr_log_severity_string(args->severity), time_buffer,
+          (int)(now.tv_nsec), GetCurrentThreadId(), display_file, args->line,
+          args->message);
+  fflush(stderr);
+}
+
+char *gpr_format_message(int messageid) {
+  LPTSTR tmessage;
+  char *message;
+  DWORD status = FormatMessage(
+      FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+          FORMAT_MESSAGE_IGNORE_INSERTS,
+      NULL, (DWORD)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 */
diff --git a/src/core/lib/support/murmur_hash.c b/src/core/lib/support/murmur_hash.c
new file mode 100644
index 0000000..97832f1
--- /dev/null
+++ b/src/core/lib/support/murmur_hash.c
@@ -0,0 +1,96 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/support/murmur_hash.h"
+
+#define ROTL32(x, r) ((x) << (r)) | ((x) >> (32 - (r)))
+
+#define FMIX32(h)    \
+  (h) ^= (h) >> 16;  \
+  (h) *= 0x85ebca6b; \
+  (h) ^= (h) >> 13;  \
+  (h) *= 0xc2b2ae35; \
+  (h) ^= (h) >> 16;
+
+/* Block read - if your platform needs to do endian-swapping or can only
+   handle aligned reads, do the conversion here */
+#define GETBLOCK32(p, i) (p)[(i)]
+
+uint32_t gpr_murmur_hash3(const void *key, size_t len, uint32_t seed) {
+  const uint8_t *data = (const uint8_t *)key;
+  const size_t nblocks = len / 4;
+  int i;
+
+  uint32_t h1 = seed;
+  uint32_t k1;
+
+  const uint32_t c1 = 0xcc9e2d51;
+  const uint32_t c2 = 0x1b873593;
+
+  const uint32_t *blocks = ((const uint32_t *)key) + nblocks;
+  const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
+
+  /* body */
+  for (i = -(int)nblocks; i; i++) {
+    k1 = GETBLOCK32(blocks, i);
+
+    k1 *= c1;
+    k1 = ROTL32(k1, 15);
+    k1 *= c2;
+
+    h1 ^= k1;
+    h1 = ROTL32(h1, 13);
+    h1 = h1 * 5 + 0xe6546b64;
+  }
+
+  k1 = 0;
+
+  /* tail */
+  switch (len & 3) {
+    case 3:
+      k1 ^= ((uint32_t)tail[2]) << 16;
+    case 2:
+      k1 ^= ((uint32_t)tail[1]) << 8;
+    case 1:
+      k1 ^= tail[0];
+      k1 *= c1;
+      k1 = ROTL32(k1, 15);
+      k1 *= c2;
+      h1 ^= k1;
+  };
+
+  /* finalization */
+  h1 ^= (uint32_t)len;
+  FMIX32(h1);
+  return h1;
+}
diff --git a/src/core/lib/support/murmur_hash.h b/src/core/lib/support/murmur_hash.h
new file mode 100644
index 0000000..e54cdf2
--- /dev/null
+++ b/src/core/lib/support/murmur_hash.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_MURMUR_HASH_H
+#define GRPC_CORE_LIB_SUPPORT_MURMUR_HASH_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stddef.h>
+
+/* compute the hash of key (length len) */
+uint32_t gpr_murmur_hash3(const void *key, size_t len, uint32_t seed);
+
+#endif /* GRPC_CORE_LIB_SUPPORT_MURMUR_HASH_H */
diff --git a/src/core/lib/support/slice.c b/src/core/lib/support/slice.c
new file mode 100644
index 0000000..cf3953c
--- /dev/null
+++ b/src/core/lib/support/slice.c
@@ -0,0 +1,343 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+
+#include <string.h>
+
+gpr_slice gpr_empty_slice(void) {
+  gpr_slice out;
+  out.refcount = 0;
+  out.data.inlined.length = 0;
+  return out;
+}
+
+gpr_slice gpr_slice_ref(gpr_slice slice) {
+  if (slice.refcount) {
+    slice.refcount->ref(slice.refcount);
+  }
+  return slice;
+}
+
+void gpr_slice_unref(gpr_slice slice) {
+  if (slice.refcount) {
+    slice.refcount->unref(slice.refcount);
+  }
+}
+
+/* gpr_slice_from_static_string support structure - a refcount that does
+   nothing */
+static void noop_ref_or_unref(void *unused) {}
+
+static gpr_slice_refcount noop_refcount = {noop_ref_or_unref,
+                                           noop_ref_or_unref};
+
+gpr_slice gpr_slice_from_static_string(const char *s) {
+  gpr_slice slice;
+  slice.refcount = &noop_refcount;
+  slice.data.refcounted.bytes = (uint8_t *)s;
+  slice.data.refcounted.length = strlen(s);
+  return slice;
+}
+
+/* gpr_slice_new support structures - we create a refcount object extended
+   with the user provided data pointer & destroy function */
+typedef struct new_slice_refcount {
+  gpr_slice_refcount rc;
+  gpr_refcount refs;
+  void (*user_destroy)(void *);
+  void *user_data;
+} new_slice_refcount;
+
+static void new_slice_ref(void *p) {
+  new_slice_refcount *r = p;
+  gpr_ref(&r->refs);
+}
+
+static void new_slice_unref(void *p) {
+  new_slice_refcount *r = p;
+  if (gpr_unref(&r->refs)) {
+    r->user_destroy(r->user_data);
+    gpr_free(r);
+  }
+}
+
+gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) {
+  gpr_slice slice;
+  new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount));
+  gpr_ref_init(&rc->refs, 1);
+  rc->rc.ref = new_slice_ref;
+  rc->rc.unref = new_slice_unref;
+  rc->user_destroy = destroy;
+  rc->user_data = p;
+
+  slice.refcount = &rc->rc;
+  slice.data.refcounted.bytes = p;
+  slice.data.refcounted.length = len;
+  return slice;
+}
+
+/* gpr_slice_new_with_len support structures - we create a refcount object
+   extended with the user provided data pointer & destroy function */
+typedef struct new_with_len_slice_refcount {
+  gpr_slice_refcount rc;
+  gpr_refcount refs;
+  void *user_data;
+  size_t user_length;
+  void (*user_destroy)(void *, size_t);
+} new_with_len_slice_refcount;
+
+static void new_with_len_ref(void *p) {
+  new_with_len_slice_refcount *r = p;
+  gpr_ref(&r->refs);
+}
+
+static void new_with_len_unref(void *p) {
+  new_with_len_slice_refcount *r = p;
+  if (gpr_unref(&r->refs)) {
+    r->user_destroy(r->user_data, r->user_length);
+    gpr_free(r);
+  }
+}
+
+gpr_slice gpr_slice_new_with_len(void *p, size_t len,
+                                 void (*destroy)(void *, size_t)) {
+  gpr_slice slice;
+  new_with_len_slice_refcount *rc =
+      gpr_malloc(sizeof(new_with_len_slice_refcount));
+  gpr_ref_init(&rc->refs, 1);
+  rc->rc.ref = new_with_len_ref;
+  rc->rc.unref = new_with_len_unref;
+  rc->user_destroy = destroy;
+  rc->user_data = p;
+  rc->user_length = len;
+
+  slice.refcount = &rc->rc;
+  slice.data.refcounted.bytes = p;
+  slice.data.refcounted.length = len;
+  return slice;
+}
+
+gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t length) {
+  gpr_slice slice = gpr_slice_malloc(length);
+  memcpy(GPR_SLICE_START_PTR(slice), source, length);
+  return slice;
+}
+
+gpr_slice gpr_slice_from_copied_string(const char *source) {
+  return gpr_slice_from_copied_buffer(source, strlen(source));
+}
+
+typedef struct {
+  gpr_slice_refcount base;
+  gpr_refcount refs;
+} malloc_refcount;
+
+static void malloc_ref(void *p) {
+  malloc_refcount *r = p;
+  gpr_ref(&r->refs);
+}
+
+static void malloc_unref(void *p) {
+  malloc_refcount *r = p;
+  if (gpr_unref(&r->refs)) {
+    gpr_free(r);
+  }
+}
+
+gpr_slice gpr_slice_malloc(size_t length) {
+  gpr_slice slice;
+
+  if (length > sizeof(slice.data.inlined.bytes)) {
+    /* Memory layout used by the slice created here:
+
+       +-----------+----------------------------------------------------------+
+       | refcount  | bytes                                                    |
+       +-----------+----------------------------------------------------------+
+
+       refcount is a malloc_refcount
+       bytes is an array of bytes of the requested length
+       Both parts are placed in the same allocation returned from gpr_malloc */
+    malloc_refcount *rc = gpr_malloc(sizeof(malloc_refcount) + length);
+
+    /* Initial refcount on rc is 1 - and it's up to the caller to release
+       this reference. */
+    gpr_ref_init(&rc->refs, 1);
+
+    rc->base.ref = malloc_ref;
+    rc->base.unref = malloc_unref;
+
+    /* Build up the slice to be returned. */
+    /* The slices refcount points back to the allocated block. */
+    slice.refcount = &rc->base;
+    /* The data bytes are placed immediately after the refcount struct */
+    slice.data.refcounted.bytes = (uint8_t *)(rc + 1);
+    /* And the length of the block is set to the requested length */
+    slice.data.refcounted.length = length;
+  } else {
+    /* small slice: just inline the data */
+    slice.refcount = NULL;
+    slice.data.inlined.length = (uint8_t)length;
+  }
+  return slice;
+}
+
+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 >= end);
+
+    /* Build the result */
+    subset.refcount = source.refcount;
+    /* Point into the source array */
+    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 = (uint8_t)(end - begin);
+    memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin,
+           end - begin);
+  }
+  return subset;
+}
+
+gpr_slice gpr_slice_sub(gpr_slice source, size_t begin, size_t end) {
+  gpr_slice subset;
+
+  if (end - begin <= sizeof(subset.data.inlined.bytes)) {
+    subset.refcount = NULL;
+    subset.data.inlined.length = (uint8_t)(end - begin);
+    memcpy(subset.data.inlined.bytes, GPR_SLICE_START_PTR(source) + begin,
+           end - begin);
+  } else {
+    subset = gpr_slice_sub_no_ref(source, begin, end);
+    /* Bump the refcount */
+    subset.refcount->ref(subset.refcount);
+  }
+  return subset;
+}
+
+gpr_slice gpr_slice_split_tail(gpr_slice *source, size_t split) {
+  gpr_slice tail;
+
+  if (source->refcount == NULL) {
+    /* inlined data, copy it out */
+    GPR_ASSERT(source->data.inlined.length >= split);
+    tail.refcount = NULL;
+    tail.data.inlined.length = (uint8_t)(source->data.inlined.length - split);
+    memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split,
+           tail.data.inlined.length);
+    source->data.inlined.length = (uint8_t)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 = (uint8_t)tail_length;
+      memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
+             tail_length);
+    } else {
+      /* Build the result */
+      tail.refcount = source->refcount;
+      /* Bump the refcount */
+      tail.refcount->ref(tail.refcount);
+      /* Point into the source array */
+      tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
+      tail.data.refcounted.length = tail_length;
+    }
+    source->data.refcounted.length = split;
+  }
+
+  return tail;
+}
+
+gpr_slice gpr_slice_split_head(gpr_slice *source, size_t split) {
+  gpr_slice head;
+
+  if (source->refcount == NULL) {
+    GPR_ASSERT(source->data.inlined.length >= split);
+
+    head.refcount = NULL;
+    head.data.inlined.length = (uint8_t)split;
+    memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split);
+    source->data.inlined.length =
+        (uint8_t)(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 = (uint8_t)split;
+    memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
+    source->data.refcounted.bytes += split;
+    source->data.refcounted.length -= split;
+  } else {
+    GPR_ASSERT(source->data.refcounted.length >= split);
+
+    /* Build the result */
+    head.refcount = source->refcount;
+    /* Bump the refcount */
+    head.refcount->ref(head.refcount);
+    /* Point into the source array */
+    head.data.refcounted.bytes = source->data.refcounted.bytes;
+    head.data.refcounted.length = split;
+    source->data.refcounted.bytes += split;
+    source->data.refcounted.length -= split;
+  }
+
+  return head;
+}
+
+int gpr_slice_cmp(gpr_slice a, gpr_slice 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));
+}
+
+int gpr_slice_str_cmp(gpr_slice a, const char *b) {
+  size_t b_length = strlen(b);
+  int d = (int)(GPR_SLICE_LENGTH(a) - b_length);
+  if (d != 0) return d;
+  return memcmp(GPR_SLICE_START_PTR(a), b, b_length);
+}
diff --git a/src/core/lib/support/slice_buffer.c b/src/core/lib/support/slice_buffer.c
new file mode 100644
index 0000000..563e659
--- /dev/null
+++ b/src/core/lib/support/slice_buffer.c
@@ -0,0 +1,282 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice_buffer.h>
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+/* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
+#define GROW(x) (3 * (x) / 2)
+
+static void maybe_embiggen(gpr_slice_buffer *sb) {
+  if (sb->count == sb->capacity) {
+    sb->capacity = GROW(sb->capacity);
+    GPR_ASSERT(sb->capacity > sb->count);
+    if (sb->slices == sb->inlined) {
+      sb->slices = gpr_malloc(sb->capacity * sizeof(gpr_slice));
+      memcpy(sb->slices, sb->inlined, sb->count * sizeof(gpr_slice));
+    } else {
+      sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
+    }
+  }
+}
+
+void gpr_slice_buffer_init(gpr_slice_buffer *sb) {
+  sb->count = 0;
+  sb->length = 0;
+  sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS;
+  sb->slices = sb->inlined;
+}
+
+void gpr_slice_buffer_destroy(gpr_slice_buffer *sb) {
+  gpr_slice_buffer_reset_and_unref(sb);
+  if (sb->slices != sb->inlined) {
+    gpr_free(sb->slices);
+  }
+}
+
+uint8_t *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, size_t n) {
+  gpr_slice *back;
+  uint8_t *out;
+
+  sb->length += n;
+
+  if (sb->count == 0) goto add_new;
+  back = &sb->slices[sb->count - 1];
+  if (back->refcount) goto add_new;
+  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 = (uint8_t)(back->data.inlined.length + n);
+  return out;
+
+add_new:
+  maybe_embiggen(sb);
+  back = &sb->slices[sb->count];
+  sb->count++;
+  back->refcount = NULL;
+  back->data.inlined.length = (uint8_t)n;
+  return back->data.inlined.bytes;
+}
+
+size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice s) {
+  size_t out = sb->count;
+  maybe_embiggen(sb);
+  sb->slices[out] = s;
+  sb->length += GPR_SLICE_LENGTH(s);
+  sb->count = out + 1;
+  return out;
+}
+
+void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) {
+  size_t n = sb->count;
+  /* if both the last slice in the slice buffer and the slice being added
+     are inlined (that is, that they carry their data inside the slice data
+     structure), and the back slice is not full, then concatenate directly
+     into the back slice, preventing many small slices being passed into
+     writes */
+  if (!s.refcount && n) {
+    gpr_slice *back = &sb->slices[n - 1];
+    if (!back->refcount && back->data.inlined.length < GPR_SLICE_INLINED_SIZE) {
+      if (s.data.inlined.length + back->data.inlined.length <=
+          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 =
+            (uint8_t)(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,
+               s.data.inlined.bytes, cp1);
+        back->data.inlined.length = GPR_SLICE_INLINED_SIZE;
+        maybe_embiggen(sb);
+        back = &sb->slices[n];
+        sb->count = n + 1;
+        back->refcount = NULL;
+        back->data.inlined.length = (uint8_t)(s.data.inlined.length - cp1);
+        memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1,
+               s.data.inlined.length - cp1);
+      }
+      sb->length += s.data.inlined.length;
+      return; /* early out */
+    }
+  }
+  gpr_slice_buffer_add_indexed(sb, s);
+}
+
+void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *s, size_t n) {
+  size_t i;
+  for (i = 0; i < n; i++) {
+    gpr_slice_buffer_add(sb, s[i]);
+  }
+}
+
+void gpr_slice_buffer_pop(gpr_slice_buffer *sb) {
+  if (sb->count != 0) {
+    size_t count = --sb->count;
+    sb->length -= GPR_SLICE_LENGTH(sb->slices[count]);
+  }
+}
+
+void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) {
+  size_t i;
+
+  for (i = 0; i < sb->count; i++) {
+    gpr_slice_unref(sb->slices[i]);
+  }
+
+  sb->count = 0;
+  sb->length = 0;
+}
+
+void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b) {
+  GPR_SWAP(size_t, a->count, b->count);
+  GPR_SWAP(size_t, a->capacity, b->capacity);
+  GPR_SWAP(size_t, a->length, b->length);
+
+  if (a->slices == a->inlined) {
+    if (b->slices == b->inlined) {
+      /* swap contents of inlined buffer */
+      gpr_slice temp[GRPC_SLICE_BUFFER_INLINE_ELEMENTS];
+      memcpy(temp, a->slices, b->count * sizeof(gpr_slice));
+      memcpy(a->slices, b->slices, a->count * sizeof(gpr_slice));
+      memcpy(b->slices, temp, b->count * sizeof(gpr_slice));
+    } else {
+      /* a is inlined, b is not - copy a inlined into b, fix pointers */
+      a->slices = b->slices;
+      b->slices = b->inlined;
+      memcpy(b->slices, a->inlined, b->count * sizeof(gpr_slice));
+    }
+  } else if (b->slices == b->inlined) {
+    /* b is inlined, a is not - copy b inlined int a, fix pointers */
+    b->slices = a->slices;
+    a->slices = a->inlined;
+    memcpy(a->slices, b->inlined, a->count * sizeof(gpr_slice));
+  } else {
+    /* no inlining: easy swap */
+    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;
+}
+
+void gpr_slice_buffer_move_first(gpr_slice_buffer *src, size_t n,
+                                 gpr_slice_buffer *dst) {
+  size_t src_idx;
+  size_t output_len = dst->length + n;
+  size_t new_input_len = src->length - n;
+  GPR_ASSERT(src->length >= n);
+  if (src->length == n) {
+    gpr_slice_buffer_move_into(src, dst);
+    return;
+  }
+  src_idx = 0;
+  while (src_idx < src->capacity) {
+    gpr_slice slice = src->slices[src_idx];
+    size_t slice_len = GPR_SLICE_LENGTH(slice);
+    if (n > slice_len) {
+      gpr_slice_buffer_add(dst, slice);
+      n -= slice_len;
+      src_idx++;
+    } else if (n == slice_len) {
+      gpr_slice_buffer_add(dst, slice);
+      src_idx++;
+      break;
+    } else { /* n < slice_len */
+      src->slices[src_idx] = gpr_slice_split_tail(&slice, n);
+      GPR_ASSERT(GPR_SLICE_LENGTH(slice) == n);
+      GPR_ASSERT(GPR_SLICE_LENGTH(src->slices[src_idx]) == slice_len - n);
+      gpr_slice_buffer_add(dst, slice);
+      break;
+    }
+  }
+  GPR_ASSERT(dst->length == output_len);
+  memmove(src->slices, src->slices + src_idx,
+          sizeof(gpr_slice) * (src->count - src_idx));
+  src->count -= src_idx;
+  src->length = new_input_len;
+  GPR_ASSERT(src->count > 0);
+}
+
+void gpr_slice_buffer_trim_end(gpr_slice_buffer *sb, size_t n,
+                               gpr_slice_buffer *garbage) {
+  GPR_ASSERT(n <= sb->length);
+  sb->length -= n;
+  for (;;) {
+    size_t idx = sb->count - 1;
+    gpr_slice slice = sb->slices[idx];
+    size_t slice_len = GPR_SLICE_LENGTH(slice);
+    if (slice_len > n) {
+      sb->slices[idx] = gpr_slice_split_head(&slice, slice_len - n);
+      gpr_slice_buffer_add_indexed(garbage, slice);
+      return;
+    } else if (slice_len == n) {
+      gpr_slice_buffer_add_indexed(garbage, slice);
+      sb->count = idx;
+      return;
+    } else {
+      gpr_slice_buffer_add_indexed(garbage, slice);
+      n -= slice_len;
+      sb->count = idx;
+    }
+  }
+}
+
+gpr_slice gpr_slice_buffer_take_first(gpr_slice_buffer *sb) {
+  gpr_slice slice;
+  GPR_ASSERT(sb->count > 0);
+  slice = sb->slices[0];
+  memmove(&sb->slices[0], &sb->slices[1], (sb->count - 1) * sizeof(gpr_slice));
+  sb->count--;
+  sb->length -= GPR_SLICE_LENGTH(slice);
+  return slice;
+}
diff --git a/src/core/lib/support/stack_lockfree.c b/src/core/lib/support/stack_lockfree.c
new file mode 100644
index 0000000..de80486
--- /dev/null
+++ b/src/core/lib/support/stack_lockfree.c
@@ -0,0 +1,185 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/support/stack_lockfree.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.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 */
+  uint16_t index;
+#ifdef GPR_ARCH_64
+  uint16_t pad;
+  uint32_t aba_ctr;
+#else
+#ifdef GPR_ARCH_32
+  uint16_t 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;
+
+/* make sure that entries aligned to 8-bytes */
+#define ENTRY_ALIGNMENT_BITS 3
+/* reserve this entry as invalid */
+#define INVALID_ENTRY_INDEX ((1 << 16) - 1)
+
+struct gpr_stack_lockfree {
+  lockfree_node *entries;
+  lockfree_node head; /* An atomic entry describing curr head */
+
+#ifndef NDEBUG
+  /* Bitmap of pushed entries to check for double-push or pop */
+  gpr_atm pushed[(INVALID_ENTRY_INDEX + 1) / (8 * sizeof(gpr_atm))];
+#endif
+};
+
+gpr_stack_lockfree *gpr_stack_lockfree_create(size_t 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));
+#ifndef NDEBUG
+  memset(&stack->pushed, 0, sizeof(stack->pushed));
+#endif
+
+  GPR_ASSERT(sizeof(stack->entries->atm) == sizeof(stack->entries->contents));
+
+  /* Point the head at reserved dummy entry */
+  stack->head.contents.index = INVALID_ENTRY_INDEX;
+/* Fill in the pad and aba_ctr to avoid confusing memcheck tools */
+#ifdef GPR_ARCH_64
+  stack->head.contents.pad = 0;
+#endif
+  stack->head.contents.aba_ctr = 0;
+  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;
+  lockfree_node curent;
+  lockfree_node newent;
+
+  /* First fill in the entry's index and aba ctr for new head */
+  newhead.contents.index = (uint16_t)entry;
+#ifdef GPR_ARCH_64
+  /* Fill in the pad to avoid confusing memcheck tools */
+  newhead.contents.pad = 0;
+#endif
+
+  /* Also post-increment the aba_ctr */
+  curent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm);
+  newhead.contents.aba_ctr = ++curent.contents.aba_ctr;
+  gpr_atm_no_barrier_store(&stack->entries[entry].atm, curent.atm);
+
+#ifndef NDEBUG
+  /* Check for double push */
+  {
+    int pushed_index = entry / (int)(8 * sizeof(gpr_atm));
+    int pushed_bit = entry % (int)(8 * sizeof(gpr_atm));
+    gpr_atm old_val;
+
+    old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
+                                           ((gpr_atm)1 << pushed_bit));
+    GPR_ASSERT((old_val & (((gpr_atm)1) << pushed_bit)) == 0);
+  }
+#endif
+
+  do {
+    /* Atomically get the existing head value for use */
+    head.atm = gpr_atm_no_barrier_load(&(stack->head.atm));
+    /* Point to it */
+    newent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm);
+    newent.contents.index = head.contents.index;
+    gpr_atm_no_barrier_store(&stack->entries[entry].atm, newent.atm);
+  } 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));
+#ifndef NDEBUG
+  /* Check for valid pop */
+  {
+    int pushed_index = head.contents.index / (8 * sizeof(gpr_atm));
+    int pushed_bit = head.contents.index % (8 * sizeof(gpr_atm));
+    gpr_atm old_val;
+
+    old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
+                                           -((gpr_atm)1 << pushed_bit));
+    GPR_ASSERT((old_val & (((gpr_atm)1) << pushed_bit)) != 0);
+  }
+#endif
+
+  return head.contents.index;
+}
diff --git a/src/core/lib/support/stack_lockfree.h b/src/core/lib/support/stack_lockfree.h
new file mode 100644
index 0000000..a030a01
--- /dev/null
+++ b/src/core/lib/support/stack_lockfree.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_STACK_LOCKFREE_H
+#define GRPC_CORE_LIB_SUPPORT_STACK_LOCKFREE_H
+
+#include <stddef.h>
+
+typedef struct gpr_stack_lockfree gpr_stack_lockfree;
+
+/* 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(size_t entries);
+void gpr_stack_lockfree_destroy(gpr_stack_lockfree *stack);
+
+/* 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_CORE_LIB_SUPPORT_STACK_LOCKFREE_H */
diff --git a/src/core/lib/support/string.c b/src/core/lib/support/string.c
new file mode 100644
index 0000000..365d861
--- /dev/null
+++ b/src/core/lib/support/string.c
@@ -0,0 +1,296 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/support/string.h"
+
+#include <ctype.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/useful.h>
+
+char *gpr_strdup(const char *src) {
+  char *dst;
+  size_t len;
+
+  if (!src) {
+    return NULL;
+  }
+
+  len = strlen(src) + 1;
+  dst = gpr_malloc(len);
+
+  memcpy(dst, src, len);
+
+  return dst;
+}
+
+typedef struct {
+  size_t capacity;
+  size_t length;
+  char *data;
+} dump_out;
+
+static dump_out dump_out_create(void) {
+  dump_out r = {0, 0, NULL};
+  return r;
+}
+
+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);
+  }
+  out->data[out->length++] = c;
+}
+
+static void hexdump(dump_out *out, const char *buf, size_t len) {
+  static const char hex[16] = "0123456789abcdef";
+
+  const uint8_t *const beg = (const uint8_t *)buf;
+  const uint8_t *const end = beg + len;
+  const uint8_t *cur;
+
+  for (cur = beg; cur != end; ++cur) {
+    if (cur != beg) dump_out_append(out, ' ');
+    dump_out_append(out, hex[*cur >> 4]);
+    dump_out_append(out, hex[*cur & 0xf]);
+  }
+}
+
+static void asciidump(dump_out *out, const char *buf, size_t len) {
+  const uint8_t *const beg = (const uint8_t *)buf;
+  const uint8_t *const end = beg + len;
+  const uint8_t *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, (char)(isprint(*cur) ? *(char *)cur : '.'));
+  }
+  if (!out_was_empty) {
+    dump_out_append(out, '\'');
+  }
+}
+
+char *gpr_dump(const char *buf, size_t len, uint32_t 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, uint32_t 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, uint32_t *result) {
+  uint32_t out = 0;
+  uint32_t new;
+  size_t i;
+
+  if (len == 0) return 0; /* must have some bytes */
+
+  for (i = 0; i < len; i++) {
+    if (buf[i] < '0' || buf[i] > '9') return 0; /* bad char */
+    new = 10 * out + (uint32_t)(buf[i] - '0');
+    if (new < out) return 0; /* overflow */
+    out = new;
+  }
+
+  *result = out;
+  return 1;
+}
+
+void gpr_reverse_bytes(char *str, int len) {
+  char *p1, *p2;
+  for (p1 = str, p2 = str + len - 1; p2 > p1; ++p1, --p2) {
+    char temp = *p1;
+    *p1 = *p2;
+    *p2 = temp;
+  }
+}
+
+int gpr_ltoa(long value, char *string) {
+  long sign;
+  int i = 0;
+
+  if (value == 0) {
+    string[0] = '0';
+    string[1] = 0;
+    return 1;
+  }
+
+  sign = value < 0 ? -1 : 1;
+  while (value) {
+    string[i++] = (char)('0' + sign * (value % 10));
+    value /= 10;
+  }
+  if (sign < 0) string[i++] = '-';
+  gpr_reverse_bytes(string, i);
+  string[i] = 0;
+  return i;
+}
+
+int int64_ttoa(int64_t value, char *string) {
+  int64_t sign;
+  int i = 0;
+
+  if (value == 0) {
+    string[0] = '0';
+    string[1] = 0;
+    return 1;
+  }
+
+  sign = value < 0 ? -1 : 1;
+  while (value) {
+    string[i++] = (char)('0' + sign * (value % 10));
+    value /= 10;
+  }
+  if (sign < 0) string[i++] = '-';
+  gpr_reverse_bytes(string, i);
+  string[i] = 0;
+  return i;
+}
+
+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;
+  for (i = 0; i < nstrs; i++) {
+    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++) {
+    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;
+  }
+  out[out_length] = 0;
+  if (final_length != NULL) {
+    *final_length = out_length;
+  }
+  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 uint8_t *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)); }
+
+void gpr_strvec_destroy(gpr_strvec *sv) {
+  size_t i;
+  for (i = 0; i < sv->count; i++) {
+    gpr_free(sv->strs[i]);
+  }
+  gpr_free(sv->strs);
+}
+
+void gpr_strvec_add(gpr_strvec *sv, char *str) {
+  if (sv->count == sv->capacity) {
+    sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 2);
+    sv->strs = gpr_realloc(sv->strs, sizeof(char *) * sv->capacity);
+  }
+  sv->strs[sv->count++] = str;
+}
+
+char *gpr_strvec_flatten(gpr_strvec *sv, size_t *final_length) {
+  return gpr_strjoin((const char **)sv->strs, sv->count, final_length);
+}
diff --git a/src/core/lib/support/string.h b/src/core/lib/support/string.h
new file mode 100644
index 0000000..68c0287
--- /dev/null
+++ b/src/core/lib/support/string.h
@@ -0,0 +1,121 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_STRING_H
+#define GRPC_CORE_LIB_SUPPORT_STRING_H
+
+#include <stddef.h>
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* String utility functions */
+
+/* Flags for gpr_dump function. */
+#define GPR_DUMP_HEX 0x00000001
+#define GPR_DUMP_ASCII 0x00000002
+
+/* 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, uint32_t flags);
+
+/* Calls gpr_dump on a slice. */
+char *gpr_dump_slice(gpr_slice slice, uint32_t flags);
+
+/* Parses an array of bytes into an integer (base 10). Returns 1 on success,
+   0 on failure. */
+int gpr_parse_bytes_to_uint32(const char *data, size_t length,
+                              uint32_t *result);
+
+/* Minimum buffer size for calling ltoa */
+#define GPR_LTOA_MIN_BUFSIZE (3 * sizeof(long))
+
+/* Convert a long to a string in base 10; returns the length of the
+   output string (or 0 on failure).
+   output must be at least GPR_LTOA_MIN_BUFSIZE bytes long. */
+int gpr_ltoa(long value, char *output);
+
+/* Minimum buffer size for calling int64toa */
+#define GPR_INT64TOA_MIN_BUFSIZE (3 * sizeof(int64_t))
+
+/* Convert an int64 to a string in base 10; returns the length of the
+output string (or 0 on failure).
+output must be at least GPR_INT64TOA_MIN_BUFSIZE bytes long.
+NOTE: This function ensures sufficient bit width even on Win x64,
+where long is 32bit is size.*/
+int int64_ttoa(int64_t value, char *output);
+
+/* Reverse a run of bytes */
+void gpr_reverse_bytes(char *str, int len);
+
+/* Join a set of strings, returning the resulting string.
+   Total combined length (excluding null terminator) is returned in total_length
+   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;
+  size_t count;
+  size_t capacity;
+} gpr_strvec;
+
+/* Initialize/destroy */
+void gpr_strvec_init(gpr_strvec *strs);
+void gpr_strvec_destroy(gpr_strvec *strs);
+/* Add a string to a strvec, takes ownership of the string */
+void gpr_strvec_add(gpr_strvec *strs, char *add);
+/* Return a joined string with all added substrings, optionally setting
+   total_length as per gpr_strjoin */
+char *gpr_strvec_flatten(gpr_strvec *strs, size_t *total_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_SUPPORT_STRING_H */
diff --git a/src/core/lib/support/string_posix.c b/src/core/lib/support/string_posix.c
new file mode 100644
index 0000000..a73b310
--- /dev/null
+++ b/src/core/lib/support/string_posix.c
@@ -0,0 +1,86 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_STRING
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+int gpr_asprintf(char **strp, const char *format, ...) {
+  va_list args;
+  int ret;
+  char buf[64];
+  size_t strp_buflen;
+
+  /* Use a constant-sized buffer to determine the length. */
+  va_start(args, format);
+  ret = vsnprintf(buf, sizeof(buf), format, args);
+  va_end(args);
+  if (ret < 0) {
+    *strp = NULL;
+    return -1;
+  }
+
+  /* Allocate a new buffer, with space for the NUL terminator. */
+  strp_buflen = (size_t)ret + 1;
+  if ((*strp = gpr_malloc(strp_buflen)) == NULL) {
+    /* This shouldn't happen, because gpr_malloc() calls abort(). */
+    return -1;
+  }
+
+  /* Return early if we have all the bytes. */
+  if (strp_buflen <= sizeof(buf)) {
+    memcpy(*strp, buf, strp_buflen);
+    return ret;
+  }
+
+  /* Try again using the larger buffer. */
+  va_start(args, format);
+  ret = vsnprintf(*strp, strp_buflen, format, args);
+  va_end(args);
+  if ((size_t)ret == strp_buflen - 1) {
+    return ret;
+  }
+
+  /* This should never happen. */
+  gpr_free(*strp);
+  *strp = NULL;
+  return -1;
+}
+
+#endif /* GPR_POSIX_STRING */
diff --git a/src/core/lib/support/string_win32.c b/src/core/lib/support/string_win32.c
new file mode 100644
index 0000000..16b7e37
--- /dev/null
+++ b/src/core/lib/support/string_win32.c
@@ -0,0 +1,109 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Posix code for gpr snprintf support. */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+#include "src/core/lib/support/string.h"
+
+int gpr_asprintf(char **strp, const char *format, ...) {
+  va_list args;
+  int ret;
+  size_t strp_buflen;
+
+  /* Determine the length. */
+  va_start(args, format);
+  ret = _vscprintf(format, args);
+  va_end(args);
+  if (ret < 0) {
+    *strp = NULL;
+    return -1;
+  }
+
+  /* Allocate a new buffer, with space for the NUL terminator. */
+  strp_buflen = (size_t)ret + 1;
+  if ((*strp = gpr_malloc(strp_buflen)) == NULL) {
+    /* This shouldn't happen, because gpr_malloc() calls abort(). */
+    return -1;
+  }
+
+  /* Print to the buffer. */
+  va_start(args, format);
+  ret = vsnprintf_s(*strp, strp_buflen, _TRUNCATE, format, args);
+  va_end(args);
+  if ((size_t)ret == strp_buflen - 1) {
+    return ret;
+  }
+
+  /* This should never happen. */
+  gpr_free(*strp);
+  *strp = NULL;
+  return -1;
+}
+
+#if defined UNICODE || defined _UNICODE
+LPTSTR
+gpr_char_to_tchar(LPCSTR input) {
+  LPTSTR ret;
+  int needed = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
+  if (needed <= 0) return NULL;
+  ret = gpr_malloc((unsigned)needed * sizeof(TCHAR));
+  MultiByteToWideChar(CP_UTF8, 0, input, -1, ret, needed);
+  return ret;
+}
+
+LPSTR
+gpr_tchar_to_char(LPCTSTR input) {
+  LPSTR ret;
+  int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL);
+  if (needed <= 0) return NULL;
+  ret = gpr_malloc((unsigned)needed);
+  WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL);
+  return ret;
+}
+#else
+char *gpr_tchar_to_char(LPTSTR input) { return gpr_strdup(input); }
+
+char *gpr_char_to_tchar(LPTSTR input) { return gpr_strdup(input); }
+#endif
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/lib/support/string_win32.h b/src/core/lib/support/string_win32.h
new file mode 100644
index 0000000..f47d567
--- /dev/null
+++ b/src/core/lib/support/string_win32.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_STRING_WIN32_H
+#define GRPC_CORE_LIB_SUPPORT_STRING_WIN32_H
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+/* 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);
+
+#endif /* GPR_WIN32 */
+
+#endif /* GRPC_CORE_LIB_SUPPORT_STRING_WIN32_H */
diff --git a/src/core/lib/support/subprocess_posix.c b/src/core/lib/support/subprocess_posix.c
new file mode 100644
index 0000000..662e7dd
--- /dev/null
+++ b/src/core/lib/support/subprocess_posix.c
@@ -0,0 +1,112 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SUBPROCESS
+
+#include <grpc/support/subprocess.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+struct gpr_subprocess {
+  int pid;
+  int joined;
+};
+
+const char *gpr_subprocess_binary_extension() { return ""; }
+
+gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) {
+  gpr_subprocess *r;
+  int pid;
+  char **exec_args;
+
+  pid = fork();
+  if (pid == -1) {
+    return NULL;
+  } else if (pid == 0) {
+    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 */
+    gpr_log(GPR_ERROR, "execv '%s' failed: %s", exec_args[0], strerror(errno));
+    _exit(1);
+    return NULL;
+  } else {
+    r = gpr_malloc(sizeof(gpr_subprocess));
+    memset(r, 0, sizeof(*r));
+    r->pid = pid;
+    return r;
+  }
+}
+
+void gpr_subprocess_destroy(gpr_subprocess *p) {
+  if (!p->joined) {
+    kill(p->pid, SIGKILL);
+    gpr_subprocess_join(p);
+  }
+  gpr_free(p);
+}
+
+int gpr_subprocess_join(gpr_subprocess *p) {
+  int status;
+retry:
+  if (waitpid(p->pid, &status, 0) == -1) {
+    if (errno == EINTR) {
+      goto retry;
+    }
+    gpr_log(GPR_ERROR, "waitpid failed: %s", strerror(errno));
+    return -1;
+  }
+  return status;
+}
+
+void gpr_subprocess_interrupt(gpr_subprocess *p) {
+  if (!p->joined) {
+    kill(p->pid, SIGINT);
+  }
+}
+
+#endif /* GPR_POSIX_SUBPROCESS */
diff --git a/src/core/lib/support/subprocess_windows.c b/src/core/lib/support/subprocess_windows.c
new file mode 100644
index 0000000..264306f
--- /dev/null
+++ b/src/core/lib/support/subprocess_windows.c
@@ -0,0 +1,141 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINDOWS_SUBPROCESS
+
+#include <string.h>
+#include <tchar.h>
+#include <windows.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/subprocess.h>
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/support/string_win32.h"
+
+struct gpr_subprocess {
+  PROCESS_INFORMATION pi;
+  int joined;
+  int interrupted;
+};
+
+const char *gpr_subprocess_binary_extension() { return ".exe"; }
+
+gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) {
+  gpr_subprocess *r;
+
+  STARTUPINFO si;
+  PROCESS_INFORMATION pi;
+
+  char *args = gpr_strjoin_sep(argv, (size_t)argc, " ", NULL);
+  TCHAR *args_tchar;
+
+  args_tchar = gpr_char_to_tchar(args);
+  gpr_free(args);
+
+  memset(&si, 0, sizeof(si));
+  si.cb = sizeof(si);
+  memset(&pi, 0, sizeof(pi));
+
+  if (!CreateProcess(NULL, args_tchar, NULL, NULL, FALSE,
+                     CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) {
+    gpr_free(args_tchar);
+    return NULL;
+  }
+  gpr_free(args_tchar);
+
+  r = gpr_malloc(sizeof(gpr_subprocess));
+  memset(r, 0, sizeof(*r));
+  r->pi = pi;
+  return r;
+}
+
+void gpr_subprocess_destroy(gpr_subprocess *p) {
+  if (p) {
+    if (!p->joined) {
+      gpr_subprocess_interrupt(p);
+      gpr_subprocess_join(p);
+    }
+    if (p->pi.hProcess) {
+      CloseHandle(p->pi.hProcess);
+    }
+    if (p->pi.hThread) {
+      CloseHandle(p->pi.hThread);
+    }
+    gpr_free(p);
+  }
+}
+
+int gpr_subprocess_join(gpr_subprocess *p) {
+  DWORD dwExitCode;
+  if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) {
+    if (dwExitCode == STILL_ACTIVE) {
+      if (WaitForSingleObject(p->pi.hProcess, INFINITE) == WAIT_OBJECT_0) {
+        p->joined = 1;
+        goto getExitCode;
+      }
+      return -1;  // failed to join
+    } else {
+      goto getExitCode;
+    }
+  } else {
+    return -1;  // failed to get exit code
+  }
+
+getExitCode:
+  if (p->interrupted) {
+    return 0;
+  }
+  if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) {
+    return (int)dwExitCode;
+  } else {
+    return -1;  // failed to get exit code
+  }
+}
+
+void gpr_subprocess_interrupt(gpr_subprocess *p) {
+  DWORD dwExitCode;
+  if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) {
+    if (dwExitCode == STILL_ACTIVE) {
+      gpr_log(GPR_INFO, "sending ctrl-break");
+      GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, p->pi.dwProcessId);
+      p->joined = 1;
+      p->interrupted = 1;
+    }
+  }
+  return;
+}
+
+#endif /* GPR_WINDOWS_SUBPROCESS */
diff --git a/src/core/lib/support/sync.c b/src/core/lib/support/sync.c
new file mode 100644
index 0000000..800cf20
--- /dev/null
+++ b/src/core/lib/support/sync.c
@@ -0,0 +1,127 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Generic implementation of synchronization primitives. */
+
+#include <grpc/support/atm.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+/* Number of mutexes to allocate for events, to avoid lock contention.
+   Should be a prime. */
+enum { event_sync_partitions = 31 };
+
+/* Events are partitioned by address to avoid lock contention. */
+static struct sync_array_s {
+  gpr_mu mu;
+  gpr_cv cv;
+} sync_array[event_sync_partitions];
+
+/* This routine is executed once on first use, via event_once */
+static gpr_once event_once = GPR_ONCE_INIT;
+static void event_initialize(void) {
+  int i;
+  for (i = 0; i != event_sync_partitions; i++) {
+    gpr_mu_init(&sync_array[i].mu);
+    gpr_cv_init(&sync_array[i].cv);
+  }
+}
+
+/* Hash ev into an element of sync_array[]. */
+static struct sync_array_s *hash(gpr_event *ev) {
+  return &sync_array[((uintptr_t)ev) % event_sync_partitions];
+}
+
+void gpr_event_init(gpr_event *ev) {
+  gpr_once_init(&event_once, &event_initialize);
+  ev->state = 0;
+}
+
+void gpr_event_set(gpr_event *ev, void *value) {
+  struct sync_array_s *s = hash(ev);
+  gpr_mu_lock(&s->mu);
+  GPR_ASSERT(gpr_atm_acq_load(&ev->state) == 0);
+  gpr_atm_rel_store(&ev->state, (gpr_atm)value);
+  gpr_cv_broadcast(&s->cv);
+  gpr_mu_unlock(&s->mu);
+  GPR_ASSERT(value != NULL);
+}
+
+void *gpr_event_get(gpr_event *ev) {
+  return (void *)gpr_atm_acq_load(&ev->state);
+}
+
+void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline) {
+  void *result = (void *)gpr_atm_acq_load(&ev->state);
+  if (result == NULL) {
+    struct sync_array_s *s = hash(ev);
+    gpr_mu_lock(&s->mu);
+    do {
+      result = (void *)gpr_atm_acq_load(&ev->state);
+    } while (result == NULL && !gpr_cv_wait(&s->cv, &s->mu, abs_deadline));
+    gpr_mu_unlock(&s->mu);
+  }
+  return result;
+}
+
+void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); }
+
+void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); }
+
+void gpr_ref_non_zero(gpr_refcount *r) {
+  gpr_atm prior = gpr_atm_no_barrier_fetch_add(&r->count, 1);
+  GPR_ASSERT(prior > 0);
+}
+
+void gpr_refn(gpr_refcount *r, int n) {
+  gpr_atm_no_barrier_fetch_add(&r->count, n);
+}
+
+int gpr_unref(gpr_refcount *r) {
+  gpr_atm prior = gpr_atm_full_fetch_add(&r->count, -1);
+  GPR_ASSERT(prior > 0);
+  return prior == 1;
+}
+
+void gpr_stats_init(gpr_stats_counter *c, intptr_t n) {
+  gpr_atm_rel_store(&c->value, n);
+}
+
+void gpr_stats_inc(gpr_stats_counter *c, intptr_t inc) {
+  gpr_atm_no_barrier_fetch_add(&c->value, inc);
+}
+
+intptr_t gpr_stats_read(const gpr_stats_counter *c) {
+  /* don't need acquire-load, but we have no no-barrier load yet */
+  return gpr_atm_acq_load(&c->value);
+}
diff --git a/src/core/lib/support/sync_posix.c b/src/core/lib/support/sync_posix.c
new file mode 100644
index 0000000..a5e59db
--- /dev/null
+++ b/src/core/lib/support/sync_posix.c
@@ -0,0 +1,104 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SYNC
+
+#include <errno.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+#include <time.h>
+#include "src/core/lib/profiling/timers.h"
+
+void gpr_mu_init(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_init(mu, NULL) == 0); }
+
+void gpr_mu_destroy(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_destroy(mu) == 0); }
+
+void gpr_mu_lock(gpr_mu* mu) {
+  GPR_TIMER_BEGIN("gpr_mu_lock", 0);
+  GPR_ASSERT(pthread_mutex_lock(mu) == 0);
+  GPR_TIMER_END("gpr_mu_lock", 0);
+}
+
+void gpr_mu_unlock(gpr_mu* mu) {
+  GPR_TIMER_BEGIN("gpr_mu_unlock", 0);
+  GPR_ASSERT(pthread_mutex_unlock(mu) == 0);
+  GPR_TIMER_END("gpr_mu_unlock", 0);
+}
+
+int gpr_mu_trylock(gpr_mu* mu) {
+  int err;
+  GPR_TIMER_BEGIN("gpr_mu_trylock", 0);
+  err = pthread_mutex_trylock(mu);
+  GPR_ASSERT(err == 0 || err == EBUSY);
+  GPR_TIMER_END("gpr_mu_trylock", 0);
+  return err == 0;
+}
+
+/*----------------------------------------*/
+
+void gpr_cv_init(gpr_cv* cv) { GPR_ASSERT(pthread_cond_init(cv, NULL) == 0); }
+
+void gpr_cv_destroy(gpr_cv* cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); }
+
+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(abs_deadline.clock_type)) ==
+      0) {
+    err = pthread_cond_wait(cv, mu);
+  } else {
+    struct timespec abs_deadline_ts;
+    abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME);
+    abs_deadline_ts.tv_sec = (time_t)abs_deadline.tv_sec;
+    abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec;
+    err = pthread_cond_timedwait(cv, mu, &abs_deadline_ts);
+  }
+  GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN);
+  return err == ETIMEDOUT;
+}
+
+void gpr_cv_signal(gpr_cv* cv) { GPR_ASSERT(pthread_cond_signal(cv) == 0); }
+
+void gpr_cv_broadcast(gpr_cv* cv) {
+  GPR_ASSERT(pthread_cond_broadcast(cv) == 0);
+}
+
+/*----------------------------------------*/
+
+void gpr_once_init(gpr_once* once, void (*init_function)(void)) {
+  GPR_ASSERT(pthread_once(once, init_function) == 0);
+}
+
+#endif /* GRP_POSIX_SYNC */
diff --git a/src/core/support/sync_win32.c b/src/core/lib/support/sync_win32.c
similarity index 100%
rename from src/core/support/sync_win32.c
rename to src/core/lib/support/sync_win32.c
diff --git a/src/core/lib/support/thd.c b/src/core/lib/support/thd.c
new file mode 100644
index 0000000..d59aace
--- /dev/null
+++ b/src/core/lib/support/thd.c
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Posix implementation for gpr threads. */
+
+#include <memory.h>
+
+#include <grpc/support/thd.h>
+
+enum { GPR_THD_JOINABLE = 1 };
+
+gpr_thd_options gpr_thd_options_default(void) {
+  gpr_thd_options options;
+  memset(&options, 0, sizeof(options));
+  return options;
+}
+
+void gpr_thd_options_set_detached(gpr_thd_options* options) {
+  options->flags &= ~GPR_THD_JOINABLE;
+}
+
+void gpr_thd_options_set_joinable(gpr_thd_options* options) {
+  options->flags |= GPR_THD_JOINABLE;
+}
+
+int gpr_thd_options_is_detached(const gpr_thd_options* options) {
+  if (!options) return 1;
+  return (options->flags & GPR_THD_JOINABLE) == 0;
+}
+
+int gpr_thd_options_is_joinable(const gpr_thd_options* options) {
+  if (!options) return 0;
+  return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE;
+}
diff --git a/src/core/lib/support/thd_internal.h b/src/core/lib/support/thd_internal.h
new file mode 100644
index 0000000..f269a32
--- /dev/null
+++ b/src/core/lib/support/thd_internal.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_THD_INTERNAL_H
+#define GRPC_CORE_LIB_SUPPORT_THD_INTERNAL_H
+
+/* Internal interfaces between modules within the gpr support library.  */
+
+#endif /* GRPC_CORE_LIB_SUPPORT_THD_INTERNAL_H */
diff --git a/src/core/lib/support/thd_posix.c b/src/core/lib/support/thd_posix.c
new file mode 100644
index 0000000..4d874d3
--- /dev/null
+++ b/src/core/lib/support/thd_posix.c
@@ -0,0 +1,94 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Posix implementation for gpr threads. */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SYNC
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct thd_arg {
+  void (*body)(void *arg); /* body of a thread */
+  void *arg;               /* argument to a thread */
+};
+
+/* Body of every thread started via gpr_thd_new. */
+static void *thread_body(void *v) {
+  struct thd_arg a = *(struct thd_arg *)v;
+  free(v);
+  (*a.body)(a.arg);
+  return NULL;
+}
+
+int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
+                const gpr_thd_options *options) {
+  int thread_started;
+  pthread_attr_t attr;
+  pthread_t p;
+  /* don't use gpr_malloc as we may cause an infinite recursion with
+   * the profiling code */
+  struct thd_arg *a = malloc(sizeof(*a));
+  GPR_ASSERT(a != NULL);
+  a->body = thd_body;
+  a->arg = arg;
+
+  GPR_ASSERT(pthread_attr_init(&attr) == 0);
+  if (gpr_thd_options_is_detached(options)) {
+    GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) ==
+               0);
+  } else {
+    GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
+               0);
+  }
+  thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
+  GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
+  if (!thread_started) {
+    free(a);
+  }
+  *t = (gpr_thd_id)p;
+  return thread_started;
+}
+
+gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }
+
+void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, NULL); }
+
+#endif /* GPR_POSIX_SYNC */
diff --git a/src/core/lib/support/thd_win32.c b/src/core/lib/support/thd_win32.c
new file mode 100644
index 0000000..630eb7f
--- /dev/null
+++ b/src/core/lib/support/thd_win32.c
@@ -0,0 +1,117 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Windows implementation for gpr threads. */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+#include <string.h>
+
+#if defined(_MSC_VER)
+#define thread_local __declspec(thread)
+#elif defined(__GNUC__)
+#define thread_local __thread
+#else
+#error "Unknown compiler - please file a bug report"
+#endif
+
+struct thd_info {
+  void (*body)(void *arg); /* body of a thread */
+  void *arg;               /* argument to a thread */
+  HANDLE join_event;       /* if joinable, the join event */
+  int joinable;            /* true if not detached */
+};
+
+static thread_local struct thd_info *g_thd_info;
+
+/* Destroys a thread info */
+static void destroy_thread(struct thd_info *t) {
+  if (t->joinable) CloseHandle(t->join_event);
+  gpr_free(t);
+}
+
+/* Body of every thread started via gpr_thd_new. */
+static DWORD WINAPI thread_body(void *v) {
+  g_thd_info = (struct thd_info *)v;
+  g_thd_info->body(g_thd_info->arg);
+  if (g_thd_info->joinable) {
+    BOOL ret = SetEvent(g_thd_info->join_event);
+    GPR_ASSERT(ret);
+  } else {
+    destroy_thread(g_thd_info);
+  }
+  return 0;
+}
+
+int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
+                const gpr_thd_options *options) {
+  HANDLE handle;
+  struct thd_info *info = gpr_malloc(sizeof(*info));
+  info->body = thd_body;
+  info->arg = arg;
+  *t = 0;
+  if (gpr_thd_options_is_joinable(options)) {
+    info->joinable = 1;
+    info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (info->join_event == NULL) {
+      gpr_free(info);
+      return 0;
+    }
+  } else {
+    info->joinable = 0;
+  }
+  handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL);
+  if (handle == NULL) {
+    destroy_thread(info);
+  } else {
+    *t = (gpr_thd_id)info;
+    CloseHandle(handle);
+  }
+  return handle != NULL;
+}
+
+gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }
+
+void gpr_thd_join(gpr_thd_id t) {
+  struct thd_info *info = (struct thd_info *)t;
+  DWORD ret = WaitForSingleObject(info->join_event, INFINITE);
+  GPR_ASSERT(ret == WAIT_OBJECT_0);
+  destroy_thread(info);
+}
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/lib/support/time.c b/src/core/lib/support/time.c
new file mode 100644
index 0000000..0e2c8fc
--- /dev/null
+++ b/src/core/lib/support/time.c
@@ -0,0 +1,304 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Generic implementation of time calls. */
+
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+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);
+  }
+  return cmp;
+}
+
+gpr_timespec gpr_time_min(gpr_timespec a, gpr_timespec b) {
+  return gpr_time_cmp(a, b) < 0 ? a : b;
+}
+
+gpr_timespec gpr_time_max(gpr_timespec a, gpr_timespec b) {
+  return gpr_time_cmp(a, b) > 0 ? a : b;
+}
+
+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 = INT64_MAX;
+  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 = INT64_MIN;
+  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(int64_t ns, gpr_clock_type type) {
+  gpr_timespec result;
+  result.clock_type = type;
+  if (ns == INT64_MAX) {
+    result = gpr_inf_future(type);
+  } else if (ns == INT64_MIN) {
+    result = gpr_inf_past(type);
+  } else if (ns >= 0) {
+    result.tv_sec = ns / GPR_NS_PER_SEC;
+    result.tv_nsec = (int32_t)(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 = (int32_t)(ns - result.tv_sec * GPR_NS_PER_SEC);
+  }
+  return result;
+}
+
+gpr_timespec gpr_time_from_micros(int64_t us, gpr_clock_type type) {
+  gpr_timespec result;
+  result.clock_type = type;
+  if (us == INT64_MAX) {
+    result = gpr_inf_future(type);
+  } else if (us == INT64_MIN) {
+    result = gpr_inf_past(type);
+  } else if (us >= 0) {
+    result.tv_sec = us / 1000000;
+    result.tv_nsec = (int32_t)((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 = (int32_t)((us - result.tv_sec * 1000000) * 1000);
+  }
+  return result;
+}
+
+gpr_timespec gpr_time_from_millis(int64_t ms, gpr_clock_type type) {
+  gpr_timespec result;
+  result.clock_type = type;
+  if (ms == INT64_MAX) {
+    result = gpr_inf_future(type);
+  } else if (ms == INT64_MIN) {
+    result = gpr_inf_past(type);
+  } else if (ms >= 0) {
+    result.tv_sec = ms / 1000;
+    result.tv_nsec = (int32_t)((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 = (int32_t)((ms - result.tv_sec * 1000) * 1000000);
+  }
+  return result;
+}
+
+gpr_timespec gpr_time_from_seconds(int64_t s, gpr_clock_type type) {
+  gpr_timespec result;
+  result.clock_type = type;
+  if (s == INT64_MAX) {
+    result = gpr_inf_future(type);
+  } else if (s == INT64_MIN) {
+    result = gpr_inf_past(type);
+  } else {
+    result.tv_sec = s;
+    result.tv_nsec = 0;
+  }
+  return result;
+}
+
+gpr_timespec gpr_time_from_minutes(int64_t m, gpr_clock_type type) {
+  gpr_timespec result;
+  result.clock_type = type;
+  if (m >= INT64_MAX / 60) {
+    result = gpr_inf_future(type);
+  } else if (m <= INT64_MIN / 60) {
+    result = gpr_inf_past(type);
+  } else {
+    result.tv_sec = m * 60;
+    result.tv_nsec = 0;
+  }
+  return result;
+}
+
+gpr_timespec gpr_time_from_hours(int64_t h, gpr_clock_type type) {
+  gpr_timespec result;
+  result.clock_type = type;
+  if (h >= INT64_MAX / 3600) {
+    result = gpr_inf_future(type);
+  } else if (h <= INT64_MIN / 3600) {
+    result = gpr_inf_past(type);
+  } else {
+    result.tv_sec = h * 3600;
+    result.tv_nsec = 0;
+  }
+  return result;
+}
+
+gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
+  gpr_timespec sum;
+  int64_t 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;
+    inc++;
+  }
+  if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) {
+    sum = a;
+  } else if (b.tv_sec == INT64_MAX ||
+             (b.tv_sec >= 0 && a.tv_sec >= INT64_MAX - b.tv_sec)) {
+    sum = gpr_inf_future(sum.clock_type);
+  } else if (b.tv_sec == INT64_MIN ||
+             (b.tv_sec <= 0 && a.tv_sec <= INT64_MIN - b.tv_sec)) {
+    sum = gpr_inf_past(sum.clock_type);
+  } else {
+    sum.tv_sec = a.tv_sec + b.tv_sec;
+    if (inc != 0 && sum.tv_sec == INT64_MAX - 1) {
+      sum = gpr_inf_future(sum.clock_type);
+    } else {
+      sum.tv_sec += inc;
+    }
+  }
+  return sum;
+}
+
+gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) {
+  gpr_timespec diff;
+  int64_t 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;
+    dec++;
+  }
+  if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) {
+    diff = a;
+  } else if (b.tv_sec == INT64_MIN ||
+             (b.tv_sec <= 0 && a.tv_sec >= INT64_MAX + b.tv_sec)) {
+    diff = gpr_inf_future(GPR_CLOCK_REALTIME);
+  } else if (b.tv_sec == INT64_MAX ||
+             (b.tv_sec >= 0 && a.tv_sec <= INT64_MIN + b.tv_sec)) {
+    diff = gpr_inf_past(GPR_CLOCK_REALTIME);
+  } else {
+    diff.tv_sec = a.tv_sec - b.tv_sec;
+    if (dec != 0 && diff.tv_sec == INT64_MIN + 1) {
+      diff = gpr_inf_past(GPR_CLOCK_REALTIME);
+    } else {
+      diff.tv_sec -= dec;
+    }
+  }
+  return diff;
+}
+
+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) {
+    return gpr_time_cmp(gpr_time_sub(b, a), threshold) <= 0;
+  } else {
+    return gpr_time_cmp(gpr_time_sub(a, b), threshold) <= 0;
+  }
+}
+
+int32_t gpr_time_to_millis(gpr_timespec t) {
+  if (t.tv_sec >= 2147483) {
+    if (t.tv_sec == 2147483 && t.tv_nsec < 648 * GPR_NS_PER_MS) {
+      return 2147483 * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS;
+    }
+    return 2147483647;
+  } else if (t.tv_sec <= -2147483) {
+    /* TODO(ctiller): correct handling here (it's so far in the past do we
+       care?) */
+    return -2147483647;
+  } else {
+    return (int32_t)(t.tv_sec * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS);
+  }
+}
+
+double gpr_timespec_to_micros(gpr_timespec t) {
+  return (double)t.tv_sec * GPR_US_PER_SEC + t.tv_nsec * 1e-3;
+}
+
+gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) {
+  if (t.clock_type == clock_type) {
+    return t;
+  }
+
+  if (t.tv_nsec == 0) {
+    if (t.tv_sec == INT64_MAX) {
+      t.clock_type = clock_type;
+      return t;
+    }
+    if (t.tv_sec == INT64_MIN) {
+      t.clock_type = clock_type;
+      return t;
+    }
+  }
+
+  if (clock_type == GPR_TIMESPAN) {
+    return gpr_time_sub(t, gpr_now(t.clock_type));
+  }
+
+  if (t.clock_type == GPR_TIMESPAN) {
+    return gpr_time_add(gpr_now(clock_type), t);
+  }
+
+  return gpr_time_add(gpr_now(clock_type),
+                      gpr_time_sub(t, gpr_now(t.clock_type)));
+}
diff --git a/src/core/lib/support/time_posix.c b/src/core/lib/support/time_posix.c
new file mode 100644
index 0000000..fcfab2f
--- /dev/null
+++ b/src/core/lib/support/time_posix.c
@@ -0,0 +1,170 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+#include "src/core/lib/support/time_precise.h"
+
+#ifdef GPR_POSIX_TIME
+
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef __linux__
+#include <sys/syscall.h>
+#endif
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include "src/core/lib/support/block_annotate.h"
+
+static struct timespec timespec_from_gpr(gpr_timespec gts) {
+  struct timespec rv;
+  if (sizeof(time_t) < sizeof(int64_t)) {
+    /* fine to assert, as this is only used in gpr_sleep_until */
+    GPR_ASSERT(gts.tv_sec <= INT32_MAX && gts.tv_sec >= INT32_MIN);
+  }
+  rv.tv_sec = (time_t)gts.tv_sec;
+  rv.tv_nsec = gts.tv_nsec;
+  return rv;
+}
+
+#if _POSIX_TIMERS > 0
+static gpr_timespec gpr_from_timespec(struct timespec ts,
+                                      gpr_clock_type clock_type) {
+  /*
+   * timespec.tv_sec can have smaller size than gpr_timespec.tv_sec,
+   * but we are only using this function to implement gpr_now
+   * so there's no need to handle "infinity" values.
+   */
+  gpr_timespec rv;
+  rv.tv_sec = ts.tv_sec;
+  rv.tv_nsec = (int32_t)ts.tv_nsec;
+  rv.clock_type = clock_type;
+  return rv;
+}
+
+/** maps gpr_clock_type --> clockid_t for clock_gettime */
+static const clockid_t clockid_for_gpr_clock[] = {CLOCK_MONOTONIC,
+                                                  CLOCK_REALTIME};
+
+void gpr_time_init(void) { gpr_precise_clock_init(); }
+
+gpr_timespec gpr_now(gpr_clock_type clock_type) {
+  struct timespec now;
+  GPR_ASSERT(clock_type != GPR_TIMESPAN);
+  if (clock_type == GPR_CLOCK_PRECISE) {
+    gpr_timespec ret;
+    gpr_precise_clock_now(&ret);
+    return ret;
+  } else {
+#if defined(GPR_BACKWARDS_COMPATIBILITY_MODE) && defined(__linux__)
+    /* avoid ABI problems by invoking syscalls directly */
+    syscall(SYS_clock_gettime, clockid_for_gpr_clock[clock_type], &now);
+#else
+    clock_gettime(clockid_for_gpr_clock[clock_type], &now);
+#endif
+    return gpr_from_timespec(now, clock_type);
+  }
+}
+#else
+/* For some reason Apple's OSes haven't implemented clock_gettime. */
+
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <sys/time.h>
+
+static double g_time_scale;
+static uint64_t g_time_start;
+
+void gpr_time_init(void) {
+  mach_timebase_info_data_t tb = {0, 1};
+  gpr_precise_clock_init();
+  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;
+  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 = (int64_t)(now_dbl * 1e-9);
+      now.tv_nsec = (int32_t)(now_dbl - ((double)now.tv_sec) * 1e9);
+      break;
+    case GPR_CLOCK_PRECISE:
+      gpr_precise_clock_now(&now);
+      break;
+    case GPR_TIMESPAN:
+      abort();
+  }
+
+  return now;
+}
+#endif
+
+void gpr_sleep_until(gpr_timespec until) {
+  gpr_timespec now;
+  gpr_timespec delta;
+  struct timespec delta_ts;
+  int ns_result;
+
+  for (;;) {
+    /* We could simplify by using clock_nanosleep instead, but it might be
+     * slightly less portable. */
+    now = gpr_now(until.clock_type);
+    if (gpr_time_cmp(until, now) <= 0) {
+      return;
+    }
+
+    delta = gpr_time_sub(until, now);
+    delta_ts = timespec_from_gpr(delta);
+    GRPC_SCHEDULING_START_BLOCKING_REGION;
+    ns_result = nanosleep(&delta_ts, NULL);
+    GRPC_SCHEDULING_END_BLOCKING_REGION;
+    if (ns_result == 0) {
+      break;
+    }
+  }
+}
+
+#endif /* GPR_POSIX_TIME */
diff --git a/src/core/lib/support/time_precise.c b/src/core/lib/support/time_precise.c
new file mode 100644
index 0000000..31ac47e
--- /dev/null
+++ b/src/core/lib/support/time_precise.c
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <stdio.h>
+
+#ifdef GRPC_TIMERS_RDTSC
+#if defined(__i386__)
+static void gpr_get_cycle_counter(long long int *clk) {
+  long long int ret;
+  __asm__ volatile("rdtsc" : "=A"(ret));
+  *clk = ret;
+}
+
+// ----------------------------------------------------------------
+#elif defined(__x86_64__) || defined(__amd64__)
+static void gpr_get_cycle_counter(long long int *clk) {
+  unsigned long long low, high;
+  __asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
+  *clk = (long long)(high << 32) | (long long)low;
+}
+#endif
+
+static double cycles_per_second = 0;
+static long long int start_cycle;
+void gpr_precise_clock_init(void) {
+  time_t start;
+  long long end_cycle;
+  gpr_log(GPR_DEBUG, "Calibrating timers");
+  start = time(NULL);
+  while (time(NULL) == start)
+    ;
+  gpr_get_cycle_counter(&start_cycle);
+  while (time(NULL) <= start + 10)
+    ;
+  gpr_get_cycle_counter(&end_cycle);
+  cycles_per_second = (double)(end_cycle - start_cycle) / 10.0;
+  gpr_log(GPR_DEBUG, "... cycles_per_second = %f\n", cycles_per_second);
+}
+
+void gpr_precise_clock_now(gpr_timespec *clk) {
+  long long int counter;
+  double secs;
+  gpr_get_cycle_counter(&counter);
+  secs = (double)(counter - start_cycle) / cycles_per_second;
+  clk->clock_type = GPR_CLOCK_PRECISE;
+  clk->tv_sec = (int64_t)secs;
+  clk->tv_nsec = (int32_t)(1e9 * (secs - (double)clk->tv_sec));
+}
+
+#else  /* GRPC_TIMERS_RDTSC */
+void gpr_precise_clock_init(void) {}
+
+void gpr_precise_clock_now(gpr_timespec *clk) {
+  *clk = gpr_now(GPR_CLOCK_REALTIME);
+  clk->clock_type = GPR_CLOCK_PRECISE;
+}
+#endif /* GRPC_TIMERS_RDTSC */
diff --git a/src/core/lib/support/time_precise.h b/src/core/lib/support/time_precise.h
new file mode 100644
index 0000000..e1faee1
--- /dev/null
+++ b/src/core/lib/support/time_precise.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_TIME_PRECISE_H
+#define GRPC_CORE_LIB_SUPPORT_TIME_PRECISE_H
+
+#include <grpc/support/time.h>
+
+void gpr_precise_clock_init(void);
+void gpr_precise_clock_now(gpr_timespec *clk);
+
+#endif /* GRPC_CORE_LIB_SUPPORT_TIME_PRECISE_H */
diff --git a/src/core/lib/support/time_win32.c b/src/core/lib/support/time_win32.c
new file mode 100644
index 0000000..a6ac003
--- /dev/null
+++ b/src/core/lib/support/time_win32.c
@@ -0,0 +1,110 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Win32 code for gpr time support. */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <limits.h>
+#include <process.h>
+#include <sys/timeb.h>
+
+#include "src/core/lib/support/block_annotate.h"
+#include "src/core/lib/support/time_precise.h"
+
+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 / (double)frequency.QuadPart;
+}
+
+gpr_timespec gpr_now(gpr_clock_type clock) {
+  gpr_timespec now_tv;
+  LONGLONG diff;
+  struct _timeb now_tb;
+  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 = (int64_t)now_tb.time;
+      now_tv.tv_nsec = now_tb.millitm * 1000000;
+      break;
+    case GPR_CLOCK_MONOTONIC:
+    case GPR_CLOCK_PRECISE:
+      QueryPerformanceCounter(&timestamp);
+      diff = timestamp.QuadPart - g_start_time.QuadPart;
+      now_dbl = (double)diff * g_time_scale;
+      now_tv.tv_sec = (int64_t)now_dbl;
+      now_tv.tv_nsec = (int32_t)((now_dbl - (double)now_tv.tv_sec) * 1e9);
+      break;
+    case GPR_TIMESPAN:
+      abort();
+      break;
+  }
+  return now_tv;
+}
+
+void gpr_sleep_until(gpr_timespec until) {
+  gpr_timespec now;
+  gpr_timespec delta;
+  int64_t sleep_millis;
+
+  for (;;) {
+    /* We could simplify by using clock_nanosleep instead, but it might be
+     * slightly less portable. */
+    now = gpr_now(until.clock_type);
+    if (gpr_time_cmp(until, now) <= 0) {
+      return;
+    }
+
+    delta = gpr_time_sub(until, now);
+    sleep_millis =
+        delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
+    GPR_ASSERT((sleep_millis >= 0) && (sleep_millis <= INT_MAX));
+    GRPC_SCHEDULING_START_BLOCKING_REGION;
+    Sleep((DWORD)sleep_millis);
+    GRPC_SCHEDULING_END_BLOCKING_REGION;
+  }
+}
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/lib/support/tls_pthread.c b/src/core/lib/support/tls_pthread.c
new file mode 100644
index 0000000..bdc7ed1
--- /dev/null
+++ b/src/core/lib/support/tls_pthread.c
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_PTHREAD_TLS
+
+#include <grpc/support/tls.h>
+
+intptr_t gpr_tls_set(struct gpr_pthread_thread_local *tls, intptr_t value) {
+  GPR_ASSERT(0 == pthread_setspecific(tls->key, (void *)value));
+  return value;
+}
+
+#endif /* GPR_PTHREAD_TLS */
diff --git a/src/core/lib/support/tmpfile.h b/src/core/lib/support/tmpfile.h
new file mode 100644
index 0000000..4fec207
--- /dev/null
+++ b/src/core/lib/support/tmpfile.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_TMPFILE_H
+#define GRPC_CORE_LIB_SUPPORT_TMPFILE_H
+
+#include <stdio.h>
+
+#include <grpc/support/slice.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Creates a temporary file from a prefix.
+   If tmp_filename is not NULL, *tmp_filename is assigned the name of the
+   created file and it is the responsibility of the caller to gpr_free it
+   unless an error occurs in which case it will be set to NULL. */
+FILE *gpr_tmpfile(const char *prefix, char **tmp_filename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_SUPPORT_TMPFILE_H */
diff --git a/src/core/lib/support/tmpfile_posix.c b/src/core/lib/support/tmpfile_posix.c
new file mode 100644
index 0000000..743f45e
--- /dev/null
+++ b/src/core/lib/support/tmpfile_posix.c
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_FILE
+
+#include "src/core/lib/support/tmpfile.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/support/string.h"
+
+FILE *gpr_tmpfile(const char *prefix, char **tmp_filename) {
+  FILE *result = NULL;
+  char *template;
+  int fd;
+
+  if (tmp_filename != NULL) *tmp_filename = NULL;
+
+  gpr_asprintf(&template, "/tmp/%s_XXXXXX", prefix);
+  GPR_ASSERT(template != NULL);
+
+  fd = mkstemp(template);
+  if (fd == -1) {
+    gpr_log(GPR_ERROR, "mkstemp failed for template %s with error %s.",
+            template, strerror(errno));
+    goto end;
+  }
+  result = fdopen(fd, "w+");
+  if (result == NULL) {
+    gpr_log(GPR_ERROR, "Could not open file %s from fd %d (error = %s).",
+            template, fd, strerror(errno));
+    unlink(template);
+    close(fd);
+    goto end;
+  }
+
+end:
+  if (result != NULL && tmp_filename != NULL) {
+    *tmp_filename = template;
+  } else {
+    gpr_free(template);
+  }
+  return result;
+}
+
+#endif /* GPR_POSIX_FILE */
diff --git a/src/core/lib/support/tmpfile_win32.c b/src/core/lib/support/tmpfile_win32.c
new file mode 100644
index 0000000..05d92b6
--- /dev/null
+++ b/src/core/lib/support/tmpfile_win32.c
@@ -0,0 +1,84 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include <io.h>
+#include <stdio.h>
+#include <string.h>
+#include <tchar.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/support/string_win32.h"
+#include "src/core/lib/support/tmpfile.h"
+
+FILE *gpr_tmpfile(const char *prefix, char **tmp_filename_out) {
+  FILE *result = NULL;
+  LPTSTR template_string = NULL;
+  TCHAR tmp_path[MAX_PATH];
+  TCHAR tmp_filename[MAX_PATH];
+  DWORD status;
+  UINT success;
+
+  if (tmp_filename_out != NULL) *tmp_filename_out = NULL;
+
+  /* Convert our prefix to TCHAR. */
+  template_string = gpr_char_to_tchar(prefix);
+  GPR_ASSERT(template_string);
+
+  /* Get the path to the best temporary folder available. */
+  status = GetTempPath(MAX_PATH, tmp_path);
+  if (status == 0 || status > MAX_PATH) goto end;
+
+  /* Generate a unique filename with our template + temporary path. */
+  success = GetTempFileName(tmp_path, template_string, 0, tmp_filename);
+  if (!success) goto end;
+
+  /* Open a file there. */
+  if (_tfopen_s(&result, tmp_filename, TEXT("wb+")) != 0) goto end;
+
+end:
+  if (result && tmp_filename_out) {
+    *tmp_filename_out = gpr_tchar_to_char(tmp_filename);
+  }
+
+  gpr_free(template_string);
+  return result;
+}
+
+#endif /* GPR_WIN32 */
diff --git a/src/core/support/wrap_memcpy.c b/src/core/lib/support/wrap_memcpy.c
similarity index 100%
rename from src/core/support/wrap_memcpy.c
rename to src/core/lib/support/wrap_memcpy.c
diff --git a/src/core/lib/surface/alarm.c b/src/core/lib/surface/alarm.c
new file mode 100644
index 0000000..3686833
--- /dev/null
+++ b/src/core/lib/surface/alarm.c
@@ -0,0 +1,84 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/surface/completion_queue.h"
+
+struct grpc_alarm {
+  grpc_timer alarm;
+  grpc_cq_completion completion;
+  /** completion queue where events about this alarm will be posted */
+  grpc_completion_queue *cq;
+  /** user supplied tag */
+  void *tag;
+};
+
+static void do_nothing_end_completion(grpc_exec_ctx *exec_ctx, void *arg,
+                                      grpc_cq_completion *c) {}
+
+static void alarm_cb(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  grpc_alarm *alarm = arg;
+  grpc_cq_end_op(exec_ctx, alarm->cq, alarm->tag, success,
+                 do_nothing_end_completion, NULL, &alarm->completion);
+}
+
+grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq, gpr_timespec deadline,
+                              void *tag) {
+  grpc_alarm *alarm = gpr_malloc(sizeof(grpc_alarm));
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  GRPC_CQ_INTERNAL_REF(cq, "alarm");
+  alarm->cq = cq;
+  alarm->tag = tag;
+
+  grpc_cq_begin_op(cq, tag);
+  grpc_timer_init(&exec_ctx, &alarm->alarm,
+                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
+                  alarm_cb, alarm, gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_exec_ctx_finish(&exec_ctx);
+  return alarm;
+}
+
+void grpc_alarm_cancel(grpc_alarm *alarm) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_timer_cancel(&exec_ctx, &alarm->alarm);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+void grpc_alarm_destroy(grpc_alarm *alarm) {
+  grpc_alarm_cancel(alarm);
+  GRPC_CQ_INTERNAL_UNREF(alarm->cq, "alarm");
+  gpr_free(alarm);
+}
diff --git a/src/core/lib/surface/api_trace.c b/src/core/lib/surface/api_trace.c
new file mode 100644
index 0000000..3702c02
--- /dev/null
+++ b/src/core/lib/surface/api_trace.c
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/api_trace.h"
+
+int grpc_api_trace = 0;
diff --git a/src/core/lib/surface/api_trace.h b/src/core/lib/surface/api_trace.h
new file mode 100644
index 0000000..b50011c
--- /dev/null
+++ b/src/core/lib/surface/api_trace.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_API_TRACE_H
+#define GRPC_CORE_LIB_SURFACE_API_TRACE_H
+
+#include <grpc/support/log.h>
+#include "src/core/lib/debug/trace.h"
+
+extern int grpc_api_trace;
+
+/* Provide unwrapping macros because we're in C89 and variadic macros weren't
+   introduced until C99... */
+#define GRPC_API_TRACE_UNWRAP0()
+#define GRPC_API_TRACE_UNWRAP1(a) , a
+#define GRPC_API_TRACE_UNWRAP2(a, b) , a, b
+#define GRPC_API_TRACE_UNWRAP3(a, b, c) , a, b, c
+#define GRPC_API_TRACE_UNWRAP4(a, b, c, d) , a, b, c, d
+#define GRPC_API_TRACE_UNWRAP5(a, b, c, d, e) , a, b, c, d, e
+#define GRPC_API_TRACE_UNWRAP6(a, b, c, d, e, f) , a, b, c, d, e, f
+#define GRPC_API_TRACE_UNWRAP7(a, b, c, d, e, f, g) , a, b, c, d, e, f, g
+#define GRPC_API_TRACE_UNWRAP8(a, b, c, d, e, f, g, h) , a, b, c, d, e, f, g, h
+#define GRPC_API_TRACE_UNWRAP9(a, b, c, d, e, f, g, h, i) \
+  , a, b, c, d, e, f, g, h, i
+#define GRPC_API_TRACE_UNWRAP10(a, b, c, d, e, f, g, h, i, j) \
+  , a, b, c, d, e, f, g, h, i, j
+
+/* Due to the limitations of C89's preprocessor, the arity of the var-arg list
+   'nargs' must be specified. */
+#define GRPC_API_TRACE(fmt, nargs, args)                      \
+  if (grpc_api_trace) {                                       \
+    gpr_log(GPR_INFO, fmt GRPC_API_TRACE_UNWRAP##nargs args); \
+  }
+
+#endif /* GRPC_CORE_LIB_SURFACE_API_TRACE_H */
diff --git a/src/core/lib/surface/byte_buffer.c b/src/core/lib/surface/byte_buffer.c
new file mode 100644
index 0000000..03071ef
--- /dev/null
+++ b/src/core/lib/surface/byte_buffer.c
@@ -0,0 +1,97 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/byte_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+grpc_byte_buffer *grpc_raw_byte_buffer_create(gpr_slice *slices,
+                                              size_t nslices) {
+  return grpc_raw_compressed_byte_buffer_create(slices, nslices,
+                                                GRPC_COMPRESS_NONE);
+}
+
+grpc_byte_buffer *grpc_raw_compressed_byte_buffer_create(
+    gpr_slice *slices, size_t nslices, grpc_compression_algorithm compression) {
+  size_t i;
+  grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer));
+  bb->type = GRPC_BB_RAW;
+  bb->data.raw.compression = compression;
+  gpr_slice_buffer_init(&bb->data.raw.slice_buffer);
+  for (i = 0; i < nslices; i++) {
+    gpr_slice_ref(slices[i]);
+    gpr_slice_buffer_add(&bb->data.raw.slice_buffer, slices[i]);
+  }
+  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:
+      return grpc_raw_byte_buffer_create(bb->data.raw.slice_buffer.slices,
+                                         bb->data.raw.slice_buffer.count);
+  }
+  GPR_UNREACHABLE_CODE(return NULL);
+}
+
+void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) {
+  if (!bb) return;
+  switch (bb->type) {
+    case GRPC_BB_RAW:
+      gpr_slice_buffer_destroy(&bb->data.raw.slice_buffer);
+      break;
+  }
+  free(bb);
+}
+
+size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) {
+  switch (bb->type) {
+    case GRPC_BB_RAW:
+      return bb->data.raw.slice_buffer.length;
+  }
+  GPR_UNREACHABLE_CODE(return 0);
+}
diff --git a/src/core/lib/surface/byte_buffer_reader.c b/src/core/lib/surface/byte_buffer_reader.c
new file mode 100644
index 0000000..7248f5f
--- /dev/null
+++ b/src/core/lib/surface/byte_buffer_reader.c
@@ -0,0 +1,123 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/byte_buffer_reader.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/compression.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice_buffer.h>
+
+#include "src/core/lib/compression/message_compress.h"
+
+static int is_compressed(grpc_byte_buffer *buffer) {
+  switch (buffer->type) {
+    case GRPC_BB_RAW:
+      if (buffer->data.raw.compression == GRPC_COMPRESS_NONE) {
+        return 0 /* GPR_FALSE */;
+      }
+      break;
+  }
+  return 1 /* GPR_TRUE */;
+}
+
+void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
+                                  grpc_byte_buffer *buffer) {
+  gpr_slice_buffer decompressed_slices_buffer;
+  reader->buffer_in = buffer;
+  switch (reader->buffer_in->type) {
+    case GRPC_BB_RAW:
+      gpr_slice_buffer_init(&decompressed_slices_buffer);
+      if (is_compressed(reader->buffer_in)) {
+        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);
+        gpr_slice_buffer_destroy(&decompressed_slices_buffer);
+      } else { /* not compressed, use the input buffer as output */
+        reader->buffer_out = reader->buffer_in;
+      }
+      reader->current.index = 0;
+      break;
+  }
+}
+
+void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) {
+  switch (reader->buffer_in->type) {
+    case GRPC_BB_RAW:
+      /* keeping the same if-else structure as in the init function */
+      if (is_compressed(reader->buffer_in)) {
+        grpc_byte_buffer_destroy(reader->buffer_out);
+      }
+      break;
+  }
+}
+
+int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
+                                 gpr_slice *slice) {
+  switch (reader->buffer_in->type) {
+    case GRPC_BB_RAW: {
+      gpr_slice_buffer *slice_buffer;
+      slice_buffer = &reader->buffer_out->data.raw.slice_buffer;
+      if (reader->current.index < slice_buffer->count) {
+        *slice = gpr_slice_ref(slice_buffer->slices[reader->current.index]);
+        reader->current.index += 1;
+        return 1;
+      }
+      break;
+    }
+  }
+  return 0;
+}
+
+gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) {
+  gpr_slice in_slice;
+  size_t bytes_read = 0;
+  const size_t input_size = grpc_byte_buffer_length(reader->buffer_out);
+  gpr_slice out_slice = gpr_slice_malloc(input_size);
+  uint8_t *const outbuf = GPR_SLICE_START_PTR(out_slice); /* just an alias */
+
+  while (grpc_byte_buffer_reader_next(reader, &in_slice) != 0) {
+    const size_t slice_length = GPR_SLICE_LENGTH(in_slice);
+    memcpy(&(outbuf[bytes_read]), GPR_SLICE_START_PTR(in_slice), slice_length);
+    bytes_read += slice_length;
+    gpr_slice_unref(in_slice);
+    GPR_ASSERT(bytes_read <= input_size);
+  }
+  return out_slice;
+}
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
new file mode 100644
index 0000000..d63a4a7
--- /dev/null
+++ b/src/core/lib/surface/call.c
@@ -0,0 +1,1491 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/compression.h>
+#include <grpc/grpc.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/lib/channel/channel_stack.h"
+#include "src/core/lib/compression/algorithm_metadata.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/completion_queue.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+/** The maximum number of concurrent batches 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_BATCHES 6
+
+typedef struct {
+  grpc_ioreq_completion_func on_complete;
+  void *user_data;
+  int success;
+} completed_request;
+
+#define MAX_SEND_EXTRA_METADATA_COUNT 3
+
+/* Status data for a request can come from several sources; this
+   enumerates them all, and acts as a priority sorting for which
+   status to return to the application - earlier entries override
+   later ones */
+typedef enum {
+  /* Status came from the application layer overriding whatever
+     the wire says */
+  STATUS_FROM_API_OVERRIDE = 0,
+  /* Status was created by some internal channel stack operation */
+  STATUS_FROM_CORE,
+  /* 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;
+
+typedef struct {
+  uint8_t is_set;
+  grpc_status_code code;
+  grpc_mdstr *details;
+} received_status;
+
+/* How far through the GRPC stream have we read? */
+typedef enum {
+  /* We are still waiting for initial metadata to complete */
+  READ_STATE_INITIAL = 0,
+  /* We have gotten initial metadata, and are reading either
+     messages or trailing metadata */
+  READ_STATE_GOT_INITIAL_METADATA,
+  /* The stream is closed for reading */
+  READ_STATE_READ_CLOSED,
+  /* The stream is closed for reading & writing */
+  READ_STATE_STREAM_CLOSED
+} read_state;
+
+typedef enum {
+  WRITE_STATE_INITIAL = 0,
+  WRITE_STATE_STARTED,
+  WRITE_STATE_WRITE_CLOSED
+} write_state;
+
+typedef struct batch_control {
+  grpc_call *call;
+  grpc_cq_completion cq_completion;
+  grpc_closure finish_batch;
+  void *notify_tag;
+  gpr_refcount steps_to_complete;
+
+  uint8_t send_initial_metadata;
+  uint8_t send_message;
+  uint8_t send_final_op;
+  uint8_t recv_initial_metadata;
+  uint8_t recv_message;
+  uint8_t recv_final_op;
+  uint8_t is_notify_tag_closure;
+  uint8_t success;
+} batch_control;
+
+struct grpc_call {
+  grpc_completion_queue *cq;
+  grpc_channel *channel;
+  grpc_call *parent;
+  grpc_call *first_child;
+  /* TODO(ctiller): share with cq if possible? */
+  gpr_mu mu;
+
+  /* client or server call */
+  uint8_t is_client;
+  /* is the alarm set */
+  uint8_t have_alarm;
+  /** has grpc_call_destroy been called */
+  uint8_t destroy_called;
+  /** flag indicating that cancellation is inherited */
+  uint8_t cancellation_is_inherited;
+  /** bitmask of live batches */
+  uint8_t used_batches;
+  /** which ops are in-flight */
+  uint8_t sent_initial_metadata;
+  uint8_t sending_message;
+  uint8_t sent_final_op;
+  uint8_t received_initial_metadata;
+  uint8_t receiving_message;
+  uint8_t received_final_op;
+
+  /* have we received initial metadata */
+  bool has_initial_md_been_received;
+
+  batch_control active_batches[MAX_CONCURRENT_BATCHES];
+
+  /* first idx: is_receiving, second idx: is_trailing */
+  grpc_metadata_batch metadata_batch[2][2];
+
+  /* Buffered read metadata waiting to be returned to the application.
+     Element 0 is initial metadata, element 1 is trailing metadata. */
+  grpc_metadata_array *buffered_metadata[2];
+
+  /* Received call statuses from various sources */
+  received_status status[STATUS_SOURCE_COUNT];
+
+  /* Compression algorithm for the call */
+  grpc_compression_algorithm compression_algorithm;
+  /* Supported encodings (compression algorithms), a bitset */
+  uint32_t encodings_accepted_by_peer;
+
+  /* Contexts for various subsystems (security, tracing, ...). */
+  grpc_call_context_element context[GRPC_CONTEXT_COUNT];
+
+  /* Deadline alarm - if have_alarm is non-zero */
+  grpc_timer alarm;
+
+  /* for the client, extra metadata is initial metadata; for the
+     server, it's trailing metadata */
+  grpc_linked_mdelem send_extra_metadata[MAX_SEND_EXTRA_METADATA_COUNT];
+  int send_extra_metadata_count;
+  gpr_timespec send_deadline;
+
+  /** siblings: children of the same parent form a list, and this list is
+     protected under
+      parent->mu */
+  grpc_call *sibling_next;
+  grpc_call *sibling_prev;
+
+  grpc_slice_buffer_stream sending_stream;
+  grpc_byte_stream *receiving_stream;
+  grpc_byte_buffer **receiving_buffer;
+  gpr_slice receiving_slice;
+  grpc_closure receiving_slice_ready;
+  grpc_closure receiving_stream_ready;
+  grpc_closure receiving_initial_metadata_ready;
+  uint32_t test_only_last_message_flags;
+
+  union {
+    struct {
+      grpc_status_code *status;
+      char **status_details;
+      size_t *status_details_capacity;
+    } client;
+    struct {
+      int *cancelled;
+    } server;
+  } final_op;
+
+  struct {
+    void *bctlp;
+    bool success;
+  } saved_receiving_stream_ready_ctx;
+};
+
+#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
+#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1)
+#define CALL_ELEM_FROM_CALL(call, idx) \
+  grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx)
+#define CALL_FROM_TOP_ELEM(top_elem) \
+  CALL_FROM_CALL_STACK(grpc_call_stack_from_top_element(top_elem))
+
+static void set_deadline_alarm(grpc_exec_ctx *exec_ctx, grpc_call *call,
+                               gpr_timespec deadline);
+static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
+                       grpc_transport_stream_op *op);
+static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+                                          grpc_status_code status,
+                                          const char *description);
+static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack,
+                         bool success);
+static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
+                                  bool success);
+
+grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
+                            uint32_t propagation_mask,
+                            grpc_completion_queue *cq,
+                            const void *server_transport_data,
+                            grpc_mdelem **add_initial_metadata,
+                            size_t add_initial_metadata_count,
+                            gpr_timespec send_deadline) {
+  size_t i, j;
+  grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_call *call;
+  GPR_TIMER_BEGIN("grpc_call_create", 0);
+  call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
+  memset(call, 0, sizeof(grpc_call));
+  gpr_mu_init(&call->mu);
+  call->channel = channel;
+  call->cq = cq;
+  call->parent = parent_call;
+  call->is_client = server_transport_data == NULL;
+  if (call->is_client) {
+    GPR_ASSERT(add_initial_metadata_count < MAX_SEND_EXTRA_METADATA_COUNT);
+    for (i = 0; i < add_initial_metadata_count; i++) {
+      call->send_extra_metadata[i].md = add_initial_metadata[i];
+    }
+    call->send_extra_metadata_count = (int)add_initial_metadata_count;
+  } else {
+    GPR_ASSERT(add_initial_metadata_count == 0);
+    call->send_extra_metadata_count = 0;
+  }
+  for (i = 0; i < 2; i++) {
+    for (j = 0; j < 2; j++) {
+      call->metadata_batch[i][j].deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+    }
+  }
+  call->send_deadline = send_deadline;
+  GRPC_CHANNEL_INTERNAL_REF(channel, "call");
+  /* initial refcount dropped by grpc_call_destroy */
+  grpc_call_stack_init(&exec_ctx, channel_stack, 1, destroy_call, call,
+                       call->context, server_transport_data,
+                       CALL_STACK_FROM_CALL(call));
+  if (cq != NULL) {
+    GRPC_CQ_INTERNAL_REF(cq, "bind");
+    grpc_call_stack_set_pollset(&exec_ctx, CALL_STACK_FROM_CALL(call),
+                                grpc_cq_pollset(cq));
+  }
+  if (parent_call != NULL) {
+    GRPC_CALL_INTERNAL_REF(parent_call, "child");
+    GPR_ASSERT(call->is_client);
+    GPR_ASSERT(!parent_call->is_client);
+
+    gpr_mu_lock(&parent_call->mu);
+
+    if (propagation_mask & GRPC_PROPAGATE_DEADLINE) {
+      send_deadline = gpr_time_min(
+          gpr_convert_clock_type(send_deadline,
+                                 parent_call->send_deadline.clock_type),
+          parent_call->send_deadline);
+    }
+    /* for now GRPC_PROPAGATE_TRACING_CONTEXT *MUST* be passed with
+     * GRPC_PROPAGATE_STATS_CONTEXT */
+    /* TODO(ctiller): This should change to use the appropriate census start_op
+     * call. */
+    if (propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) {
+      GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
+      grpc_call_context_set(call, GRPC_CONTEXT_TRACING,
+                            parent_call->context[GRPC_CONTEXT_TRACING].value,
+                            NULL);
+    } else {
+      GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
+    }
+    if (propagation_mask & GRPC_PROPAGATE_CANCELLATION) {
+      call->cancellation_is_inherited = 1;
+    }
+
+    if (parent_call->first_child == NULL) {
+      parent_call->first_child = call;
+      call->sibling_next = call->sibling_prev = call;
+    } else {
+      call->sibling_next = parent_call->first_child;
+      call->sibling_prev = parent_call->first_child->sibling_prev;
+      call->sibling_next->sibling_prev = call->sibling_prev->sibling_next =
+          call;
+    }
+
+    gpr_mu_unlock(&parent_call->mu);
+  }
+  if (gpr_time_cmp(send_deadline, gpr_inf_future(send_deadline.clock_type)) !=
+      0) {
+    set_deadline_alarm(&exec_ctx, call, send_deadline);
+  }
+  grpc_exec_ctx_finish(&exec_ctx);
+  GPR_TIMER_END("grpc_call_create", 0);
+  return call;
+}
+
+void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call,
+                                    grpc_completion_queue *cq) {
+  GPR_ASSERT(cq);
+  call->cq = cq;
+  GRPC_CQ_INTERNAL_REF(cq, "bind");
+  grpc_call_stack_set_pollset(exec_ctx, CALL_STACK_FROM_CALL(call),
+                              grpc_cq_pollset(cq));
+}
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+#define REF_REASON reason
+#define REF_ARG , const char *reason
+#else
+#define REF_REASON ""
+#define REF_ARG
+#endif
+void grpc_call_internal_ref(grpc_call *c REF_ARG) {
+  GRPC_CALL_STACK_REF(CALL_STACK_FROM_CALL(c), REF_REASON);
+}
+void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c REF_ARG) {
+  GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON);
+}
+
+static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, bool success) {
+  size_t i;
+  int ii;
+  grpc_call *c = call;
+  GPR_TIMER_BEGIN("destroy_call", 0);
+  for (i = 0; i < 2; i++) {
+    grpc_metadata_batch_destroy(
+        &c->metadata_batch[1 /* is_receiving */][i /* is_initial */]);
+  }
+  if (c->receiving_stream != NULL) {
+    grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
+  }
+  grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c));
+  GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->channel, "call");
+  gpr_mu_destroy(&c->mu);
+  for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+    if (c->status[i].details) {
+      GRPC_MDSTR_UNREF(c->status[i].details);
+    }
+  }
+  for (ii = 0; ii < c->send_extra_metadata_count; ii++) {
+    GRPC_MDELEM_UNREF(c->send_extra_metadata[ii].md);
+  }
+  for (i = 0; i < GRPC_CONTEXT_COUNT; i++) {
+    if (c->context[i].destroy) {
+      c->context[i].destroy(c->context[i].value);
+    }
+  }
+  if (c->cq) {
+    GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
+  }
+  gpr_free(c);
+  GPR_TIMER_END("destroy_call", 0);
+}
+
+static void set_status_code(grpc_call *call, status_source source,
+                            uint32_t status) {
+  if (call->status[source].is_set) return;
+
+  call->status[source].is_set = 1;
+  call->status[source].code = (grpc_status_code)status;
+
+  /* TODO(ctiller): what to do about the flush that was previously here */
+}
+
+static void set_compression_algorithm(grpc_call *call,
+                                      grpc_compression_algorithm algo) {
+  call->compression_algorithm = algo;
+}
+
+grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm(
+    grpc_call *call) {
+  grpc_compression_algorithm algorithm;
+  gpr_mu_lock(&call->mu);
+  algorithm = call->compression_algorithm;
+  gpr_mu_unlock(&call->mu);
+  return algorithm;
+}
+
+uint32_t grpc_call_test_only_get_message_flags(grpc_call *call) {
+  uint32_t flags;
+  gpr_mu_lock(&call->mu);
+  flags = call->test_only_last_message_flags;
+  gpr_mu_unlock(&call->mu);
+  return flags;
+}
+
+static void destroy_encodings_accepted_by_peer(void *p) { return; }
+
+static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) {
+  size_t i;
+  grpc_compression_algorithm algorithm;
+  gpr_slice_buffer accept_encoding_parts;
+  gpr_slice accept_encoding_slice;
+  void *accepted_user_data;
+
+  accepted_user_data =
+      grpc_mdelem_get_user_data(mdel, destroy_encodings_accepted_by_peer);
+  if (accepted_user_data != NULL) {
+    call->encodings_accepted_by_peer =
+        (uint32_t)(((uintptr_t)accepted_user_data) - 1);
+    return;
+  }
+
+  accept_encoding_slice = mdel->value->slice;
+  gpr_slice_buffer_init(&accept_encoding_parts);
+  gpr_slice_split(accept_encoding_slice, ",", &accept_encoding_parts);
+
+  /* No need to zero call->encodings_accepted_by_peer: grpc_call_create already
+   * zeroes the whole grpc_call */
+  /* Always support no compression */
+  GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
+  for (i = 0; i < accept_encoding_parts.count; i++) {
+    const gpr_slice *accept_encoding_entry_slice =
+        &accept_encoding_parts.slices[i];
+    if (grpc_compression_algorithm_parse(
+            (const char *)GPR_SLICE_START_PTR(*accept_encoding_entry_slice),
+            GPR_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) {
+      GPR_BITSET(&call->encodings_accepted_by_peer, algorithm);
+    } else {
+      char *accept_encoding_entry_str =
+          gpr_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII);
+      gpr_log(GPR_ERROR,
+              "Invalid entry in accept encoding metadata: '%s'. Ignoring.",
+              accept_encoding_entry_str);
+      gpr_free(accept_encoding_entry_str);
+    }
+  }
+
+  gpr_slice_buffer_destroy(&accept_encoding_parts);
+
+  grpc_mdelem_set_user_data(
+      mdel, destroy_encodings_accepted_by_peer,
+      (void *)(((uintptr_t)call->encodings_accepted_by_peer) + 1));
+}
+
+uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) {
+  uint32_t encodings_accepted_by_peer;
+  gpr_mu_lock(&call->mu);
+  encodings_accepted_by_peer = call->encodings_accepted_by_peer;
+  gpr_mu_unlock(&call->mu);
+  return encodings_accepted_by_peer;
+}
+
+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);
+  }
+  call->status[source].details = status;
+}
+
+static void get_final_status(grpc_call *call,
+                             void (*set_value)(grpc_status_code code,
+                                               void *user_data),
+                             void *set_value_user_data) {
+  int i;
+  for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+    if (call->status[i].is_set) {
+      set_value(call->status[i].code, set_value_user_data);
+      return;
+    }
+  }
+  if (call->is_client) {
+    set_value(GRPC_STATUS_UNKNOWN, set_value_user_data);
+  } else {
+    set_value(GRPC_STATUS_OK, set_value_user_data);
+  }
+}
+
+static void get_final_details(grpc_call *call, char **out_details,
+                              size_t *out_details_capacity) {
+  int i;
+  for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+    if (call->status[i].is_set) {
+      if (call->status[i].details) {
+        gpr_slice details = call->status[i].details->slice;
+        size_t len = GPR_SLICE_LENGTH(details);
+        if (len + 1 > *out_details_capacity) {
+          *out_details_capacity =
+              GPR_MAX(len + 1, *out_details_capacity * 3 / 2);
+          *out_details = gpr_realloc(*out_details, *out_details_capacity);
+        }
+        memcpy(*out_details, GPR_SLICE_START_PTR(details), len);
+        (*out_details)[len] = 0;
+      } else {
+        goto no_details;
+      }
+      return;
+    }
+  }
+
+no_details:
+  if (0 == *out_details_capacity) {
+    *out_details_capacity = 8;
+    *out_details = gpr_malloc(*out_details_capacity);
+  }
+  **out_details = 0;
+}
+
+static grpc_linked_mdelem *linked_from_md(grpc_metadata *md) {
+  return (grpc_linked_mdelem *)&md->internal_data;
+}
+
+static int prepare_application_metadata(grpc_call *call, int count,
+                                        grpc_metadata *metadata,
+                                        int is_trailing,
+                                        int prepend_extra_metadata) {
+  int i;
+  grpc_metadata_batch *batch =
+      &call->metadata_batch[0 /* is_receiving */][is_trailing];
+  if (prepend_extra_metadata) {
+    if (call->send_extra_metadata_count == 0) {
+      prepend_extra_metadata = 0;
+    } else {
+      for (i = 0; i < call->send_extra_metadata_count; i++) {
+        GRPC_MDELEM_REF(call->send_extra_metadata[i].md);
+      }
+      for (i = 1; i < call->send_extra_metadata_count; i++) {
+        call->send_extra_metadata[i].prev = &call->send_extra_metadata[i - 1];
+      }
+      for (i = 0; i < call->send_extra_metadata_count - 1; i++) {
+        call->send_extra_metadata[i].next = &call->send_extra_metadata[i + 1];
+      }
+    }
+  }
+  for (i = 0; i < count; i++) {
+    grpc_metadata *md = &metadata[i];
+    grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
+    GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
+    l->md = grpc_mdelem_from_string_and_buffer(
+        md->key, (const uint8_t *)md->value, md->value_length);
+    if (!grpc_header_key_is_legal(grpc_mdstr_as_c_string(l->md->key),
+                                  GRPC_MDSTR_LENGTH(l->md->key))) {
+      gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s",
+              grpc_mdstr_as_c_string(l->md->key));
+      return 0;
+    } else if (!grpc_is_binary_header(grpc_mdstr_as_c_string(l->md->key),
+                                      GRPC_MDSTR_LENGTH(l->md->key)) &&
+               !grpc_header_nonbin_value_is_legal(
+                   grpc_mdstr_as_c_string(l->md->value),
+                   GRPC_MDSTR_LENGTH(l->md->value))) {
+      gpr_log(GPR_ERROR, "attempt to send invalid metadata value");
+      return 0;
+    }
+  }
+  for (i = 1; i < count; i++) {
+    linked_from_md(&metadata[i])->prev = linked_from_md(&metadata[i - 1]);
+  }
+  for (i = 0; i < count - 1; i++) {
+    linked_from_md(&metadata[i])->next = linked_from_md(&metadata[i + 1]);
+  }
+  switch (prepend_extra_metadata * 2 + (count != 0)) {
+    case 0:
+      /* no prepend, no metadata => nothing to do */
+      batch->list.head = batch->list.tail = NULL;
+      break;
+    case 1:
+      /* metadata, but no prepend */
+      batch->list.head = linked_from_md(&metadata[0]);
+      batch->list.tail = linked_from_md(&metadata[count - 1]);
+      batch->list.head->prev = NULL;
+      batch->list.tail->next = NULL;
+      break;
+    case 2:
+      /* prepend, but no md */
+      batch->list.head = &call->send_extra_metadata[0];
+      batch->list.tail =
+          &call->send_extra_metadata[call->send_extra_metadata_count - 1];
+      batch->list.head->prev = NULL;
+      batch->list.tail->next = NULL;
+      break;
+    case 3:
+      /* prepend AND md */
+      batch->list.head = &call->send_extra_metadata[0];
+      call->send_extra_metadata[call->send_extra_metadata_count - 1].next =
+          linked_from_md(&metadata[0]);
+      linked_from_md(&metadata[0])->prev =
+          &call->send_extra_metadata[call->send_extra_metadata_count - 1];
+      batch->list.tail = linked_from_md(&metadata[count - 1]);
+      batch->list.head->prev = NULL;
+      batch->list.tail->next = NULL;
+      break;
+    default:
+      GPR_UNREACHABLE_CODE(return 0);
+  }
+
+  return 1;
+}
+
+void grpc_call_destroy(grpc_call *c) {
+  int cancel;
+  grpc_call *parent = c->parent;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  GPR_TIMER_BEGIN("grpc_call_destroy", 0);
+  GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c));
+
+  if (parent) {
+    gpr_mu_lock(&parent->mu);
+    if (c == parent->first_child) {
+      parent->first_child = c->sibling_next;
+      if (c == parent->first_child) {
+        parent->first_child = NULL;
+      }
+      c->sibling_prev->sibling_next = c->sibling_next;
+      c->sibling_next->sibling_prev = c->sibling_prev;
+    }
+    gpr_mu_unlock(&parent->mu);
+    GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
+  }
+
+  gpr_mu_lock(&c->mu);
+  GPR_ASSERT(!c->destroy_called);
+  c->destroy_called = 1;
+  if (c->have_alarm) {
+    grpc_timer_cancel(&exec_ctx, &c->alarm);
+  }
+  cancel = !c->received_final_op;
+  gpr_mu_unlock(&c->mu);
+  if (cancel) grpc_call_cancel(c, NULL);
+  GRPC_CALL_INTERNAL_UNREF(&exec_ctx, c, "destroy");
+  grpc_exec_ctx_finish(&exec_ctx);
+  GPR_TIMER_END("grpc_call_destroy", 0);
+}
+
+grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) {
+  GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved));
+  GPR_ASSERT(!reserved);
+  return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled",
+                                      NULL);
+}
+
+grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
+                                             grpc_status_code status,
+                                             const char *description,
+                                             void *reserved) {
+  grpc_call_error r;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  GRPC_API_TRACE(
+      "grpc_call_cancel_with_status("
+      "c=%p, status=%d, description=%s, reserved=%p)",
+      4, (c, (int)status, description, reserved));
+  GPR_ASSERT(reserved == NULL);
+  gpr_mu_lock(&c->mu);
+  r = cancel_with_status(&exec_ctx, c, status, description);
+  gpr_mu_unlock(&c->mu);
+  grpc_exec_ctx_finish(&exec_ctx);
+  return r;
+}
+
+typedef struct cancel_closure {
+  grpc_closure closure;
+  grpc_call *call;
+  grpc_status_code status;
+} cancel_closure;
+
+static void done_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) {
+  cancel_closure *cc = ccp;
+  GRPC_CALL_INTERNAL_UNREF(exec_ctx, cc->call, "cancel");
+  gpr_free(cc);
+}
+
+static void send_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) {
+  grpc_transport_stream_op op;
+  cancel_closure *cc = ccp;
+  memset(&op, 0, sizeof(op));
+  op.cancel_with_status = cc->status;
+  /* reuse closure to catch completion */
+  grpc_closure_init(&cc->closure, done_cancel, cc);
+  op.on_complete = &cc->closure;
+  execute_op(exec_ctx, cc->call, &op);
+}
+
+static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+                                          grpc_status_code status,
+                                          const char *description) {
+  grpc_mdstr *details =
+      description ? grpc_mdstr_from_string(description) : NULL;
+  cancel_closure *cc = gpr_malloc(sizeof(*cc));
+
+  GPR_ASSERT(status != GRPC_STATUS_OK);
+
+  set_status_code(c, STATUS_FROM_API_OVERRIDE, (uint32_t)status);
+  set_status_details(c, STATUS_FROM_API_OVERRIDE, details);
+
+  grpc_closure_init(&cc->closure, send_cancel, cc);
+  cc->call = c;
+  cc->status = status;
+  GRPC_CALL_INTERNAL_REF(c, "cancel");
+  grpc_exec_ctx_enqueue(exec_ctx, &cc->closure, true, NULL);
+
+  return GRPC_CALL_OK;
+}
+
+static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
+                       grpc_transport_stream_op *op) {
+  grpc_call_element *elem;
+
+  GPR_TIMER_BEGIN("execute_op", 0);
+  elem = CALL_ELEM_FROM_CALL(call, 0);
+  op->context = call->context;
+  elem->filter->start_transport_stream_op(exec_ctx, elem, op);
+  GPR_TIMER_END("execute_op", 0);
+}
+
+char *grpc_call_get_peer(grpc_call *call) {
+  grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  char *result;
+  GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call));
+  result = elem->filter->get_peer(&exec_ctx, elem);
+  if (result == NULL) {
+    result = grpc_channel_get_target(call->channel);
+  }
+  if (result == NULL) {
+    result = gpr_strdup("unknown");
+  }
+  grpc_exec_ctx_finish(&exec_ctx);
+  return result;
+}
+
+grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
+  return CALL_FROM_TOP_ELEM(elem);
+}
+
+static void call_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  grpc_call *call = arg;
+  gpr_mu_lock(&call->mu);
+  call->have_alarm = 0;
+  if (success) {
+    cancel_with_status(exec_ctx, call, GRPC_STATUS_DEADLINE_EXCEEDED,
+                       "Deadline Exceeded");
+  }
+  gpr_mu_unlock(&call->mu);
+  GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "alarm");
+}
+
+static void set_deadline_alarm(grpc_exec_ctx *exec_ctx, grpc_call *call,
+                               gpr_timespec deadline) {
+  if (call->have_alarm) {
+    gpr_log(GPR_ERROR, "Attempt to set deadline alarm twice");
+    assert(0);
+    return;
+  }
+  GRPC_CALL_INTERNAL_REF(call, "alarm");
+  call->have_alarm = 1;
+  call->send_deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
+  grpc_timer_init(exec_ctx, &call->alarm, call->send_deadline, call_alarm, call,
+                  gpr_now(GPR_CLOCK_MONOTONIC));
+}
+
+/* we offset status by a small amount when storing it into transport metadata
+   as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
+   */
+#define STATUS_OFFSET 1
+static void destroy_status(void *ignored) {}
+
+static uint32_t decode_status(grpc_mdelem *md) {
+  uint32_t status;
+  void *user_data;
+  if (md == GRPC_MDELEM_GRPC_STATUS_0) return 0;
+  if (md == GRPC_MDELEM_GRPC_STATUS_1) return 1;
+  if (md == GRPC_MDELEM_GRPC_STATUS_2) return 2;
+  user_data = grpc_mdelem_get_user_data(md, destroy_status);
+  if (user_data != NULL) {
+    status = ((uint32_t)(intptr_t)user_data) - STATUS_OFFSET;
+  } else {
+    if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
+                                   GPR_SLICE_LENGTH(md->value->slice),
+                                   &status)) {
+      status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
+    }
+    grpc_mdelem_set_user_data(md, destroy_status,
+                              (void *)(intptr_t)(status + STATUS_OFFSET));
+  }
+  return status;
+}
+
+static uint32_t decode_compression(grpc_mdelem *md) {
+  grpc_compression_algorithm algorithm =
+      grpc_compression_algorithm_from_mdstr(md->value);
+  if (algorithm == GRPC_COMPRESS_ALGORITHMS_COUNT) {
+    const char *md_c_str = grpc_mdstr_as_c_string(md->value);
+    gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str);
+  }
+  return algorithm;
+}
+
+static grpc_mdelem *recv_common_filter(grpc_call *call, grpc_mdelem *elem) {
+  if (elem->key == GRPC_MDSTR_GRPC_STATUS) {
+    GPR_TIMER_BEGIN("status", 0);
+    set_status_code(call, STATUS_FROM_WIRE, decode_status(elem));
+    GPR_TIMER_END("status", 0);
+    return NULL;
+  } else if (elem->key == GRPC_MDSTR_GRPC_MESSAGE) {
+    GPR_TIMER_BEGIN("status-details", 0);
+    set_status_details(call, STATUS_FROM_WIRE, GRPC_MDSTR_REF(elem->value));
+    GPR_TIMER_END("status-details", 0);
+    return NULL;
+  }
+  return elem;
+}
+
+static grpc_mdelem *publish_app_metadata(grpc_call *call, grpc_mdelem *elem,
+                                         int is_trailing) {
+  grpc_metadata_array *dest;
+  grpc_metadata *mdusr;
+  GPR_TIMER_BEGIN("publish_app_metadata", 0);
+  dest = call->buffered_metadata[is_trailing];
+  if (dest->count == dest->capacity) {
+    dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2);
+    dest->metadata =
+        gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity);
+  }
+  mdusr = &dest->metadata[dest->count++];
+  mdusr->key = grpc_mdstr_as_c_string(elem->key);
+  mdusr->value = grpc_mdstr_as_c_string(elem->value);
+  mdusr->value_length = GPR_SLICE_LENGTH(elem->value->slice);
+  GPR_TIMER_END("publish_app_metadata", 0);
+  return elem;
+}
+
+static grpc_mdelem *recv_initial_filter(void *callp, grpc_mdelem *elem) {
+  grpc_call *call = callp;
+  elem = recv_common_filter(call, elem);
+  if (elem == NULL) {
+    return NULL;
+  } else if (elem->key == GRPC_MDSTR_GRPC_ENCODING) {
+    GPR_TIMER_BEGIN("compression_algorithm", 0);
+    set_compression_algorithm(call, decode_compression(elem));
+    GPR_TIMER_END("compression_algorithm", 0);
+    return NULL;
+  } else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) {
+    GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0);
+    set_encodings_accepted_by_peer(call, elem);
+    GPR_TIMER_END("encodings_accepted_by_peer", 0);
+    return NULL;
+  } else {
+    return publish_app_metadata(call, elem, 0);
+  }
+}
+
+static grpc_mdelem *recv_trailing_filter(void *callp, grpc_mdelem *elem) {
+  grpc_call *call = callp;
+  elem = recv_common_filter(call, elem);
+  if (elem == NULL) {
+    return NULL;
+  } else {
+    return publish_app_metadata(call, elem, 1);
+  }
+}
+
+grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) {
+  return CALL_STACK_FROM_CALL(call);
+}
+
+/*
+ * BATCH API IMPLEMENTATION
+ */
+
+static void set_status_value_directly(grpc_status_code status, void *dest) {
+  *(grpc_status_code *)dest = status;
+}
+
+static void set_cancelled_value(grpc_status_code status, void *dest) {
+  *(int *)dest = (status != GRPC_STATUS_OK);
+}
+
+static int are_write_flags_valid(uint32_t flags) {
+  /* check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set */
+  const uint32_t allowed_write_positions =
+      (GRPC_WRITE_USED_MASK | GRPC_WRITE_INTERNAL_USED_MASK);
+  const uint32_t invalid_positions = ~allowed_write_positions;
+  return !(flags & invalid_positions);
+}
+
+static batch_control *allocate_batch_control(grpc_call *call) {
+  size_t i;
+  for (i = 0; i < MAX_CONCURRENT_BATCHES; i++) {
+    if ((call->used_batches & (1 << i)) == 0) {
+      call->used_batches = (uint8_t)(call->used_batches | (uint8_t)(1 << i));
+      return &call->active_batches[i];
+    }
+  }
+  return NULL;
+}
+
+static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data,
+                                    grpc_cq_completion *storage) {
+  batch_control *bctl = user_data;
+  grpc_call *call = bctl->call;
+  gpr_mu_lock(&call->mu);
+  call->used_batches = (uint8_t)(
+      call->used_batches & ~(uint8_t)(1 << (bctl - call->active_batches)));
+  gpr_mu_unlock(&call->mu);
+  GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
+}
+
+static void post_batch_completion(grpc_exec_ctx *exec_ctx,
+                                  batch_control *bctl) {
+  grpc_call *call = bctl->call;
+  if (bctl->is_notify_tag_closure) {
+    grpc_exec_ctx_enqueue(exec_ctx, bctl->notify_tag, bctl->success, NULL);
+    gpr_mu_lock(&call->mu);
+    bctl->call->used_batches =
+        (uint8_t)(bctl->call->used_batches &
+                  ~(uint8_t)(1 << (bctl - bctl->call->active_batches)));
+    gpr_mu_unlock(&call->mu);
+    GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
+  } else {
+    grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, bctl->success,
+                   finish_batch_completion, bctl, &bctl->cq_completion);
+  }
+}
+
+static void continue_receiving_slices(grpc_exec_ctx *exec_ctx,
+                                      batch_control *bctl) {
+  grpc_call *call = bctl->call;
+  for (;;) {
+    size_t remaining = call->receiving_stream->length -
+                       (*call->receiving_buffer)->data.raw.slice_buffer.length;
+    if (remaining == 0) {
+      call->receiving_message = 0;
+      grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
+      call->receiving_stream = NULL;
+      if (gpr_unref(&bctl->steps_to_complete)) {
+        post_batch_completion(exec_ctx, bctl);
+      }
+      return;
+    }
+    if (grpc_byte_stream_next(exec_ctx, call->receiving_stream,
+                              &call->receiving_slice, remaining,
+                              &call->receiving_slice_ready)) {
+      gpr_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
+                           call->receiving_slice);
+    } else {
+      return;
+    }
+  }
+}
+
+static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
+                                  bool success) {
+  batch_control *bctl = bctlp;
+  grpc_call *call = bctl->call;
+
+  if (success) {
+    gpr_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
+                         call->receiving_slice);
+    continue_receiving_slices(exec_ctx, bctl);
+  } else {
+    grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
+    call->receiving_stream = NULL;
+    grpc_byte_buffer_destroy(*call->receiving_buffer);
+    *call->receiving_buffer = NULL;
+    if (gpr_unref(&bctl->steps_to_complete)) {
+      post_batch_completion(exec_ctx, bctl);
+    }
+  }
+}
+
+static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl,
+                                  bool success) {
+  grpc_call *call = bctl->call;
+  if (call->receiving_stream == NULL) {
+    *call->receiving_buffer = NULL;
+    call->receiving_message = 0;
+    if (gpr_unref(&bctl->steps_to_complete)) {
+      post_batch_completion(exec_ctx, bctl);
+    }
+  } else if (call->receiving_stream->length >
+             grpc_channel_get_max_message_length(call->channel)) {
+    cancel_with_status(exec_ctx, call, GRPC_STATUS_INTERNAL,
+                       "Max message size exceeded");
+    grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
+    call->receiving_stream = NULL;
+    *call->receiving_buffer = NULL;
+    call->receiving_message = 0;
+    if (gpr_unref(&bctl->steps_to_complete)) {
+      post_batch_completion(exec_ctx, bctl);
+    }
+  } else {
+    call->test_only_last_message_flags = call->receiving_stream->flags;
+    if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
+        (call->compression_algorithm > GRPC_COMPRESS_NONE)) {
+      *call->receiving_buffer = grpc_raw_compressed_byte_buffer_create(
+          NULL, 0, call->compression_algorithm);
+    } else {
+      *call->receiving_buffer = grpc_raw_byte_buffer_create(NULL, 0);
+    }
+    grpc_closure_init(&call->receiving_slice_ready, receiving_slice_ready,
+                      bctl);
+    continue_receiving_slices(exec_ctx, bctl);
+    /* early out */
+    return;
+  }
+}
+
+static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
+                                   bool success) {
+  batch_control *bctl = bctlp;
+  grpc_call *call = bctl->call;
+
+  gpr_mu_lock(&bctl->call->mu);
+  if (bctl->call->has_initial_md_been_received) {
+    gpr_mu_unlock(&bctl->call->mu);
+    process_data_after_md(exec_ctx, bctlp, success);
+  } else {
+    call->saved_receiving_stream_ready_ctx.bctlp = bctlp;
+    call->saved_receiving_stream_ready_ctx.success = success;
+    gpr_mu_unlock(&bctl->call->mu);
+  }
+}
+
+static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
+                                             void *bctlp, bool success) {
+  batch_control *bctl = bctlp;
+  grpc_call *call = bctl->call;
+
+  gpr_mu_lock(&call->mu);
+
+  grpc_metadata_batch *md =
+      &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
+  grpc_metadata_batch_filter(md, recv_initial_filter, call);
+  call->has_initial_md_been_received = true;
+
+  if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) !=
+          0 &&
+      !call->is_client) {
+    GPR_TIMER_BEGIN("set_deadline_alarm", 0);
+    set_deadline_alarm(exec_ctx, call, md->deadline);
+    GPR_TIMER_END("set_deadline_alarm", 0);
+  }
+
+  if (call->saved_receiving_stream_ready_ctx.bctlp != NULL) {
+    grpc_closure *saved_rsr_closure = grpc_closure_create(
+        receiving_stream_ready, call->saved_receiving_stream_ready_ctx.bctlp);
+    grpc_exec_ctx_enqueue(exec_ctx, saved_rsr_closure,
+                          call->saved_receiving_stream_ready_ctx.success, NULL);
+    call->saved_receiving_stream_ready_ctx.bctlp = NULL;
+  }
+
+  gpr_mu_unlock(&call->mu);
+
+  if (gpr_unref(&bctl->steps_to_complete)) {
+    post_batch_completion(exec_ctx, bctl);
+  }
+}
+
+static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp, bool success) {
+  batch_control *bctl = bctlp;
+  grpc_call *call = bctl->call;
+  grpc_call *child_call;
+  grpc_call *next_child_call;
+
+  gpr_mu_lock(&call->mu);
+  if (bctl->send_initial_metadata) {
+    grpc_metadata_batch_destroy(
+        &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]);
+  }
+  if (bctl->send_message) {
+    call->sending_message = 0;
+  }
+  if (bctl->send_final_op) {
+    grpc_metadata_batch_destroy(
+        &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]);
+  }
+  if (bctl->recv_final_op) {
+    grpc_metadata_batch *md =
+        &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
+    grpc_metadata_batch_filter(md, recv_trailing_filter, call);
+
+    if (call->have_alarm) {
+      grpc_timer_cancel(exec_ctx, &call->alarm);
+    }
+    /* propagate cancellation to any interested children */
+    child_call = call->first_child;
+    if (child_call != NULL) {
+      do {
+        next_child_call = child_call->sibling_next;
+        if (child_call->cancellation_is_inherited) {
+          GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
+          grpc_call_cancel(child_call, NULL);
+          GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel");
+        }
+        child_call = next_child_call;
+      } while (child_call != call->first_child);
+    }
+
+    if (call->is_client) {
+      get_final_status(call, set_status_value_directly,
+                       call->final_op.client.status);
+      get_final_details(call, call->final_op.client.status_details,
+                        call->final_op.client.status_details_capacity);
+    } else {
+      get_final_status(call, set_cancelled_value,
+                       call->final_op.server.cancelled);
+    }
+
+    success = 1;
+  }
+  bctl->success = success != 0;
+  gpr_mu_unlock(&call->mu);
+  if (gpr_unref(&bctl->steps_to_complete)) {
+    post_batch_completion(exec_ctx, bctl);
+  }
+}
+
+static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
+                                        grpc_call *call, const grpc_op *ops,
+                                        size_t nops, void *notify_tag,
+                                        int is_notify_tag_closure) {
+  grpc_transport_stream_op stream_op;
+  size_t i;
+  const grpc_op *op;
+  batch_control *bctl;
+  int num_completion_callbacks_needed = 1;
+  grpc_call_error error = GRPC_CALL_OK;
+
+  GPR_TIMER_BEGIN("grpc_call_start_batch", 0);
+
+  GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, notify_tag);
+
+  memset(&stream_op, 0, sizeof(stream_op));
+
+  /* TODO(ctiller): this feels like it could be made lock-free */
+  gpr_mu_lock(&call->mu);
+  bctl = allocate_batch_control(call);
+  memset(bctl, 0, sizeof(*bctl));
+  bctl->call = call;
+  bctl->notify_tag = notify_tag;
+  bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0);
+
+  if (nops == 0) {
+    GRPC_CALL_INTERNAL_REF(call, "completion");
+    bctl->success = 1;
+    if (!is_notify_tag_closure) {
+      grpc_cq_begin_op(call->cq, notify_tag);
+    }
+    gpr_mu_unlock(&call->mu);
+    post_batch_completion(exec_ctx, bctl);
+    error = GRPC_CALL_OK;
+    goto done;
+  }
+
+  /* rewrite batch ops into a transport op */
+  for (i = 0; i < nops; i++) {
+    op = &ops[i];
+    if (op->reserved != NULL) {
+      error = GRPC_CALL_ERROR;
+      goto done_with_error;
+    }
+    switch (op->op) {
+      case GRPC_OP_SEND_INITIAL_METADATA:
+        /* Flag validation: currently allow no flags */
+        if (op->flags != 0) {
+          error = GRPC_CALL_ERROR_INVALID_FLAGS;
+          goto done_with_error;
+        }
+        if (call->sent_initial_metadata) {
+          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+          goto done_with_error;
+        }
+        if (op->data.send_initial_metadata.count > INT_MAX) {
+          error = GRPC_CALL_ERROR_INVALID_METADATA;
+          goto done_with_error;
+        }
+        bctl->send_initial_metadata = 1;
+        call->sent_initial_metadata = 1;
+        if (!prepare_application_metadata(
+                call, (int)op->data.send_initial_metadata.count,
+                op->data.send_initial_metadata.metadata, 0, call->is_client)) {
+          error = GRPC_CALL_ERROR_INVALID_METADATA;
+          goto done_with_error;
+        }
+        /* TODO(ctiller): just make these the same variable? */
+        call->metadata_batch[0][0].deadline = call->send_deadline;
+        stream_op.send_initial_metadata =
+            &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */];
+        break;
+      case GRPC_OP_SEND_MESSAGE:
+        if (!are_write_flags_valid(op->flags)) {
+          error = GRPC_CALL_ERROR_INVALID_FLAGS;
+          goto done_with_error;
+        }
+        if (op->data.send_message == NULL) {
+          error = GRPC_CALL_ERROR_INVALID_MESSAGE;
+          goto done_with_error;
+        }
+        if (call->sending_message) {
+          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+          goto done_with_error;
+        }
+        bctl->send_message = 1;
+        call->sending_message = 1;
+        grpc_slice_buffer_stream_init(
+            &call->sending_stream,
+            &op->data.send_message->data.raw.slice_buffer, op->flags);
+        stream_op.send_message = &call->sending_stream.base;
+        break;
+      case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+        /* Flag validation: currently allow no flags */
+        if (op->flags != 0) {
+          error = GRPC_CALL_ERROR_INVALID_FLAGS;
+          goto done_with_error;
+        }
+        if (!call->is_client) {
+          error = GRPC_CALL_ERROR_NOT_ON_SERVER;
+          goto done_with_error;
+        }
+        if (call->sent_final_op) {
+          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+          goto done_with_error;
+        }
+        bctl->send_final_op = 1;
+        call->sent_final_op = 1;
+        stream_op.send_trailing_metadata =
+            &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
+        break;
+      case GRPC_OP_SEND_STATUS_FROM_SERVER:
+        /* Flag validation: currently allow no flags */
+        if (op->flags != 0) {
+          error = GRPC_CALL_ERROR_INVALID_FLAGS;
+          goto done_with_error;
+        }
+        if (call->is_client) {
+          error = GRPC_CALL_ERROR_NOT_ON_CLIENT;
+          goto done_with_error;
+        }
+        if (call->sent_final_op) {
+          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+          goto done_with_error;
+        }
+        if (op->data.send_status_from_server.trailing_metadata_count >
+            INT_MAX) {
+          error = GRPC_CALL_ERROR_INVALID_METADATA;
+          goto done_with_error;
+        }
+        bctl->send_final_op = 1;
+        call->sent_final_op = 1;
+        call->send_extra_metadata_count = 1;
+        call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem(
+            call->channel, op->data.send_status_from_server.status);
+        if (op->data.send_status_from_server.status_details != NULL) {
+          call->send_extra_metadata[1].md = grpc_mdelem_from_metadata_strings(
+              GRPC_MDSTR_GRPC_MESSAGE,
+              grpc_mdstr_from_string(
+                  op->data.send_status_from_server.status_details));
+          call->send_extra_metadata_count++;
+          set_status_details(
+              call, STATUS_FROM_API_OVERRIDE,
+              GRPC_MDSTR_REF(call->send_extra_metadata[1].md->value));
+        }
+        set_status_code(call, STATUS_FROM_API_OVERRIDE,
+                        (uint32_t)op->data.send_status_from_server.status);
+        if (!prepare_application_metadata(
+                call,
+                (int)op->data.send_status_from_server.trailing_metadata_count,
+                op->data.send_status_from_server.trailing_metadata, 1, 1)) {
+          error = GRPC_CALL_ERROR_INVALID_METADATA;
+          goto done_with_error;
+        }
+        stream_op.send_trailing_metadata =
+            &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
+        break;
+      case GRPC_OP_RECV_INITIAL_METADATA:
+        /* Flag validation: currently allow no flags */
+        if (op->flags != 0) {
+          error = GRPC_CALL_ERROR_INVALID_FLAGS;
+          goto done_with_error;
+        }
+        if (call->received_initial_metadata) {
+          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+          goto done_with_error;
+        }
+        call->received_initial_metadata = 1;
+        call->buffered_metadata[0] = op->data.recv_initial_metadata;
+        grpc_closure_init(&call->receiving_initial_metadata_ready,
+                          receiving_initial_metadata_ready, bctl);
+        bctl->recv_initial_metadata = 1;
+        stream_op.recv_initial_metadata =
+            &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
+        stream_op.recv_initial_metadata_ready =
+            &call->receiving_initial_metadata_ready;
+        num_completion_callbacks_needed++;
+        break;
+      case GRPC_OP_RECV_MESSAGE:
+        /* Flag validation: currently allow no flags */
+        if (op->flags != 0) {
+          error = GRPC_CALL_ERROR_INVALID_FLAGS;
+          goto done_with_error;
+        }
+        if (call->receiving_message) {
+          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+          goto done_with_error;
+        }
+        call->receiving_message = 1;
+        bctl->recv_message = 1;
+        call->receiving_buffer = op->data.recv_message;
+        stream_op.recv_message = &call->receiving_stream;
+        grpc_closure_init(&call->receiving_stream_ready, receiving_stream_ready,
+                          bctl);
+        stream_op.recv_message_ready = &call->receiving_stream_ready;
+        num_completion_callbacks_needed++;
+        break;
+      case GRPC_OP_RECV_STATUS_ON_CLIENT:
+        /* Flag validation: currently allow no flags */
+        if (op->flags != 0) {
+          error = GRPC_CALL_ERROR_INVALID_FLAGS;
+          goto done_with_error;
+        }
+        if (!call->is_client) {
+          error = GRPC_CALL_ERROR_NOT_ON_SERVER;
+          goto done_with_error;
+        }
+        if (call->received_final_op) {
+          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+          goto done_with_error;
+        }
+        call->received_final_op = 1;
+        call->buffered_metadata[1] =
+            op->data.recv_status_on_client.trailing_metadata;
+        call->final_op.client.status = op->data.recv_status_on_client.status;
+        call->final_op.client.status_details =
+            op->data.recv_status_on_client.status_details;
+        call->final_op.client.status_details_capacity =
+            op->data.recv_status_on_client.status_details_capacity;
+        bctl->recv_final_op = 1;
+        stream_op.recv_trailing_metadata =
+            &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
+        break;
+      case GRPC_OP_RECV_CLOSE_ON_SERVER:
+        /* Flag validation: currently allow no flags */
+        if (op->flags != 0) {
+          error = GRPC_CALL_ERROR_INVALID_FLAGS;
+          goto done_with_error;
+        }
+        if (call->is_client) {
+          error = GRPC_CALL_ERROR_NOT_ON_CLIENT;
+          goto done_with_error;
+        }
+        if (call->received_final_op) {
+          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+          goto done_with_error;
+        }
+        call->received_final_op = 1;
+        call->final_op.server.cancelled =
+            op->data.recv_close_on_server.cancelled;
+        bctl->recv_final_op = 1;
+        stream_op.recv_trailing_metadata =
+            &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
+        break;
+    }
+  }
+
+  GRPC_CALL_INTERNAL_REF(call, "completion");
+  if (!is_notify_tag_closure) {
+    grpc_cq_begin_op(call->cq, notify_tag);
+  }
+  gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed);
+
+  stream_op.context = call->context;
+  grpc_closure_init(&bctl->finish_batch, finish_batch, bctl);
+  stream_op.on_complete = &bctl->finish_batch;
+  gpr_mu_unlock(&call->mu);
+
+  execute_op(exec_ctx, call, &stream_op);
+
+done:
+  GPR_TIMER_END("grpc_call_start_batch", 0);
+  return error;
+
+done_with_error:
+  /* reverse any mutations that occured */
+  if (bctl->send_initial_metadata) {
+    call->sent_initial_metadata = 0;
+    grpc_metadata_batch_clear(&call->metadata_batch[0][0]);
+  }
+  if (bctl->send_message) {
+    call->sending_message = 0;
+    grpc_byte_stream_destroy(exec_ctx, &call->sending_stream.base);
+  }
+  if (bctl->send_final_op) {
+    call->sent_final_op = 0;
+    grpc_metadata_batch_clear(&call->metadata_batch[0][1]);
+  }
+  if (bctl->recv_initial_metadata) {
+    call->received_initial_metadata = 0;
+  }
+  if (bctl->recv_message) {
+    call->receiving_message = 0;
+  }
+  if (bctl->recv_final_op) {
+    call->received_final_op = 0;
+  }
+  gpr_mu_unlock(&call->mu);
+  goto done;
+}
+
+grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
+                                      size_t nops, void *tag, void *reserved) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_call_error err;
+
+  GRPC_API_TRACE(
+      "grpc_call_start_batch(call=%p, ops=%p, nops=%lu, tag=%p, reserved=%p)",
+      5, (call, ops, (unsigned long)nops, tag, reserved));
+
+  if (reserved != NULL) {
+    err = GRPC_CALL_ERROR;
+  } else {
+    err = call_start_batch(&exec_ctx, call, ops, nops, tag, 0);
+  }
+
+  grpc_exec_ctx_finish(&exec_ctx);
+  return err;
+}
+
+grpc_call_error grpc_call_start_batch_and_execute(grpc_exec_ctx *exec_ctx,
+                                                  grpc_call *call,
+                                                  const grpc_op *ops,
+                                                  size_t nops,
+                                                  grpc_closure *closure) {
+  return call_start_batch(exec_ctx, call, ops, nops, closure, 1);
+}
+
+void grpc_call_context_set(grpc_call *call, grpc_context_index elem,
+                           void *value, void (*destroy)(void *value)) {
+  if (call->context[elem].destroy) {
+    call->context[elem].destroy(call->context[elem].value);
+  }
+  call->context[elem].value = value;
+  call->context[elem].destroy = destroy;
+}
+
+void *grpc_call_context_get(grpc_call *call, grpc_context_index elem) {
+  return call->context[elem].value;
+}
+
+uint8_t grpc_call_is_client(grpc_call *call) { return call->is_client; }
+
+grpc_compression_algorithm grpc_call_compression_for_level(
+    grpc_call *call, grpc_compression_level level) {
+  gpr_mu_lock(&call->mu);
+  const uint32_t accepted_encodings = call->encodings_accepted_by_peer;
+  gpr_mu_unlock(&call->mu);
+  return grpc_compression_algorithm_for_level(level, accepted_encodings);
+}
diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h
new file mode 100644
index 0000000..e2e7586
--- /dev/null
+++ b/src/core/lib/surface/call.h
@@ -0,0 +1,116 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_CALL_H
+#define GRPC_CORE_LIB_SURFACE_CALL_H
+
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/channel/context.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/surface_trace.h"
+
+#include <grpc/grpc.h>
+#include <grpc/impl/codegen/compression_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*grpc_ioreq_completion_func)(grpc_exec_ctx *exec_ctx,
+                                           grpc_call *call, int success,
+                                           void *user_data);
+
+grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
+                            uint32_t propagation_mask,
+                            grpc_completion_queue *cq,
+                            const void *server_transport_data,
+                            grpc_mdelem **add_initial_metadata,
+                            size_t add_initial_metadata_count,
+                            gpr_timespec send_deadline);
+
+void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call,
+                                    grpc_completion_queue *cq);
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+void grpc_call_internal_ref(grpc_call *call, const char *reason);
+void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *call,
+                              const char *reason);
+#define GRPC_CALL_INTERNAL_REF(call, reason) \
+  grpc_call_internal_ref(call, reason)
+#define GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, reason) \
+  grpc_call_internal_unref(exec_ctx, call, reason)
+#else
+void grpc_call_internal_ref(grpc_call *call);
+void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *call);
+#define GRPC_CALL_INTERNAL_REF(call, reason) grpc_call_internal_ref(call)
+#define GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, reason) \
+  grpc_call_internal_unref(exec_ctx, call)
+#endif
+
+grpc_call_stack *grpc_call_get_call_stack(grpc_call *call);
+
+grpc_call_error grpc_call_start_batch_and_execute(grpc_exec_ctx *exec_ctx,
+                                                  grpc_call *call,
+                                                  const grpc_op *ops,
+                                                  size_t nops,
+                                                  grpc_closure *closure);
+
+/* Given the top call_element, get the call object. */
+grpc_call *grpc_call_from_top_element(grpc_call_element *surface_element);
+
+void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
+                         grpc_call *call, const grpc_op *ops, size_t nops,
+                         void *tag);
+
+/* 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));
+/* 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_api_trace) grpc_call_log_batch(sev, call, ops, nops, tag)
+
+uint8_t grpc_call_is_client(grpc_call *call);
+
+/* Return an appropriate compression algorithm for the requested compression \a
+ * level in the context of \a call. */
+grpc_compression_algorithm grpc_call_compression_for_level(
+    grpc_call *call, grpc_compression_level level);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_SURFACE_CALL_H */
diff --git a/src/core/lib/surface/call_details.c b/src/core/lib/surface/call_details.c
new file mode 100644
index 0000000..08f606d
--- /dev/null
+++ b/src/core/lib/surface/call_details.c
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+
+#include <string.h>
+
+#include "src/core/lib/surface/api_trace.h"
+
+void grpc_call_details_init(grpc_call_details* cd) {
+  GRPC_API_TRACE("grpc_call_details_init(cd=%p)", 1, (cd));
+  memset(cd, 0, sizeof(*cd));
+}
+
+void grpc_call_details_destroy(grpc_call_details* cd) {
+  GRPC_API_TRACE("grpc_call_details_destroy(cd=%p)", 1, (cd));
+  gpr_free(cd->method);
+  gpr_free(cd->host);
+}
diff --git a/src/core/lib/surface/call_log_batch.c b/src/core/lib/surface/call_log_batch.c
new file mode 100644
index 0000000..bc5a2ff
--- /dev/null
+++ b/src/core/lib/surface/call_log_batch.c
@@ -0,0 +1,118 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/call.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+#include "src/core/lib/support/string.h"
+
+static void add_metadata(gpr_strvec *b, const grpc_metadata *md, size_t count) {
+  size_t i;
+  for (i = 0; i < count; i++) {
+    gpr_strvec_add(b, gpr_strdup("\nkey="));
+    gpr_strvec_add(b, gpr_strdup(md[i].key));
+
+    gpr_strvec_add(b, gpr_strdup(" value="));
+    gpr_strvec_add(b, gpr_dump(md[i].value, md[i].value_length,
+                               GPR_DUMP_HEX | GPR_DUMP_ASCII));
+  }
+}
+
+char *grpc_op_string(const grpc_op *op) {
+  char *tmp;
+  char *out;
+
+  gpr_strvec b;
+  gpr_strvec_init(&b);
+
+  switch (op->op) {
+    case GRPC_OP_SEND_INITIAL_METADATA:
+      gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA"));
+      add_metadata(&b, op->data.send_initial_metadata.metadata,
+                   op->data.send_initial_metadata.count);
+      break;
+    case GRPC_OP_SEND_MESSAGE:
+      gpr_asprintf(&tmp, "SEND_MESSAGE ptr=%p", op->data.send_message);
+      gpr_strvec_add(&b, tmp);
+      break;
+    case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+      gpr_strvec_add(&b, gpr_strdup("SEND_CLOSE_FROM_CLIENT"));
+      break;
+    case GRPC_OP_SEND_STATUS_FROM_SERVER:
+      gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=%s",
+                   op->data.send_status_from_server.status,
+                   op->data.send_status_from_server.status_details);
+      gpr_strvec_add(&b, tmp);
+      add_metadata(&b, op->data.send_status_from_server.trailing_metadata,
+                   op->data.send_status_from_server.trailing_metadata_count);
+      break;
+    case GRPC_OP_RECV_INITIAL_METADATA:
+      gpr_asprintf(&tmp, "RECV_INITIAL_METADATA ptr=%p",
+                   op->data.recv_initial_metadata);
+      gpr_strvec_add(&b, tmp);
+      break;
+    case GRPC_OP_RECV_MESSAGE:
+      gpr_asprintf(&tmp, "RECV_MESSAGE ptr=%p", op->data.recv_message);
+      gpr_strvec_add(&b, tmp);
+      break;
+    case GRPC_OP_RECV_STATUS_ON_CLIENT:
+      gpr_asprintf(&tmp,
+                   "RECV_STATUS_ON_CLIENT metadata=%p status=%p details=%p",
+                   op->data.recv_status_on_client.trailing_metadata,
+                   op->data.recv_status_on_client.status,
+                   op->data.recv_status_on_client.status_details);
+      gpr_strvec_add(&b, tmp);
+      break;
+    case GRPC_OP_RECV_CLOSE_ON_SERVER:
+      gpr_asprintf(&tmp, "RECV_CLOSE_ON_SERVER cancelled=%p",
+                   op->data.recv_close_on_server.cancelled);
+      gpr_strvec_add(&b, tmp);
+  }
+  out = gpr_strvec_flatten(&b, NULL);
+  gpr_strvec_destroy(&b);
+
+  return out;
+}
+
+void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
+                         grpc_call *call, const grpc_op *ops, size_t nops,
+                         void *tag) {
+  char *tmp;
+  size_t i;
+  for (i = 0; i < nops; i++) {
+    tmp = grpc_op_string(&ops[i]);
+    gpr_log(file, line, severity, "ops[%d]: %s", i, tmp);
+    gpr_free(tmp);
+  }
+}
diff --git a/src/core/lib/surface/call_test_only.h b/src/core/lib/surface/call_test_only.h
new file mode 100644
index 0000000..4002141
--- /dev/null
+++ b/src/core/lib/surface/call_test_only.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_CALL_TEST_ONLY_H
+#define GRPC_CORE_LIB_SURFACE_CALL_TEST_ONLY_H
+
+#include <grpc/grpc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Return the compression algorithm from \a call.
+ *
+ * \warning This function should \b only be used in test code. */
+grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm(
+    grpc_call *call);
+
+/** Return the message flags from \a call.
+ *
+ * \warning This function should \b only be used in test code. */
+uint32_t grpc_call_test_only_get_message_flags(grpc_call *call);
+
+/** Returns a bitset for the encodings (compression algorithms) supported by \a
+ * call's peer.
+ *
+ * To be indexed by grpc_compression_algorithm enum values. */
+uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_SURFACE_CALL_TEST_ONLY_H */
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
new file mode 100644
index 0000000..d815daa
--- /dev/null
+++ b/src/core/lib/surface/channel.c
@@ -0,0 +1,324 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/channel.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/client_config/resolver_registry.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/channel_init.h"
+#include "src/core/lib/surface/init.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+/** Cache grpc-status: X mdelems for X = 0..NUM_CACHED_STATUS_ELEMS.
+ *  Avoids needing to take a metadata context lock for sending status
+ *  if the status code is <= NUM_CACHED_STATUS_ELEMS.
+ *  Sized to allow the most commonly used codes to fit in
+ *  (OK, Cancelled, Unknown). */
+#define NUM_CACHED_STATUS_ELEMS 3
+
+typedef struct registered_call {
+  grpc_mdelem *path;
+  grpc_mdelem *authority;
+  struct registered_call *next;
+} registered_call;
+
+struct grpc_channel {
+  int is_client;
+  uint32_t max_message_length;
+  grpc_mdelem *default_authority;
+
+  gpr_mu registered_call_mu;
+  registered_call *registered_calls;
+  char *target;
+};
+
+#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1))
+#define CHANNEL_FROM_CHANNEL_STACK(channel_stack) \
+  (((grpc_channel *)(channel_stack)) - 1)
+#define CHANNEL_FROM_TOP_ELEM(top_elem) \
+  CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem))
+
+/* the protobuf library will (by default) start warning at 100megs */
+#define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024)
+
+static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, bool success);
+
+grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
+                                  const grpc_channel_args *args,
+                                  grpc_channel_stack_type channel_stack_type,
+                                  grpc_transport *optional_transport) {
+  bool is_client = grpc_channel_stack_type_is_client(channel_stack_type);
+
+  grpc_channel *channel = grpc_channel_init_create_stack(
+      exec_ctx, channel_stack_type, sizeof(grpc_channel), args, 1,
+      destroy_channel, NULL, optional_transport);
+
+  memset(channel, 0, sizeof(*channel));
+  channel->target = gpr_strdup(target);
+  channel->is_client = is_client;
+  gpr_mu_init(&channel->registered_call_mu);
+  channel->registered_calls = NULL;
+
+  channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH;
+  if (args) {
+    for (size_t i = 0; i < args->num_args; i++) {
+      if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) {
+        if (args->args[i].type != GRPC_ARG_INTEGER) {
+          gpr_log(GPR_ERROR, "%s ignored: it must be an integer",
+                  GRPC_ARG_MAX_MESSAGE_LENGTH);
+        } else if (args->args[i].value.integer < 0) {
+          gpr_log(GPR_ERROR, "%s ignored: it must be >= 0",
+                  GRPC_ARG_MAX_MESSAGE_LENGTH);
+        } else {
+          channel->max_message_length = (uint32_t)args->args[i].value.integer;
+        }
+      } else if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) {
+        if (args->args[i].type != GRPC_ARG_STRING) {
+          gpr_log(GPR_ERROR, "%s ignored: it must be a string",
+                  GRPC_ARG_DEFAULT_AUTHORITY);
+        } else {
+          if (channel->default_authority) {
+            /* setting this takes precedence over anything else */
+            GRPC_MDELEM_UNREF(channel->default_authority);
+          }
+          channel->default_authority = grpc_mdelem_from_strings(
+              ":authority", args->args[i].value.string);
+        }
+      } else if (0 ==
+                 strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) {
+        if (args->args[i].type != GRPC_ARG_STRING) {
+          gpr_log(GPR_ERROR, "%s ignored: it must be a string",
+                  GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
+        } else {
+          if (channel->default_authority) {
+            /* other ways of setting this (notably ssl) take precedence */
+            gpr_log(GPR_ERROR,
+                    "%s ignored: default host already set some other way",
+                    GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
+          } else {
+            channel->default_authority = grpc_mdelem_from_strings(
+                ":authority", args->args[i].value.string);
+          }
+        }
+      }
+    }
+  }
+
+  if (channel->is_client && channel->default_authority == NULL &&
+      target != NULL) {
+    char *default_authority = grpc_get_default_authority(target);
+    if (default_authority) {
+      channel->default_authority =
+          grpc_mdelem_from_strings(":authority", default_authority);
+    }
+    gpr_free(default_authority);
+  }
+
+  return channel;
+}
+
+char *grpc_channel_get_target(grpc_channel *channel) {
+  GRPC_API_TRACE("grpc_channel_get_target(channel=%p)", 1, (channel));
+  return gpr_strdup(channel->target);
+}
+
+static grpc_call *grpc_channel_create_call_internal(
+    grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
+    grpc_completion_queue *cq, grpc_mdelem *path_mdelem,
+    grpc_mdelem *authority_mdelem, gpr_timespec deadline) {
+  grpc_mdelem *send_metadata[2];
+  size_t num_metadata = 0;
+
+  GPR_ASSERT(channel->is_client);
+
+  send_metadata[num_metadata++] = path_mdelem;
+  if (authority_mdelem != NULL) {
+    send_metadata[num_metadata++] = authority_mdelem;
+  } else if (channel->default_authority != NULL) {
+    send_metadata[num_metadata++] = GRPC_MDELEM_REF(channel->default_authority);
+  }
+
+  return grpc_call_create(channel, parent_call, propagation_mask, cq, NULL,
+                          send_metadata, num_metadata, deadline);
+}
+
+grpc_call *grpc_channel_create_call(grpc_channel *channel,
+                                    grpc_call *parent_call,
+                                    uint32_t propagation_mask,
+                                    grpc_completion_queue *cq,
+                                    const char *method, const char *host,
+                                    gpr_timespec deadline, void *reserved) {
+  GRPC_API_TRACE(
+      "grpc_channel_create_call("
+      "channel=%p, parent_call=%p, propagation_mask=%x, cq=%p, method=%s, "
+      "host=%s, "
+      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
+      "reserved=%p)",
+      10, (channel, parent_call, (unsigned)propagation_mask, cq, method, host,
+           (long long)deadline.tv_sec, (int)deadline.tv_nsec,
+           (int)deadline.clock_type, reserved));
+  GPR_ASSERT(!reserved);
+  return grpc_channel_create_call_internal(
+      channel, parent_call, propagation_mask, cq,
+      grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
+                                        grpc_mdstr_from_string(method)),
+      host ? grpc_mdelem_from_metadata_strings(GRPC_MDSTR_AUTHORITY,
+                                               grpc_mdstr_from_string(host))
+           : NULL,
+      deadline);
+}
+
+void *grpc_channel_register_call(grpc_channel *channel, const char *method,
+                                 const char *host, void *reserved) {
+  registered_call *rc = gpr_malloc(sizeof(registered_call));
+  GRPC_API_TRACE(
+      "grpc_channel_register_call(channel=%p, method=%s, host=%s, reserved=%p)",
+      4, (channel, method, host, reserved));
+  GPR_ASSERT(!reserved);
+  rc->path = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
+                                               grpc_mdstr_from_string(method));
+  rc->authority = host ? grpc_mdelem_from_metadata_strings(
+                             GRPC_MDSTR_AUTHORITY, grpc_mdstr_from_string(host))
+                       : NULL;
+  gpr_mu_lock(&channel->registered_call_mu);
+  rc->next = channel->registered_calls;
+  channel->registered_calls = rc;
+  gpr_mu_unlock(&channel->registered_call_mu);
+  return rc;
+}
+
+grpc_call *grpc_channel_create_registered_call(
+    grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
+    grpc_completion_queue *completion_queue, void *registered_call_handle,
+    gpr_timespec deadline, void *reserved) {
+  registered_call *rc = registered_call_handle;
+  GRPC_API_TRACE(
+      "grpc_channel_create_registered_call("
+      "channel=%p, parent_call=%p, propagation_mask=%x, completion_queue=%p, "
+      "registered_call_handle=%p, "
+      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
+      "reserved=%p)",
+      9, (channel, parent_call, (unsigned)propagation_mask, completion_queue,
+          registered_call_handle, (long long)deadline.tv_sec,
+          (int)deadline.tv_nsec, (int)deadline.clock_type, reserved));
+  GPR_ASSERT(!reserved);
+  return grpc_channel_create_call_internal(
+      channel, parent_call, propagation_mask, completion_queue,
+      GRPC_MDELEM_REF(rc->path),
+      rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline);
+}
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+#define REF_REASON reason
+#define REF_ARG , const char *reason
+#else
+#define REF_REASON ""
+#define REF_ARG
+#endif
+void grpc_channel_internal_ref(grpc_channel *c REF_ARG) {
+  GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
+}
+
+void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel *c REF_ARG) {
+  GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
+}
+
+static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg,
+                            bool iomgr_success) {
+  grpc_channel *channel = arg;
+  grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(channel));
+  while (channel->registered_calls) {
+    registered_call *rc = channel->registered_calls;
+    channel->registered_calls = rc->next;
+    GRPC_MDELEM_UNREF(rc->path);
+    if (rc->authority) {
+      GRPC_MDELEM_UNREF(rc->authority);
+    }
+    gpr_free(rc);
+  }
+  if (channel->default_authority != NULL) {
+    GRPC_MDELEM_UNREF(channel->default_authority);
+  }
+  gpr_mu_destroy(&channel->registered_call_mu);
+  gpr_free(channel->target);
+  gpr_free(channel);
+}
+
+void grpc_channel_destroy(grpc_channel *channel) {
+  grpc_transport_op op;
+  grpc_channel_element *elem;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  GRPC_API_TRACE("grpc_channel_destroy(channel=%p)", 1, (channel));
+  memset(&op, 0, sizeof(op));
+  op.disconnect = 1;
+  elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
+  elem->filter->start_transport_op(&exec_ctx, elem, &op);
+
+  GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, channel, "channel");
+
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
+  return CHANNEL_STACK_FROM_CHANNEL(channel);
+}
+
+grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
+  char tmp[GPR_LTOA_MIN_BUFSIZE];
+  switch (i) {
+    case 0:
+      return GRPC_MDELEM_GRPC_STATUS_0;
+    case 1:
+      return GRPC_MDELEM_GRPC_STATUS_1;
+    case 2:
+      return GRPC_MDELEM_GRPC_STATUS_2;
+  }
+  gpr_ltoa(i, tmp);
+  return grpc_mdelem_from_metadata_strings(GRPC_MDSTR_GRPC_STATUS,
+                                           grpc_mdstr_from_string(tmp));
+}
+
+uint32_t grpc_channel_get_max_message_length(grpc_channel *channel) {
+  return channel->max_message_length;
+}
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
new file mode 100644
index 0000000..09de0fc
--- /dev/null
+++ b/src/core/lib/surface/channel.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_CHANNEL_H
+#define GRPC_CORE_LIB_SURFACE_CHANNEL_H
+
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/client_config/subchannel_factory.h"
+#include "src/core/lib/surface/channel_stack_type.h"
+
+grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
+                                  const grpc_channel_args *args,
+                                  grpc_channel_stack_type channel_stack_type,
+                                  grpc_transport *optional_transport);
+
+/** Get a (borrowed) pointer to this channels underlying channel stack */
+grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
+
+/** Get a grpc_mdelem of grpc-status: X where X is the numeric value of
+    status_code.
+
+    The returned elem is owned by the caller. */
+grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel,
+                                                 int status_code);
+uint32_t grpc_channel_get_max_message_length(grpc_channel *channel);
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+void grpc_channel_internal_ref(grpc_channel *channel, const char *reason);
+void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
+                                 const char *reason);
+#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
+  grpc_channel_internal_ref(channel, reason)
+#define GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, reason) \
+  grpc_channel_internal_unref(exec_ctx, channel, reason)
+#else
+void grpc_channel_internal_ref(grpc_channel *channel);
+void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel *channel);
+#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
+  grpc_channel_internal_ref(channel)
+#define GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, reason) \
+  grpc_channel_internal_unref(exec_ctx, channel)
+#endif
+
+#endif /* GRPC_CORE_LIB_SURFACE_CHANNEL_H */
diff --git a/src/core/lib/surface/channel_connectivity.c b/src/core/lib/surface/channel_connectivity.c
new file mode 100644
index 0000000..2f5d763
--- /dev/null
+++ b/src/core/lib/surface/channel_connectivity.c
@@ -0,0 +1,207 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/channel.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/completion_queue.h"
+
+grpc_connectivity_state grpc_channel_check_connectivity_state(
+    grpc_channel *channel, int try_to_connect) {
+  /* forward through to the underlying client channel */
+  grpc_channel_element *client_channel_elem =
+      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_connectivity_state state;
+  GRPC_API_TRACE(
+      "grpc_channel_check_connectivity_state(channel=%p, try_to_connect=%d)", 2,
+      (channel, try_to_connect));
+  if (client_channel_elem->filter == &grpc_client_channel_filter) {
+    state = grpc_client_channel_check_connectivity_state(
+        &exec_ctx, client_channel_elem, try_to_connect);
+    grpc_exec_ctx_finish(&exec_ctx);
+    return state;
+  }
+  gpr_log(GPR_ERROR,
+          "grpc_channel_check_connectivity_state called on something that is "
+          "not a (u)client channel, but '%s'",
+          client_channel_elem->filter->name);
+  grpc_exec_ctx_finish(&exec_ctx);
+  return GRPC_CHANNEL_FATAL_FAILURE;
+}
+
+typedef enum {
+  WAITING,
+  CALLING_BACK,
+  CALLING_BACK_AND_FINISHED,
+  CALLED_BACK
+} callback_phase;
+
+typedef struct {
+  gpr_mu mu;
+  callback_phase phase;
+  int success;
+  grpc_closure on_complete;
+  grpc_timer alarm;
+  grpc_connectivity_state state;
+  grpc_completion_queue *cq;
+  grpc_cq_completion completion_storage;
+  grpc_channel *channel;
+  void *tag;
+} state_watcher;
+
+static void delete_state_watcher(grpc_exec_ctx *exec_ctx, state_watcher *w) {
+  grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(
+      grpc_channel_get_channel_stack(w->channel));
+  if (client_channel_elem->filter == &grpc_client_channel_filter) {
+    GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->channel,
+                                "watch_channel_connectivity");
+  } else {
+    abort();
+  }
+  gpr_mu_destroy(&w->mu);
+  gpr_free(w);
+}
+
+static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw,
+                                grpc_cq_completion *ignored) {
+  int delete = 0;
+  state_watcher *w = pw;
+  gpr_mu_lock(&w->mu);
+  switch (w->phase) {
+    case WAITING:
+    case CALLED_BACK:
+      GPR_UNREACHABLE_CODE(return );
+    case CALLING_BACK:
+      w->phase = CALLED_BACK;
+      break;
+    case CALLING_BACK_AND_FINISHED:
+      delete = 1;
+      break;
+  }
+  gpr_mu_unlock(&w->mu);
+
+  if (delete) {
+    delete_state_watcher(exec_ctx, w);
+  }
+}
+
+static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
+                        int due_to_completion) {
+  int delete = 0;
+
+  if (due_to_completion) {
+    grpc_timer_cancel(exec_ctx, &w->alarm);
+  }
+
+  gpr_mu_lock(&w->mu);
+  if (due_to_completion) {
+    w->success = 1;
+  }
+  switch (w->phase) {
+    case WAITING:
+      w->phase = CALLING_BACK;
+      grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->success, finished_completion,
+                     w, &w->completion_storage);
+      break;
+    case CALLING_BACK:
+      w->phase = CALLING_BACK_AND_FINISHED;
+      break;
+    case CALLING_BACK_AND_FINISHED:
+      GPR_UNREACHABLE_CODE(return );
+    case CALLED_BACK:
+      delete = 1;
+      break;
+  }
+  gpr_mu_unlock(&w->mu);
+
+  if (delete) {
+    delete_state_watcher(exec_ctx, w);
+  }
+}
+
+static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) {
+  partly_done(exec_ctx, pw, 1);
+}
+
+static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) {
+  partly_done(exec_ctx, pw, 0);
+}
+
+void grpc_channel_watch_connectivity_state(
+    grpc_channel *channel, grpc_connectivity_state last_observed_state,
+    gpr_timespec deadline, grpc_completion_queue *cq, void *tag) {
+  grpc_channel_element *client_channel_elem =
+      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  state_watcher *w = gpr_malloc(sizeof(*w));
+
+  GRPC_API_TRACE(
+      "grpc_channel_watch_connectivity_state("
+      "channel=%p, last_observed_state=%d, "
+      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
+      "cq=%p, tag=%p)",
+      7, (channel, (int)last_observed_state, (long long)deadline.tv_sec,
+          (int)deadline.tv_nsec, (int)deadline.clock_type, cq, tag));
+
+  grpc_cq_begin_op(cq, tag);
+
+  gpr_mu_init(&w->mu);
+  grpc_closure_init(&w->on_complete, watch_complete, w);
+  w->phase = WAITING;
+  w->state = last_observed_state;
+  w->success = 0;
+  w->cq = cq;
+  w->tag = tag;
+  w->channel = channel;
+
+  grpc_timer_init(&exec_ctx, &w->alarm,
+                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
+                  timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC));
+
+  if (client_channel_elem->filter == &grpc_client_channel_filter) {
+    GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
+    grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem,
+                                                 grpc_cq_pollset(cq), &w->state,
+                                                 &w->on_complete);
+  } else {
+    abort();
+  }
+
+  grpc_exec_ctx_finish(&exec_ctx);
+}
diff --git a/src/core/lib/surface/channel_init.c b/src/core/lib/surface/channel_init.c
new file mode 100644
index 0000000..fc69f61
--- /dev/null
+++ b/src/core/lib/surface/channel_init.c
@@ -0,0 +1,146 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/channel_init.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/useful.h>
+
+typedef struct stage_slot {
+  grpc_channel_init_stage fn;
+  void *arg;
+  int priority;
+  size_t insertion_order;
+} stage_slot;
+
+typedef struct stage_slots {
+  stage_slot *slots;
+  size_t num_slots;
+  size_t cap_slots;
+} stage_slots;
+
+static stage_slots g_slots[GRPC_NUM_CHANNEL_STACK_TYPES];
+static bool g_finalized;
+
+void grpc_channel_init_init(void) {
+  for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) {
+    g_slots[i].slots = NULL;
+    g_slots[i].num_slots = 0;
+    g_slots[i].cap_slots = 0;
+  }
+  g_finalized = false;
+}
+
+void grpc_channel_init_register_stage(grpc_channel_stack_type type,
+                                      int priority,
+                                      grpc_channel_init_stage stage,
+                                      void *stage_arg) {
+  GPR_ASSERT(!g_finalized);
+  if (g_slots[type].cap_slots == g_slots[type].num_slots) {
+    g_slots[type].cap_slots = GPR_MAX(8, 3 * g_slots[type].cap_slots / 2);
+    g_slots[type].slots =
+        gpr_realloc(g_slots[type].slots,
+                    g_slots[type].cap_slots * sizeof(*g_slots[type].slots));
+  }
+  stage_slot *s = &g_slots[type].slots[g_slots[type].num_slots++];
+  s->insertion_order = g_slots[type].num_slots;
+  s->priority = priority;
+  s->fn = stage;
+  s->arg = stage_arg;
+}
+
+static int compare_slots(const void *a, const void *b) {
+  const stage_slot *sa = a;
+  const stage_slot *sb = b;
+
+  int c = GPR_ICMP(sa->priority, sb->priority);
+  if (c != 0) return c;
+  return GPR_ICMP(sa->insertion_order, sb->insertion_order);
+}
+
+void grpc_channel_init_finalize(void) {
+  GPR_ASSERT(!g_finalized);
+  for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) {
+    qsort(g_slots[i].slots, g_slots[i].num_slots, sizeof(*g_slots[i].slots),
+          compare_slots);
+  }
+  g_finalized = true;
+}
+
+void grpc_channel_init_shutdown(void) {
+  for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) {
+    gpr_free(g_slots[i].slots);
+    g_slots[i].slots = (void *)(uintptr_t)0xdeadbeef;
+  }
+}
+
+static const char *name_for_type(grpc_channel_stack_type type) {
+  switch (type) {
+    case GRPC_CLIENT_CHANNEL:
+      return "CLIENT_CHANNEL";
+    case GRPC_CLIENT_SUBCHANNEL:
+      return "CLIENT_SUBCHANNEL";
+    case GRPC_SERVER_CHANNEL:
+      return "SERVER_CHANNEL";
+    case GRPC_CLIENT_LAME_CHANNEL:
+      return "CLIENT_LAME_CHANNEL";
+    case GRPC_CLIENT_DIRECT_CHANNEL:
+      return "CLIENT_DIRECT_CHANNEL";
+    case GRPC_NUM_CHANNEL_STACK_TYPES:
+      break;
+  }
+  GPR_UNREACHABLE_CODE(return "UNKNOWN");
+}
+
+void *grpc_channel_init_create_stack(
+    grpc_exec_ctx *exec_ctx, grpc_channel_stack_type type, size_t prefix_bytes,
+    const grpc_channel_args *args, int initial_refs, grpc_iomgr_cb_func destroy,
+    void *destroy_arg, grpc_transport *transport) {
+  GPR_ASSERT(g_finalized);
+
+  grpc_channel_stack_builder *builder = grpc_channel_stack_builder_create();
+  grpc_channel_stack_builder_set_name(builder, name_for_type(type));
+  grpc_channel_stack_builder_set_channel_arguments(builder, args);
+  grpc_channel_stack_builder_set_transport(builder, transport);
+
+  for (size_t i = 0; i < g_slots[type].num_slots; i++) {
+    const stage_slot *slot = &g_slots[type].slots[i];
+    if (!slot->fn(builder, slot->arg)) {
+      grpc_channel_stack_builder_destroy(builder);
+      return NULL;
+    }
+  }
+
+  return grpc_channel_stack_builder_finish(exec_ctx, builder, prefix_bytes,
+                                           initial_refs, destroy, destroy_arg);
+}
diff --git a/src/core/lib/surface/channel_init.h b/src/core/lib/surface/channel_init.h
new file mode 100644
index 0000000..a4d8271
--- /dev/null
+++ b/src/core/lib/surface/channel_init.h
@@ -0,0 +1,86 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_CHANNEL_INIT_H
+#define GRPC_CORE_LIB_SURFACE_CHANNEL_INIT_H
+
+#include "src/core/lib/channel/channel_stack_builder.h"
+#include "src/core/lib/surface/channel_stack_type.h"
+#include "src/core/lib/transport/transport.h"
+
+/// This module provides a way for plugins (and the grpc core library itself)
+/// to register mutators for channel stacks.
+/// It also provides a universal entry path to run those mutators to build
+/// a channel stack for various subsystems.
+
+/// One stage of mutation: call functions against \a builder to influence the
+/// finally constructed channel stack
+typedef bool (*grpc_channel_init_stage)(grpc_channel_stack_builder *builder,
+                                        void *arg);
+
+/// Global initialization of the system
+void grpc_channel_init_init(void);
+
+/// Register one stage of mutators.
+/// Stages are run in priority order (lowest to highest), and then in
+/// registration order (in the case of a tie).
+/// Stages are registered against one of the pre-determined channel stack
+/// types.
+void grpc_channel_init_register_stage(grpc_channel_stack_type type,
+                                      int priority,
+                                      grpc_channel_init_stage stage_fn,
+                                      void *stage_arg);
+
+/// Finalize registration. No more calls to grpc_channel_init_register_stage are
+/// allowed.
+void grpc_channel_init_finalize(void);
+/// Shutdown the channel init system
+void grpc_channel_init_shutdown(void);
+
+/// Construct a channel stack of some sort: see channel_stack.h for details
+/// \a type is the type of channel stack to create
+/// \a prefix_bytes is the number of bytes before the channel stack to allocate
+/// \a args are configuration arguments for the channel stack
+/// \a initial_refs is the initial refcount to give the channel stack
+/// \a destroy and \a destroy_arg specify how to destroy the channel stack
+///    if destroy_arg is NULL, the returned value from this function will be
+///    substituted
+/// \a optional_transport is either NULL or a constructed transport object
+/// Returns a pointer to the base of the memory allocated (the actual channel
+/// stack object will be prefix_bytes past that pointer)
+void *grpc_channel_init_create_stack(
+    grpc_exec_ctx *exec_ctx, grpc_channel_stack_type type, size_t prefix_bytes,
+    const grpc_channel_args *args, int initial_refs, grpc_iomgr_cb_func destroy,
+    void *destroy_arg, grpc_transport *optional_transport);
+
+#endif /* GRPC_CORE_LIB_SURFACE_CHANNEL_INIT_H */
diff --git a/src/core/lib/surface/channel_ping.c b/src/core/lib/surface/channel_ping.c
new file mode 100644
index 0000000..dd862cd
--- /dev/null
+++ b/src/core/lib/surface/channel_ping.c
@@ -0,0 +1,79 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/channel.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/completion_queue.h"
+
+typedef struct {
+  grpc_closure closure;
+  void *tag;
+  grpc_completion_queue *cq;
+  grpc_cq_completion completion_storage;
+} ping_result;
+
+static void ping_destroy(grpc_exec_ctx *exec_ctx, void *arg,
+                         grpc_cq_completion *storage) {
+  gpr_free(arg);
+}
+
+static void ping_done(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  ping_result *pr = arg;
+  grpc_cq_end_op(exec_ctx, pr->cq, pr->tag, success, ping_destroy, pr,
+                 &pr->completion_storage);
+}
+
+void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq,
+                       void *tag, void *reserved) {
+  grpc_transport_op op;
+  ping_result *pr = gpr_malloc(sizeof(*pr));
+  grpc_channel_element *top_elem =
+      grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  GPR_ASSERT(reserved == NULL);
+  memset(&op, 0, sizeof(op));
+  pr->tag = tag;
+  pr->cq = cq;
+  grpc_closure_init(&pr->closure, ping_done, pr);
+  op.send_ping = &pr->closure;
+  op.bind_pollset = grpc_cq_pollset(cq);
+  grpc_cq_begin_op(cq, tag);
+  top_elem->filter->start_transport_op(&exec_ctx, top_elem, &op);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
diff --git a/src/core/lib/surface/channel_stack_type.c b/src/core/lib/surface/channel_stack_type.c
new file mode 100644
index 0000000..c35d603
--- /dev/null
+++ b/src/core/lib/surface/channel_stack_type.c
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/channel_stack_type.h"
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+
+bool grpc_channel_stack_type_is_client(grpc_channel_stack_type type) {
+  switch (type) {
+    case GRPC_CLIENT_CHANNEL:
+      return true;
+    case GRPC_CLIENT_SUBCHANNEL:
+      return true;
+    case GRPC_CLIENT_LAME_CHANNEL:
+      return true;
+    case GRPC_CLIENT_DIRECT_CHANNEL:
+      return true;
+    case GRPC_SERVER_CHANNEL:
+      return false;
+    case GRPC_NUM_CHANNEL_STACK_TYPES:
+      break;
+  }
+  GPR_UNREACHABLE_CODE(return true;);
+}
diff --git a/src/core/lib/surface/channel_stack_type.h b/src/core/lib/surface/channel_stack_type.h
new file mode 100644
index 0000000..16608fa
--- /dev/null
+++ b/src/core/lib/surface/channel_stack_type.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_CHANNEL_STACK_TYPE_H
+#define GRPC_CORE_LIB_SURFACE_CHANNEL_STACK_TYPE_H
+
+#include <stdbool.h>
+
+typedef enum {
+  // normal top-half client channel with load-balancing, connection management
+  GRPC_CLIENT_CHANNEL,
+  // bottom-half of a client channel: everything that happens post-load
+  // balancing (bound to a specific transport)
+  GRPC_CLIENT_SUBCHANNEL,
+  // a permanently broken client channel
+  GRPC_CLIENT_LAME_CHANNEL,
+  // a directly connected client channel (without load-balancing, directly talks
+  // to a transport)
+  GRPC_CLIENT_DIRECT_CHANNEL,
+  // server side channel
+  GRPC_SERVER_CHANNEL,
+  // must be last
+  GRPC_NUM_CHANNEL_STACK_TYPES
+} grpc_channel_stack_type;
+
+bool grpc_channel_stack_type_is_client(grpc_channel_stack_type type);
+
+#endif /* GRPC_CORE_LIB_SURFACE_CHANNEL_STACK_TYPE_H */
diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c
new file mode 100644
index 0000000..a0d7002
--- /dev/null
+++ b/src/core/lib/surface/completion_queue.c
@@ -0,0 +1,512 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/completion_queue.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/event_string.h"
+#include "src/core/lib/surface/surface_trace.h"
+
+typedef struct {
+  grpc_pollset_worker **worker;
+  void *tag;
+} plucker;
+
+/* Completion queue structure */
+struct grpc_completion_queue {
+  /** owned by pollset */
+  gpr_mu *mu;
+  /** 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;
+  /** 0 initially, 1 once we've begun shutting down */
+  int shutdown;
+  int shutdown_called;
+  int is_server_cq;
+  int num_pluckers;
+  plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
+  grpc_closure pollset_shutdown_done;
+
+#ifndef NDEBUG
+  void **outstanding_tags;
+  size_t outstanding_tag_count;
+  size_t outstanding_tag_capacity;
+#endif
+
+  grpc_completion_queue *next_free;
+};
+
+#define POLLSET_FROM_CQ(cq) ((grpc_pollset *)(cq + 1))
+
+static gpr_mu g_freelist_mu;
+static grpc_completion_queue *g_freelist;
+
+static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *cc,
+                                     bool success);
+
+void grpc_cq_global_init(void) { gpr_mu_init(&g_freelist_mu); }
+
+void grpc_cq_global_shutdown(void) {
+  gpr_mu_destroy(&g_freelist_mu);
+  while (g_freelist) {
+    grpc_completion_queue *next = g_freelist->next_free;
+    grpc_pollset_destroy(POLLSET_FROM_CQ(g_freelist));
+#ifndef NDEBUG
+    gpr_free(g_freelist->outstanding_tags);
+#endif
+    gpr_free(g_freelist);
+    g_freelist = next;
+  }
+}
+
+struct grpc_cq_alarm {
+  grpc_timer alarm;
+  grpc_cq_completion completion;
+  /** completion queue where events about this alarm will be posted */
+  grpc_completion_queue *cq;
+  /** user supplied tag */
+  void *tag;
+};
+
+grpc_completion_queue *grpc_completion_queue_create(void *reserved) {
+  grpc_completion_queue *cc;
+  GPR_ASSERT(!reserved);
+
+  GPR_TIMER_BEGIN("grpc_completion_queue_create", 0);
+
+  GRPC_API_TRACE("grpc_completion_queue_create(reserved=%p)", 1, (reserved));
+
+  gpr_mu_lock(&g_freelist_mu);
+  if (g_freelist == NULL) {
+    gpr_mu_unlock(&g_freelist_mu);
+
+    cc = gpr_malloc(sizeof(grpc_completion_queue) + grpc_pollset_size());
+    grpc_pollset_init(POLLSET_FROM_CQ(cc), &cc->mu);
+#ifndef NDEBUG
+    cc->outstanding_tags = NULL;
+    cc->outstanding_tag_capacity = 0;
+#endif
+  } else {
+    cc = g_freelist;
+    g_freelist = g_freelist->next_free;
+    gpr_mu_unlock(&g_freelist_mu);
+    /* pollset already initialized */
+  }
+
+  /* Initial ref is dropped by grpc_completion_queue_shutdown */
+  gpr_ref_init(&cc->pending_events, 1);
+  /* One for destroy(), one for pollset_shutdown */
+  gpr_ref_init(&cc->owning_refs, 2);
+  cc->completed_tail = &cc->completed_head;
+  cc->completed_head.next = (uintptr_t)cc->completed_tail;
+  cc->shutdown = 0;
+  cc->shutdown_called = 0;
+  cc->is_server_cq = 0;
+  cc->num_pluckers = 0;
+#ifndef NDEBUG
+  cc->outstanding_tag_count = 0;
+#endif
+  grpc_closure_init(&cc->pollset_shutdown_done, on_pollset_shutdown_done, cc);
+
+  GPR_TIMER_END("grpc_completion_queue_create", 0);
+
+  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_shutdown_done(grpc_exec_ctx *exec_ctx, void *arg,
+                                     bool success) {
+  grpc_completion_queue *cc = arg;
+  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->completed_head.next == (uintptr_t)&cc->completed_head);
+    grpc_pollset_reset(POLLSET_FROM_CQ(cc));
+    gpr_mu_lock(&g_freelist_mu);
+    cc->next_free = g_freelist;
+    g_freelist = cc;
+    gpr_mu_unlock(&g_freelist_mu);
+  }
+}
+
+void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag) {
+#ifndef NDEBUG
+  gpr_mu_lock(cc->mu);
+  GPR_ASSERT(!cc->shutdown_called);
+  if (cc->outstanding_tag_count == cc->outstanding_tag_capacity) {
+    cc->outstanding_tag_capacity = GPR_MAX(4, 2 * cc->outstanding_tag_capacity);
+    cc->outstanding_tags =
+        gpr_realloc(cc->outstanding_tags, sizeof(*cc->outstanding_tags) *
+                                              cc->outstanding_tag_capacity);
+  }
+  cc->outstanding_tags[cc->outstanding_tag_count++] = tag;
+  gpr_mu_unlock(cc->mu);
+#endif
+  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 */
+/* Queue a GRPC_OP_COMPLETED operation */
+void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
+                    void *tag, int success,
+                    void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg,
+                                 grpc_cq_completion *storage),
+                    void *done_arg, grpc_cq_completion *storage) {
+  int shutdown;
+  int i;
+  grpc_pollset_worker *pluck_worker;
+#ifndef NDEBUG
+  int found = 0;
+#endif
+
+  GPR_TIMER_BEGIN("grpc_cq_end_op", 0);
+
+  storage->tag = tag;
+  storage->done = done;
+  storage->done_arg = done_arg;
+  storage->next =
+      ((uintptr_t)&cc->completed_head) | ((uintptr_t)(success != 0));
+
+  gpr_mu_lock(cc->mu);
+#ifndef NDEBUG
+  for (i = 0; i < (int)cc->outstanding_tag_count; i++) {
+    if (cc->outstanding_tags[i] == tag) {
+      cc->outstanding_tag_count--;
+      GPR_SWAP(void *, cc->outstanding_tags[i],
+               cc->outstanding_tags[cc->outstanding_tag_count]);
+      found = 1;
+      break;
+    }
+  }
+  GPR_ASSERT(found);
+#endif
+  shutdown = gpr_unref(&cc->pending_events);
+  if (!shutdown) {
+    cc->completed_tail->next =
+        ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next);
+    cc->completed_tail = storage;
+    pluck_worker = NULL;
+    for (i = 0; i < cc->num_pluckers; i++) {
+      if (cc->pluckers[i].tag == tag) {
+        pluck_worker = *cc->pluckers[i].worker;
+        break;
+      }
+    }
+    grpc_pollset_kick(POLLSET_FROM_CQ(cc), pluck_worker);
+    gpr_mu_unlock(cc->mu);
+  } else {
+    cc->completed_tail->next =
+        ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next);
+    cc->completed_tail = storage;
+    GPR_ASSERT(!cc->shutdown);
+    GPR_ASSERT(cc->shutdown_called);
+    cc->shutdown = 1;
+    grpc_pollset_shutdown(exec_ctx, POLLSET_FROM_CQ(cc),
+                          &cc->pollset_shutdown_done);
+    gpr_mu_unlock(cc->mu);
+  }
+
+  GPR_TIMER_END("grpc_cq_end_op", 0);
+}
+
+grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
+                                      gpr_timespec deadline, void *reserved) {
+  grpc_event ret;
+  grpc_pollset_worker *worker = NULL;
+  int first_loop = 1;
+  gpr_timespec now;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  GPR_TIMER_BEGIN("grpc_completion_queue_next", 0);
+
+  GRPC_API_TRACE(
+      "grpc_completion_queue_next("
+      "cc=%p, "
+      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
+      "reserved=%p)",
+      5, (cc, (long long)deadline.tv_sec, (int)deadline.tv_nsec,
+          (int)deadline.clock_type, reserved));
+  GPR_ASSERT(!reserved);
+
+  deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
+
+  GRPC_CQ_INTERNAL_REF(cc, "next");
+  gpr_mu_lock(cc->mu);
+  for (;;) {
+    if (cc->completed_tail != &cc->completed_head) {
+      grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next;
+      cc->completed_head.next = c->next & ~(uintptr_t)1;
+      if (c == cc->completed_tail) {
+        cc->completed_tail = &cc->completed_head;
+      }
+      gpr_mu_unlock(cc->mu);
+      ret.type = GRPC_OP_COMPLETE;
+      ret.success = c->next & 1u;
+      ret.tag = c->tag;
+      c->done(&exec_ctx, c->done_arg, c);
+      break;
+    }
+    if (cc->shutdown) {
+      gpr_mu_unlock(cc->mu);
+      memset(&ret, 0, sizeof(ret));
+      ret.type = GRPC_QUEUE_SHUTDOWN;
+      break;
+    }
+    now = gpr_now(GPR_CLOCK_MONOTONIC);
+    if (!first_loop && gpr_time_cmp(now, deadline) >= 0) {
+      gpr_mu_unlock(cc->mu);
+      memset(&ret, 0, sizeof(ret));
+      ret.type = GRPC_QUEUE_TIMEOUT;
+      break;
+    }
+    first_loop = 0;
+    /* Check alarms - these are a global resource so we just ping
+       each time through on every pollset.
+       May update deadline to ensure timely wakeups.
+       TODO(ctiller): can this work be localized? */
+    gpr_timespec iteration_deadline = deadline;
+    if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) {
+      GPR_TIMER_MARK("alarm_triggered", 0);
+      gpr_mu_unlock(cc->mu);
+      grpc_exec_ctx_flush(&exec_ctx);
+      gpr_mu_lock(cc->mu);
+      continue;
+    } else {
+      grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), &worker, now,
+                        iteration_deadline);
+    }
+  }
+  GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
+  GRPC_CQ_INTERNAL_UNREF(cc, "next");
+  grpc_exec_ctx_finish(&exec_ctx);
+
+  GPR_TIMER_END("grpc_completion_queue_next", 0);
+
+  return ret;
+}
+
+static int add_plucker(grpc_completion_queue *cc, void *tag,
+                       grpc_pollset_worker **worker) {
+  if (cc->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) {
+    return 0;
+  }
+  cc->pluckers[cc->num_pluckers].tag = tag;
+  cc->pluckers[cc->num_pluckers].worker = worker;
+  cc->num_pluckers++;
+  return 1;
+}
+
+static void del_plucker(grpc_completion_queue *cc, void *tag,
+                        grpc_pollset_worker **worker) {
+  int i;
+  for (i = 0; i < cc->num_pluckers; i++) {
+    if (cc->pluckers[i].tag == tag && cc->pluckers[i].worker == worker) {
+      cc->num_pluckers--;
+      GPR_SWAP(plucker, cc->pluckers[i], cc->pluckers[cc->num_pluckers]);
+      return;
+    }
+  }
+  GPR_UNREACHABLE_CODE(return );
+}
+
+grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
+                                       gpr_timespec deadline, void *reserved) {
+  grpc_event ret;
+  grpc_cq_completion *c;
+  grpc_cq_completion *prev;
+  grpc_pollset_worker *worker = NULL;
+  gpr_timespec now;
+  int first_loop = 1;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0);
+
+  GRPC_API_TRACE(
+      "grpc_completion_queue_pluck("
+      "cc=%p, tag=%p, "
+      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
+      "reserved=%p)",
+      6, (cc, tag, (long long)deadline.tv_sec, (int)deadline.tv_nsec,
+          (int)deadline.clock_type, reserved));
+  GPR_ASSERT(!reserved);
+
+  deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
+
+  GRPC_CQ_INTERNAL_REF(cc, "pluck");
+  gpr_mu_lock(cc->mu);
+  for (;;) {
+    prev = &cc->completed_head;
+    while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) !=
+           &cc->completed_head) {
+      if (c->tag == tag) {
+        prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1);
+        if (c == cc->completed_tail) {
+          cc->completed_tail = prev;
+        }
+        gpr_mu_unlock(cc->mu);
+        ret.type = GRPC_OP_COMPLETE;
+        ret.success = c->next & 1u;
+        ret.tag = c->tag;
+        c->done(&exec_ctx, c->done_arg, c);
+        goto done;
+      }
+      prev = c;
+    }
+    if (cc->shutdown) {
+      gpr_mu_unlock(cc->mu);
+      memset(&ret, 0, sizeof(ret));
+      ret.type = GRPC_QUEUE_SHUTDOWN;
+      break;
+    }
+    if (!add_plucker(cc, tag, &worker)) {
+      gpr_log(GPR_DEBUG,
+              "Too many outstanding grpc_completion_queue_pluck calls: maximum "
+              "is %d",
+              GRPC_MAX_COMPLETION_QUEUE_PLUCKERS);
+      gpr_mu_unlock(cc->mu);
+      memset(&ret, 0, sizeof(ret));
+      /* TODO(ctiller): should we use a different result here */
+      ret.type = GRPC_QUEUE_TIMEOUT;
+      break;
+    }
+    now = gpr_now(GPR_CLOCK_MONOTONIC);
+    if (!first_loop && gpr_time_cmp(now, deadline) >= 0) {
+      del_plucker(cc, tag, &worker);
+      gpr_mu_unlock(cc->mu);
+      memset(&ret, 0, sizeof(ret));
+      ret.type = GRPC_QUEUE_TIMEOUT;
+      break;
+    }
+    first_loop = 0;
+    /* Check alarms - these are a global resource so we just ping
+       each time through on every pollset.
+       May update deadline to ensure timely wakeups.
+       TODO(ctiller): can this work be localized? */
+    gpr_timespec iteration_deadline = deadline;
+    if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) {
+      GPR_TIMER_MARK("alarm_triggered", 0);
+      gpr_mu_unlock(cc->mu);
+      grpc_exec_ctx_flush(&exec_ctx);
+      gpr_mu_lock(cc->mu);
+    } else {
+      grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), &worker, now,
+                        iteration_deadline);
+    }
+    del_plucker(cc, tag, &worker);
+  }
+done:
+  GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
+  GRPC_CQ_INTERNAL_UNREF(cc, "pluck");
+  grpc_exec_ctx_finish(&exec_ctx);
+
+  GPR_TIMER_END("grpc_completion_queue_pluck", 0);
+
+  return ret;
+}
+
+/* Shutdown simply drops a ref that we reserved at creation time; if we drop
+   to zero here, then enter shutdown mode and wake up any waiters */
+void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  GPR_TIMER_BEGIN("grpc_completion_queue_shutdown", 0);
+  GRPC_API_TRACE("grpc_completion_queue_shutdown(cc=%p)", 1, (cc));
+  gpr_mu_lock(cc->mu);
+  if (cc->shutdown_called) {
+    gpr_mu_unlock(cc->mu);
+    GPR_TIMER_END("grpc_completion_queue_shutdown", 0);
+    return;
+  }
+  cc->shutdown_called = 1;
+  if (gpr_unref(&cc->pending_events)) {
+    GPR_ASSERT(!cc->shutdown);
+    cc->shutdown = 1;
+    grpc_pollset_shutdown(&exec_ctx, POLLSET_FROM_CQ(cc),
+                          &cc->pollset_shutdown_done);
+  }
+  gpr_mu_unlock(cc->mu);
+  grpc_exec_ctx_finish(&exec_ctx);
+  GPR_TIMER_END("grpc_completion_queue_shutdown", 0);
+}
+
+void grpc_completion_queue_destroy(grpc_completion_queue *cc) {
+  GRPC_API_TRACE("grpc_completion_queue_destroy(cc=%p)", 1, (cc));
+  GPR_TIMER_BEGIN("grpc_completion_queue_destroy", 0);
+  grpc_completion_queue_shutdown(cc);
+  GRPC_CQ_INTERNAL_UNREF(cc, "destroy");
+  GPR_TIMER_END("grpc_completion_queue_destroy", 0);
+}
+
+grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) {
+  return POLLSET_FROM_CQ(cc);
+}
+
+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/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h
new file mode 100644
index 0000000..35591cb
--- /dev/null
+++ b/src/core/lib/surface/completion_queue.h
@@ -0,0 +1,91 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_H
+#define GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_H
+
+/* Internal API for completion queues */
+
+#include <grpc/grpc.h>
+#include "src/core/lib/iomgr/pollset.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)(grpc_exec_ctx *exec_ctx, void *done_arg,
+               struct grpc_cq_completion *c);
+  void *done_arg;
+  /** next pointer; low bit is used to indicate success or not */
+  uintptr_t 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.
+   \a tag is currently used only in debug builds. */
+void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag);
+
+/* Queue a GRPC_OP_COMPLETED operation; tag must correspond to the tag passed to
+   grpc_cq_begin_op */
+void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
+                    void *tag, int success,
+                    void (*done)(grpc_exec_ctx *exec_ctx, 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_mark_server_cq(grpc_completion_queue *cc);
+int grpc_cq_is_server_cq(grpc_completion_queue *cc);
+
+void grpc_cq_global_init(void);
+void grpc_cq_global_shutdown(void);
+
+#endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_H */
diff --git a/src/core/lib/surface/event_string.c b/src/core/lib/surface/event_string.c
new file mode 100644
index 0000000..360c718
--- /dev/null
+++ b/src/core/lib/surface/event_string.c
@@ -0,0 +1,81 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/event_string.h"
+
+#include <stdio.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/support/string_util.h>
+#include "src/core/lib/support/string.h"
+
+static void addhdr(gpr_strvec *buf, grpc_event *ev) {
+  char *tmp;
+  gpr_asprintf(&tmp, "tag:%p", ev->tag);
+  gpr_strvec_add(buf, tmp);
+}
+
+static const char *errstr(int success) { return success ? "OK" : "ERROR"; }
+
+static void adderr(gpr_strvec *buf, int success) {
+  char *tmp;
+  gpr_asprintf(&tmp, " %s", errstr(success));
+  gpr_strvec_add(buf, tmp);
+}
+
+char *grpc_event_string(grpc_event *ev) {
+  char *out;
+  gpr_strvec buf;
+
+  if (ev == NULL) return gpr_strdup("null");
+
+  gpr_strvec_init(&buf);
+
+  switch (ev->type) {
+    case GRPC_QUEUE_TIMEOUT:
+      gpr_strvec_add(&buf, gpr_strdup("QUEUE_TIMEOUT"));
+      break;
+    case GRPC_QUEUE_SHUTDOWN:
+      gpr_strvec_add(&buf, gpr_strdup("QUEUE_SHUTDOWN"));
+      break;
+    case GRPC_OP_COMPLETE:
+      gpr_strvec_add(&buf, gpr_strdup("OP_COMPLETE: "));
+      addhdr(&buf, ev);
+      adderr(&buf, ev->success);
+      break;
+  }
+
+  out = gpr_strvec_flatten(&buf, NULL);
+  gpr_strvec_destroy(&buf);
+  return out;
+}
diff --git a/src/core/lib/surface/event_string.h b/src/core/lib/surface/event_string.h
new file mode 100644
index 0000000..577e9c7
--- /dev/null
+++ b/src/core/lib/surface/event_string.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_EVENT_STRING_H
+#define GRPC_CORE_LIB_SURFACE_EVENT_STRING_H
+
+#include <grpc/grpc.h>
+
+/* Returns a string describing an event. Must be later freed with gpr_free() */
+char *grpc_event_string(grpc_event *ev);
+
+#endif /* GRPC_CORE_LIB_SURFACE_EVENT_STRING_H */
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
new file mode 100644
index 0000000..dbfc8a9
--- /dev/null
+++ b/src/core/lib/surface/init.c
@@ -0,0 +1,239 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include <limits.h>
+#include <memory.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/time.h>
+/* TODO(ctiller): find another way? - better not to include census here */
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/census/grpc_plugin.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/compress_filter.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_client_filter.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/client_config/lb_policies/pick_first.h"
+#include "src/core/lib/client_config/lb_policies/round_robin.h"
+#include "src/core/lib/client_config/lb_policy_registry.h"
+#include "src/core/lib/client_config/resolver_registry.h"
+#include "src/core/lib/client_config/resolvers/dns_resolver.h"
+#include "src/core/lib/client_config/resolvers/sockaddr_resolver.h"
+#include "src/core/lib/client_config/subchannel.h"
+#include "src/core/lib/client_config/subchannel_index.h"
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/channel_init.h"
+#include "src/core/lib/surface/completion_queue.h"
+#include "src/core/lib/surface/init.h"
+#include "src/core/lib/surface/lame_client.h"
+#include "src/core/lib/surface/server.h"
+#include "src/core/lib/surface/surface_trace.h"
+#include "src/core/lib/transport/connectivity_state.h"
+#include "src/core/lib/transport/transport_impl.h"
+
+#ifndef GRPC_DEFAULT_NAME_PREFIX
+#define GRPC_DEFAULT_NAME_PREFIX "dns:///"
+#endif
+
+#define MAX_PLUGINS 128
+
+static gpr_once g_basic_init = GPR_ONCE_INIT;
+static gpr_mu g_init_mu;
+static int g_initializations;
+
+static void do_basic_init(void) {
+  gpr_mu_init(&g_init_mu);
+  /* TODO(ctiller): ideally remove this strict linkage */
+  grpc_register_plugin(census_grpc_plugin_init, census_grpc_plugin_destroy);
+  g_initializations = 0;
+}
+
+static bool append_filter(grpc_channel_stack_builder *builder, void *arg) {
+  return grpc_channel_stack_builder_append_filter(
+      builder, (const grpc_channel_filter *)arg, NULL, NULL);
+}
+
+static bool prepend_filter(grpc_channel_stack_builder *builder, void *arg) {
+  return grpc_channel_stack_builder_prepend_filter(
+      builder, (const grpc_channel_filter *)arg, NULL, NULL);
+}
+
+static bool maybe_add_http_filter(grpc_channel_stack_builder *builder,
+                                  void *arg) {
+  grpc_transport *t = grpc_channel_stack_builder_get_transport(builder);
+  if (t && strstr(t->vtable->name, "http")) {
+    return grpc_channel_stack_builder_prepend_filter(
+        builder, (const grpc_channel_filter *)arg, NULL, NULL);
+  }
+  return true;
+}
+
+static void register_builtin_channel_init() {
+  grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, prepend_filter,
+                                   (void *)&grpc_compress_filter);
+  grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX,
+                                   prepend_filter,
+                                   (void *)&grpc_compress_filter);
+  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, prepend_filter,
+                                   (void *)&grpc_compress_filter);
+  grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX,
+                                   maybe_add_http_filter,
+                                   (void *)&grpc_http_client_filter);
+  grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX,
+                                   grpc_add_connected_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX,
+                                   maybe_add_http_filter,
+                                   (void *)&grpc_http_client_filter);
+  grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX,
+                                   grpc_add_connected_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
+                                   maybe_add_http_filter,
+                                   (void *)&grpc_http_server_filter);
+  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
+                                   grpc_add_connected_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, append_filter,
+                                   (void *)&grpc_client_channel_filter);
+  grpc_channel_init_register_stage(GRPC_CLIENT_LAME_CHANNEL, INT_MAX,
+                                   append_filter, (void *)&grpc_lame_filter);
+  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, prepend_filter,
+                                   (void *)&grpc_server_top_filter);
+}
+
+typedef struct grpc_plugin {
+  void (*init)();
+  void (*destroy)();
+} grpc_plugin;
+
+static grpc_plugin g_all_of_the_plugins[MAX_PLUGINS];
+static int g_number_of_plugins = 0;
+
+void grpc_register_plugin(void (*init)(void), void (*destroy)(void)) {
+  GRPC_API_TRACE("grpc_register_plugin(init=%p, destroy=%p)", 2,
+                 ((void *)(intptr_t)init, (void *)(intptr_t)destroy));
+  GPR_ASSERT(g_number_of_plugins != MAX_PLUGINS);
+  g_all_of_the_plugins[g_number_of_plugins].init = init;
+  g_all_of_the_plugins[g_number_of_plugins].destroy = destroy;
+  g_number_of_plugins++;
+}
+
+void grpc_init(void) {
+  int i;
+  gpr_once_init(&g_basic_init, do_basic_init);
+
+  gpr_mu_lock(&g_init_mu);
+  if (++g_initializations == 1) {
+    gpr_time_init();
+    grpc_mdctx_global_init();
+    grpc_channel_init_init();
+    grpc_lb_policy_registry_init(grpc_pick_first_lb_factory_create());
+    grpc_register_lb_policy(grpc_pick_first_lb_factory_create());
+    grpc_register_lb_policy(grpc_round_robin_lb_factory_create());
+    grpc_resolver_registry_init(GRPC_DEFAULT_NAME_PREFIX);
+    grpc_register_resolver_type(grpc_dns_resolver_factory_create());
+    grpc_register_resolver_type(grpc_ipv4_resolver_factory_create());
+    grpc_register_resolver_type(grpc_ipv6_resolver_factory_create());
+#ifdef GPR_POSIX_SOCKET
+    grpc_register_resolver_type(grpc_unix_resolver_factory_create());
+#endif
+    grpc_register_tracer("api", &grpc_api_trace);
+    grpc_register_tracer("channel", &grpc_trace_channel);
+    grpc_register_tracer("http", &grpc_http_trace);
+    grpc_register_tracer("flowctl", &grpc_flowctl_trace);
+    grpc_register_tracer("connectivity_state", &grpc_connectivity_state_trace);
+    grpc_register_tracer("channel_stack_builder",
+                         &grpc_trace_channel_stack_builder);
+    grpc_security_pre_init();
+    grpc_iomgr_init();
+    grpc_executor_init();
+    grpc_tracer_init("GRPC_TRACE");
+    gpr_timers_global_init();
+    grpc_cq_global_init();
+    grpc_subchannel_index_init();
+    for (i = 0; i < g_number_of_plugins; i++) {
+      if (g_all_of_the_plugins[i].init != NULL) {
+        g_all_of_the_plugins[i].init();
+      }
+    }
+    /* register channel finalization AFTER all plugins, to ensure that it's run
+     * at the appropriate time */
+    grpc_register_security_filters();
+    register_builtin_channel_init();
+    /* no more changes to channel init pipelines */
+    grpc_channel_init_finalize();
+  }
+  gpr_mu_unlock(&g_init_mu);
+  GRPC_API_TRACE("grpc_init(void)", 0, ());
+}
+
+void grpc_shutdown(void) {
+  int i;
+  GRPC_API_TRACE("grpc_shutdown(void)", 0, ());
+  gpr_mu_lock(&g_init_mu);
+  if (--g_initializations == 0) {
+    grpc_executor_shutdown();
+    grpc_cq_global_shutdown();
+    grpc_iomgr_shutdown();
+    grpc_subchannel_index_shutdown();
+    gpr_timers_global_destroy();
+    grpc_tracer_shutdown();
+    grpc_resolver_registry_shutdown();
+    grpc_lb_policy_registry_shutdown();
+    for (i = 0; i < g_number_of_plugins; i++) {
+      if (g_all_of_the_plugins[i].destroy != NULL) {
+        g_all_of_the_plugins[i].destroy();
+      }
+    }
+    grpc_channel_init_shutdown();
+    grpc_mdctx_global_shutdown();
+  }
+  gpr_mu_unlock(&g_init_mu);
+}
+
+int grpc_is_initialized(void) {
+  int r;
+  gpr_once_init(&g_basic_init, do_basic_init);
+  gpr_mu_lock(&g_init_mu);
+  r = g_initializations > 0;
+  gpr_mu_unlock(&g_init_mu);
+  return r;
+}
diff --git a/src/core/lib/surface/init.h b/src/core/lib/surface/init.h
new file mode 100644
index 0000000..10e2a58
--- /dev/null
+++ b/src/core/lib/surface/init.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_INIT_H
+#define GRPC_CORE_LIB_SURFACE_INIT_H
+
+void grpc_register_security_filters(void);
+void grpc_security_pre_init(void);
+int grpc_is_initialized(void);
+
+#endif /* GRPC_CORE_LIB_SURFACE_INIT_H */
diff --git a/src/core/lib/surface/init_secure.c b/src/core/lib/surface/init_secure.c
new file mode 100644
index 0000000..d3c2f64
--- /dev/null
+++ b/src/core/lib/surface/init_secure.c
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/init.h"
+
+#include <limits.h>
+#include <string.h>
+
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/security/auth_filters.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/security/secure_endpoint.h"
+#include "src/core/lib/security/security_connector.h"
+#include "src/core/lib/surface/channel_init.h"
+#include "src/core/lib/tsi/transport_security_interface.h"
+
+void grpc_security_pre_init(void) {
+  grpc_register_tracer("secure_endpoint", &grpc_trace_secure_endpoint);
+  grpc_register_tracer("transport_security", &tsi_tracing_enabled);
+}
+
+static bool maybe_prepend_client_auth_filter(
+    grpc_channel_stack_builder *builder, void *arg) {
+  const grpc_channel_args *args =
+      grpc_channel_stack_builder_get_channel_arguments(builder);
+  if (args) {
+    for (size_t i = 0; i < args->num_args; i++) {
+      if (0 == strcmp(GRPC_SECURITY_CONNECTOR_ARG, args->args[i].key)) {
+        return grpc_channel_stack_builder_prepend_filter(
+            builder, &grpc_client_auth_filter, NULL, NULL);
+      }
+    }
+  }
+  return true;
+}
+
+static bool maybe_prepend_server_auth_filter(
+    grpc_channel_stack_builder *builder, void *arg) {
+  const grpc_channel_args *args =
+      grpc_channel_stack_builder_get_channel_arguments(builder);
+  if (args) {
+    for (size_t i = 0; i < args->num_args; i++) {
+      if (0 == strcmp(GRPC_SERVER_CREDENTIALS_ARG, args->args[i].key)) {
+        return grpc_channel_stack_builder_prepend_filter(
+            builder, &grpc_server_auth_filter, NULL, NULL);
+      }
+    }
+  }
+  return true;
+}
+
+void grpc_register_security_filters(void) {
+  grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX,
+                                   maybe_prepend_client_auth_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX,
+                                   maybe_prepend_client_auth_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
+                                   maybe_prepend_server_auth_filter, NULL);
+}
diff --git a/src/core/lib/surface/init_unsecure.c b/src/core/lib/surface/init_unsecure.c
new file mode 100644
index 0000000..243c005
--- /dev/null
+++ b/src/core/lib/surface/init_unsecure.c
@@ -0,0 +1,38 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/init.h"
+
+void grpc_security_pre_init(void) {}
+
+void grpc_register_security_filters(void) {}
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
new file mode 100644
index 0000000..95ec4b0
--- /dev/null
+++ b/src/core/lib/surface/lame_client.c
@@ -0,0 +1,155 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/lame_client.h"
+
+#include <grpc/grpc.h>
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/channel.h"
+
+typedef struct {
+  grpc_linked_mdelem status;
+  grpc_linked_mdelem details;
+} call_data;
+
+typedef struct {
+  grpc_status_code error_code;
+  const char *error_message;
+} channel_data;
+
+static void fill_metadata(grpc_call_element *elem, grpc_metadata_batch *mdb) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  char tmp[GPR_LTOA_MIN_BUFSIZE];
+  gpr_ltoa(chand->error_code, tmp);
+  calld->status.md = grpc_mdelem_from_strings("grpc-status", tmp);
+  calld->details.md =
+      grpc_mdelem_from_strings("grpc-message", chand->error_message);
+  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->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+}
+
+static void lame_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
+                                           grpc_call_element *elem,
+                                           grpc_transport_stream_op *op) {
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+  if (op->recv_initial_metadata != NULL) {
+    fill_metadata(elem, op->recv_initial_metadata);
+  } else if (op->recv_trailing_metadata != NULL) {
+    fill_metadata(elem, op->recv_trailing_metadata);
+  }
+  grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
+}
+
+static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
+  return NULL;
+}
+
+static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
+                                    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(
+        exec_ctx, op->on_connectivity_state_change->cb_arg, 1);
+  }
+  if (op->on_consumed != NULL) {
+    op->on_consumed->cb(exec_ctx, op->on_consumed->cb_arg, 1);
+  }
+}
+
+static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                           grpc_call_element_args *args) {}
+
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_call_element *elem) {}
+
+static void init_channel_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_channel_element *elem,
+                              grpc_channel_element_args *args) {
+  GPR_ASSERT(args->is_first);
+  GPR_ASSERT(args->is_last);
+}
+
+static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem) {}
+
+const grpc_channel_filter grpc_lame_filter = {
+    lame_start_transport_stream_op,
+    lame_start_transport_op,
+    sizeof(call_data),
+    init_call_elem,
+    grpc_call_stack_ignore_set_pollset,
+    destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    lame_get_peer,
+    "lame-client",
+};
+
+#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1))
+
+grpc_channel *grpc_lame_client_channel_create(const char *target,
+                                              grpc_status_code error_code,
+                                              const char *error_message) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_channel_element *elem;
+  channel_data *chand;
+  grpc_channel *channel = grpc_channel_create(&exec_ctx, target, NULL,
+                                              GRPC_CLIENT_LAME_CHANNEL, NULL);
+  elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
+  GRPC_API_TRACE(
+      "grpc_lame_client_channel_create(target=%s, error_code=%d, "
+      "error_message=%s)",
+      3, (target, (int)error_code, error_message));
+  GPR_ASSERT(elem->filter == &grpc_lame_filter);
+  chand = (channel_data *)elem->channel_data;
+  chand->error_code = error_code;
+  chand->error_message = error_message;
+  grpc_exec_ctx_finish(&exec_ctx);
+  return channel;
+}
diff --git a/src/core/lib/surface/lame_client.h b/src/core/lib/surface/lame_client.h
new file mode 100644
index 0000000..5f6ea34
--- /dev/null
+++ b/src/core/lib/surface/lame_client.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_LAME_CLIENT_H
+#define GRPC_CORE_LIB_SURFACE_LAME_CLIENT_H
+
+#include "src/core/lib/channel/channel_stack.h"
+
+extern const grpc_channel_filter grpc_lame_filter;
+
+#endif /* GRPC_CORE_LIB_SURFACE_LAME_CLIENT_H */
diff --git a/src/core/lib/surface/metadata_array.c b/src/core/lib/surface/metadata_array.c
new file mode 100644
index 0000000..4436f2d
--- /dev/null
+++ b/src/core/lib/surface/metadata_array.c
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+
+#include <string.h>
+
+#include "src/core/lib/surface/api_trace.h"
+
+void grpc_metadata_array_init(grpc_metadata_array* array) {
+  GRPC_API_TRACE("grpc_metadata_array_init(array=%p)", 1, (array));
+  memset(array, 0, sizeof(*array));
+}
+
+void grpc_metadata_array_destroy(grpc_metadata_array* array) {
+  GRPC_API_TRACE("grpc_metadata_array_destroy(array=%p)", 1, (array));
+  gpr_free(array->metadata);
+}
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
new file mode 100644
index 0000000..080734e
--- /dev/null
+++ b/src/core/lib/surface/server.c
@@ -0,0 +1,1319 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/server.h"
+
+#include <limits.h>
+#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/lib/channel/channel_args.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/support/stack_lockfree.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/completion_queue.h"
+#include "src/core/lib/surface/init.h"
+#include "src/core/lib/transport/metadata.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+typedef struct listener {
+  void *arg;
+  void (*start)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
+                grpc_pollset **pollsets, size_t pollset_count);
+  void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
+                  grpc_closure *closure);
+  struct listener *next;
+  grpc_closure destroy_done;
+} listener;
+
+typedef struct call_data call_data;
+typedef struct channel_data channel_data;
+typedef struct registered_method registered_method;
+
+typedef struct {
+  call_data *next;
+  call_data *prev;
+} call_link;
+
+typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type;
+
+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;
+  grpc_metadata_array *initial_metadata;
+  union {
+    struct {
+      grpc_call_details *details;
+    } batch;
+    struct {
+      registered_method *registered_method;
+      gpr_timespec *deadline;
+      grpc_byte_buffer **optional_payload;
+    } registered;
+  } data;
+  grpc_closure publish;
+} requested_call;
+
+typedef struct channel_registered_method {
+  registered_method *server_registered_method;
+  grpc_mdstr *method;
+  grpc_mdstr *host;
+} channel_registered_method;
+
+struct channel_data {
+  grpc_server *server;
+  grpc_connectivity_state connectivity_state;
+  grpc_channel *channel;
+  /* linked list of all channels on a server */
+  channel_data *next;
+  channel_data *prev;
+  channel_registered_method *registered_methods;
+  uint32_t registered_method_slots;
+  uint32_t registered_method_max_probes;
+  grpc_closure finish_destroy_channel_closure;
+  grpc_closure channel_connectivity_changed;
+};
+
+typedef struct shutdown_tag {
+  void *tag;
+  grpc_completion_queue *cq;
+  grpc_cq_completion completion;
+} shutdown_tag;
+
+typedef enum {
+  /* waiting for metadata */
+  NOT_STARTED,
+  /* inital metadata read, not flow controlled in yet */
+  PENDING,
+  /* flow controlled in, on completion queue */
+  ACTIVATED,
+  /* cancelled before being queued */
+  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;
+
+  grpc_completion_queue *cq_new;
+
+  grpc_metadata_batch *recv_initial_metadata;
+  grpc_metadata_array initial_metadata;
+
+  grpc_closure got_initial_metadata;
+  grpc_closure server_on_recv_initial_metadata;
+  grpc_closure kill_zombie_closure;
+  grpc_closure *on_done_recv_initial_metadata;
+
+  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 {
+  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;
+  size_t max_requested_calls;
+
+  gpr_atm shutdown_flag;
+  uint8_t 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) \
+  (((channel_data *)(elem)->channel_data)->server)
+
+static void begin_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
+                       call_data *calld, requested_call *rc);
+static void fail_call(grpc_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx, grpc_server *server);
+
+/*
+ * 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++;
+  }
+  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");
+  }
+}
+
+struct shutdown_cleanup_args {
+  grpc_closure closure;
+  gpr_slice slice;
+};
+
+static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg,
+                             bool iomgr_status_ignored) {
+  struct shutdown_cleanup_args *a = arg;
+  gpr_slice_unref(a->slice);
+  gpr_free(a);
+}
+
+static void send_shutdown(grpc_exec_ctx *exec_ctx, 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_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(exec_ctx, elem, &op);
+}
+
+static void channel_broadcaster_shutdown(grpc_exec_ctx *exec_ctx,
+                                         channel_broadcaster *cb,
+                                         int send_goaway,
+                                         int force_disconnect) {
+  size_t i;
+
+  for (i = 0; i < cb->num_channels; i++) {
+    send_shutdown(exec_ctx, cb->channels[i], send_goaway, force_disconnect);
+    GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, cb->channels[i], "broadcast");
+  }
+  gpr_free(cb->channels);
+}
+
+/*
+ * request_matcher
+ */
+
+static void request_matcher_init(request_matcher *rm, size_t entries) {
+  memset(rm, 0, sizeof(*rm));
+  rm->requests = gpr_stack_lockfree_create(entries);
+}
+
+static void request_matcher_destroy(request_matcher *rm) {
+  GPR_ASSERT(gpr_stack_lockfree_pop(rm->requests) == -1);
+  gpr_stack_lockfree_destroy(rm->requests);
+}
+
+static void kill_zombie(grpc_exec_ctx *exec_ctx, void *elem, bool success) {
+  grpc_call_destroy(grpc_call_from_top_element(elem));
+}
+
+static void request_matcher_zombify_all_pending_calls(grpc_exec_ctx *exec_ctx,
+                                                      request_matcher *rm) {
+  while (rm->pending_head) {
+    call_data *calld = rm->pending_head;
+    rm->pending_head = calld->pending_next;
+    gpr_mu_lock(&calld->mu_state);
+    calld->state = ZOMBIED;
+    gpr_mu_unlock(&calld->mu_state);
+    grpc_closure_init(
+        &calld->kill_zombie_closure, kill_zombie,
+        grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
+    grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
+  }
+}
+
+static void request_matcher_kill_requests(grpc_exec_ctx *exec_ctx,
+                                          grpc_server *server,
+                                          request_matcher *rm) {
+  int request_id;
+  while ((request_id = gpr_stack_lockfree_pop(rm->requests)) != -1) {
+    fail_call(exec_ctx, server, &server->requested_calls[request_id]);
+  }
+}
+
+/*
+ * server proper
+ */
+
+static void server_ref(grpc_server *server) {
+  gpr_ref(&server->internal_refcount);
+}
+
+static void server_delete(grpc_exec_ctx *exec_ctx, grpc_server *server) {
+  registered_method *rm;
+  size_t i;
+  grpc_channel_args_destroy(server->channel_args);
+  gpr_mu_destroy(&server->mu_global);
+  gpr_mu_destroy(&server->mu_call);
+  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);
+    gpr_free(rm);
+  }
+  for (i = 0; i < server->cq_count; 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);
+}
+
+static void server_unref(grpc_exec_ctx *exec_ctx, grpc_server *server) {
+  if (gpr_unref(&server->internal_refcount)) {
+    server_delete(exec_ctx, server);
+  }
+}
+
+static int is_channel_orphaned(channel_data *chand) {
+  return chand->next == chand;
+}
+
+static void orphan_channel(channel_data *chand) {
+  chand->next->prev = chand->prev;
+  chand->prev->next = chand->next;
+  chand->next = chand->prev = chand;
+}
+
+static void finish_destroy_channel(grpc_exec_ctx *exec_ctx, void *cd,
+                                   bool success) {
+  channel_data *chand = cd;
+  grpc_server *server = chand->server;
+  GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "server");
+  server_unref(exec_ctx, server);
+}
+
+static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand) {
+  if (is_channel_orphaned(chand)) return;
+  GPR_ASSERT(chand->server != NULL);
+  orphan_channel(chand);
+  server_ref(chand->server);
+  maybe_finish_shutdown(exec_ctx, chand->server);
+  chand->finish_destroy_channel_closure.cb = finish_destroy_channel;
+  chand->finish_destroy_channel_closure.cb_arg = chand;
+
+  grpc_transport_op op;
+  memset(&op, 0, sizeof(op));
+  op.set_accept_stream = true;
+  op.on_consumed = &chand->finish_destroy_channel_closure;
+  grpc_channel_next_op(exec_ctx,
+                       grpc_channel_stack_element(
+                           grpc_channel_get_channel_stack(chand->channel), 0),
+                       &op);
+}
+
+static void finish_start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_server *server,
+                                 grpc_call_element *elem, request_matcher *rm) {
+  call_data *calld = elem->call_data;
+  int request_id;
+
+  if (gpr_atm_acq_load(&server->shutdown_flag)) {
+    gpr_mu_lock(&calld->mu_state);
+    calld->state = ZOMBIED;
+    gpr_mu_unlock(&calld->mu_state);
+    grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
+    grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
+    return;
+  }
+
+  request_id = gpr_stack_lockfree_pop(rm->requests);
+  if (request_id == -1) {
+    gpr_mu_lock(&server->mu_call);
+    gpr_mu_lock(&calld->mu_state);
+    calld->state = PENDING;
+    gpr_mu_unlock(&calld->mu_state);
+    if (rm->pending_head == NULL) {
+      rm->pending_tail = rm->pending_head = calld;
+    } else {
+      rm->pending_tail->pending_next = calld;
+      rm->pending_tail = calld;
+    }
+    calld->pending_next = NULL;
+    gpr_mu_unlock(&server->mu_call);
+  } else {
+    gpr_mu_lock(&calld->mu_state);
+    calld->state = ACTIVATED;
+    gpr_mu_unlock(&calld->mu_state);
+    begin_call(exec_ctx, server, calld, &server->requested_calls[request_id]);
+  }
+}
+
+static void start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
+  channel_data *chand = elem->channel_data;
+  call_data *calld = elem->call_data;
+  grpc_server *server = chand->server;
+  uint32_t i;
+  uint32_t hash;
+  channel_registered_method *rm;
+
+  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++) {
+      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(exec_ctx, server, elem,
+                           &rm->server_registered_method->request_matcher);
+      return;
+    }
+    /* check for a wildcard method definition (no host set) */
+    hash = GRPC_MDSTR_KV_HASH(0, calld->path->hash);
+    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 != NULL) continue;
+      if (rm->method != calld->path) continue;
+      finish_start_new_rpc(exec_ctx, server, elem,
+                           &rm->server_registered_method->request_matcher);
+      return;
+    }
+  }
+  finish_start_new_rpc(exec_ctx, server, elem,
+                       &server->unregistered_request_matcher);
+}
+
+static int num_listeners(grpc_server *server) {
+  listener *l;
+  int n = 0;
+  for (l = server->listeners; l; l = l->next) {
+    n++;
+  }
+  return n;
+}
+
+static void done_shutdown_event(grpc_exec_ctx *exec_ctx, void *server,
+                                grpc_cq_completion *completion) {
+  server_unref(exec_ctx, 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 kill_pending_work_locked(grpc_exec_ctx *exec_ctx,
+                                     grpc_server *server) {
+  registered_method *rm;
+  request_matcher_kill_requests(exec_ctx, server,
+                                &server->unregistered_request_matcher);
+  request_matcher_zombify_all_pending_calls(
+      exec_ctx, &server->unregistered_request_matcher);
+  for (rm = server->registered_methods; rm; rm = rm->next) {
+    request_matcher_kill_requests(exec_ctx, server, &rm->request_matcher);
+    request_matcher_zombify_all_pending_calls(exec_ctx, &rm->request_matcher);
+  }
+}
+
+static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx,
+                                  grpc_server *server) {
+  size_t i;
+  if (!gpr_atm_acq_load(&server->shutdown_flag) || server->shutdown_published) {
+    return;
+  }
+
+  kill_pending_work_locked(exec_ctx, server);
+
+  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(exec_ctx, server->shutdown_tags[i].cq,
+                   server->shutdown_tags[i].tag, 1, done_shutdown_event, server,
+                   &server->shutdown_tags[i].completion);
+  }
+}
+
+static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
+  grpc_call_element *elem = user_data;
+  call_data *calld = elem->call_data;
+  if (md->key == GRPC_MDSTR_PATH) {
+    calld->path = GRPC_MDSTR_REF(md->value);
+    return NULL;
+  } else if (md->key == GRPC_MDSTR_AUTHORITY) {
+    calld->host = GRPC_MDSTR_REF(md->value);
+    return NULL;
+  }
+  return md;
+}
+
+static void server_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
+                                            bool success) {
+  grpc_call_element *elem = ptr;
+  call_data *calld = elem->call_data;
+  gpr_timespec op_deadline;
+
+  grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, elem);
+  op_deadline = calld->recv_initial_metadata->deadline;
+  if (0 != gpr_time_cmp(op_deadline, gpr_inf_future(op_deadline.clock_type))) {
+    calld->deadline = op_deadline;
+  }
+  if (calld->host && calld->path) {
+    /* do nothing */
+  } else {
+    success = 0;
+  }
+
+  calld->on_done_recv_initial_metadata->cb(
+      exec_ctx, calld->on_done_recv_initial_metadata->cb_arg, success);
+}
+
+static void server_mutate_op(grpc_call_element *elem,
+                             grpc_transport_stream_op *op) {
+  call_data *calld = elem->call_data;
+
+  if (op->recv_initial_metadata != NULL) {
+    calld->recv_initial_metadata = op->recv_initial_metadata;
+    calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready;
+    op->recv_initial_metadata_ready = &calld->server_on_recv_initial_metadata;
+  }
+}
+
+static void server_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
+                                             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(exec_ctx, elem, op);
+}
+
+static void got_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
+                                 bool success) {
+  grpc_call_element *elem = ptr;
+  call_data *calld = elem->call_data;
+  if (success) {
+    start_new_rpc(exec_ctx, elem);
+  } else {
+    gpr_mu_lock(&calld->mu_state);
+    if (calld->state == NOT_STARTED) {
+      calld->state = ZOMBIED;
+      gpr_mu_unlock(&calld->mu_state);
+      grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
+      grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
+    } else if (calld->state == PENDING) {
+      calld->state = ZOMBIED;
+      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);
+    }
+  }
+}
+
+static void accept_stream(grpc_exec_ctx *exec_ctx, void *cd,
+                          grpc_transport *transport,
+                          const void *transport_server_data) {
+  channel_data *chand = cd;
+  /* create a call */
+  grpc_call *call =
+      grpc_call_create(chand->channel, NULL, 0, NULL, transport_server_data,
+                       NULL, 0, gpr_inf_future(GPR_CLOCK_MONOTONIC));
+  grpc_call_element *elem =
+      grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
+  call_data *calld = elem->call_data;
+  grpc_op op;
+  memset(&op, 0, sizeof(op));
+  op.op = GRPC_OP_RECV_INITIAL_METADATA;
+  op.data.recv_initial_metadata = &calld->initial_metadata;
+  grpc_closure_init(&calld->got_initial_metadata, got_initial_metadata, elem);
+  grpc_call_start_batch_and_execute(exec_ctx, call, &op, 1,
+                                    &calld->got_initial_metadata);
+}
+
+static void channel_connectivity_changed(grpc_exec_ctx *exec_ctx, void *cd,
+                                         bool 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(exec_ctx,
+                         grpc_channel_stack_element(
+                             grpc_channel_get_channel_stack(chand->channel), 0),
+                         &op);
+  } else {
+    gpr_mu_lock(&server->mu_global);
+    destroy_channel(exec_ctx, chand);
+    gpr_mu_unlock(&server->mu_global);
+    GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "connectivity");
+  }
+}
+
+static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                           grpc_call_element_args *args) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  memset(calld, 0, sizeof(call_data));
+  calld->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+  calld->call = grpc_call_from_top_element(elem);
+  gpr_mu_init(&calld->mu_state);
+
+  grpc_closure_init(&calld->server_on_recv_initial_metadata,
+                    server_on_recv_initial_metadata, elem);
+
+  server_ref(chand->server);
+}
+
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_call_element *elem) {
+  channel_data *chand = elem->channel_data;
+  call_data *calld = elem->call_data;
+
+  GPR_ASSERT(calld->state != PENDING);
+
+  if (calld->host) {
+    GRPC_MDSTR_UNREF(calld->host);
+  }
+  if (calld->path) {
+    GRPC_MDSTR_UNREF(calld->path);
+  }
+  grpc_metadata_array_destroy(&calld->initial_metadata);
+
+  gpr_mu_destroy(&calld->mu_state);
+
+  server_unref(exec_ctx, chand->server);
+}
+
+static void init_channel_elem(grpc_exec_ctx *exec_ctx,
+                              grpc_channel_element *elem,
+                              grpc_channel_element_args *args) {
+  channel_data *chand = elem->channel_data;
+  GPR_ASSERT(args->is_first);
+  GPR_ASSERT(!args->is_last);
+  chand->server = NULL;
+  chand->channel = NULL;
+  chand->next = chand->prev = chand;
+  chand->registered_methods = NULL;
+  chand->connectivity_state = GRPC_CHANNEL_IDLE;
+  grpc_closure_init(&chand->channel_connectivity_changed,
+                    channel_connectivity_changed, chand);
+}
+
+static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem) {
+  size_t i;
+  channel_data *chand = elem->channel_data;
+  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);
+      }
+      if (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_global);
+    chand->next->prev = chand->prev;
+    chand->prev->next = chand->next;
+    chand->next = chand->prev = chand;
+    maybe_finish_shutdown(exec_ctx, chand->server);
+    gpr_mu_unlock(&chand->server->mu_global);
+    server_unref(exec_ctx, chand->server);
+  }
+}
+
+const grpc_channel_filter grpc_server_top_filter = {
+    server_start_transport_stream_op,
+    grpc_channel_next_op,
+    sizeof(call_data),
+    init_call_elem,
+    grpc_call_stack_ignore_set_pollset,
+    destroy_call_elem,
+    sizeof(channel_data),
+    init_channel_elem,
+    destroy_channel_elem,
+    grpc_call_next_get_peer,
+    "server",
+};
+
+void grpc_server_register_completion_queue(grpc_server *server,
+                                           grpc_completion_queue *cq,
+                                           void *reserved) {
+  size_t i, n;
+  GRPC_API_TRACE(
+      "grpc_server_register_completion_queue(server=%p, cq=%p, reserved=%p)", 3,
+      (server, cq, reserved));
+  GPR_ASSERT(!reserved);
+  for (i = 0; i < server->cq_count; i++) {
+    if (server->cqs[i] == cq) return;
+  }
+  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(const grpc_channel_args *args, void *reserved) {
+  size_t i;
+
+  GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved));
+
+  grpc_server *server = gpr_malloc(sizeof(grpc_server));
+
+  GPR_ASSERT(grpc_is_initialized() && "call grpc_init()");
+
+  memset(server, 0, sizeof(grpc_server));
+
+  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, (int)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->channel_args = grpc_channel_args_copy(args);
+
+  return server;
+}
+
+static int streq(const char *a, const char *b) {
+  if (a == NULL && b == NULL) return 1;
+  if (a == NULL) return 0;
+  if (b == NULL) return 0;
+  return 0 == strcmp(a, b);
+}
+
+void *grpc_server_register_method(grpc_server *server, const char *method,
+                                  const char *host) {
+  registered_method *m;
+  GRPC_API_TRACE("grpc_server_register_method(server=%p, method=%s, host=%s)",
+                 3, (server, method, host));
+  if (!method) {
+    gpr_log(GPR_ERROR,
+            "grpc_server_register_method method string cannot be NULL");
+    return NULL;
+  }
+  for (m = server->registered_methods; m; m = m->next) {
+    if (streq(m->method, method) && streq(m->host, host)) {
+      gpr_log(GPR_ERROR, "duplicate registration for %s@%s", method,
+              host ? host : "*");
+      return NULL;
+    }
+  }
+  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;
+  server->registered_methods = m;
+  return m;
+}
+
+void grpc_server_start(grpc_server *server) {
+  listener *l;
+  size_t i;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  GRPC_API_TRACE("grpc_server_start(server=%p)", 1, (server));
+
+  server->pollsets = gpr_malloc(sizeof(grpc_pollset *) * server->cq_count);
+  for (i = 0; i < server->cq_count; i++) {
+    server->pollsets[i] = grpc_cq_pollset(server->cqs[i]);
+  }
+
+  for (l = server->listeners; l; l = l->next) {
+    l->start(&exec_ctx, server, l->arg, server->pollsets, server->cq_count);
+  }
+
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
+                                 grpc_transport *transport,
+                                 const grpc_channel_args *args) {
+  size_t i;
+  size_t num_registered_methods;
+  size_t alloc;
+  registered_method *rm;
+  channel_registered_method *crm;
+  grpc_channel *channel;
+  channel_data *chand;
+  grpc_mdstr *host;
+  grpc_mdstr *method;
+  uint32_t hash;
+  size_t slots;
+  uint32_t probes;
+  uint32_t max_probes = 0;
+  grpc_transport_op op;
+
+  for (i = 0; i < s->cq_count; i++) {
+    memset(&op, 0, sizeof(op));
+    op.bind_pollset = grpc_cq_pollset(s->cqs[i]);
+    grpc_transport_perform_op(exec_ctx, transport, &op);
+  }
+
+  channel =
+      grpc_channel_create(exec_ctx, NULL, args, GRPC_SERVER_CHANNEL, transport);
+  chand = (channel_data *)grpc_channel_stack_element(
+              grpc_channel_get_channel_stack(channel), 0)
+              ->channel_data;
+  chand->server = s;
+  server_ref(s);
+  chand->channel = channel;
+
+  num_registered_methods = 0;
+  for (rm = s->registered_methods; rm; rm = rm->next) {
+    num_registered_methods++;
+  }
+  /* build a lookup table phrased in terms of mdstr's in this channels context
+     to quickly find registered methods */
+  if (num_registered_methods > 0) {
+    slots = 2 * num_registered_methods;
+    alloc = sizeof(channel_registered_method) * slots;
+    chand->registered_methods = gpr_malloc(alloc);
+    memset(chand->registered_methods, 0, alloc);
+    for (rm = s->registered_methods; rm; rm = rm->next) {
+      host = rm->host ? grpc_mdstr_from_string(rm->host) : NULL;
+      method = grpc_mdstr_from_string(rm->method);
+      hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash);
+      for (probes = 0; chand->registered_methods[(hash + probes) % slots]
+                           .server_registered_method != NULL;
+           probes++)
+        ;
+      if (probes > max_probes) max_probes = probes;
+      crm = &chand->registered_methods[(hash + probes) % slots];
+      crm->server_registered_method = rm;
+      crm->host = host;
+      crm->method = method;
+    }
+    GPR_ASSERT(slots <= UINT32_MAX);
+    chand->registered_method_slots = (uint32_t)slots;
+    chand->registered_method_max_probes = max_probes;
+  }
+
+  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_global);
+
+  GRPC_CHANNEL_INTERNAL_REF(channel, "connectivity");
+  memset(&op, 0, sizeof(op));
+  op.set_accept_stream = true;
+  op.set_accept_stream_fn = accept_stream;
+  op.set_accept_stream_user_data = chand;
+  op.on_connectivity_state_change = &chand->channel_connectivity_changed;
+  op.connectivity_state = &chand->connectivity_state;
+  op.disconnect = gpr_atm_acq_load(&s->shutdown_flag) != 0;
+  grpc_transport_perform_op(exec_ctx, transport, &op);
+}
+
+void done_published_shutdown(grpc_exec_ctx *exec_ctx, void *done_arg,
+                             grpc_cq_completion *storage) {
+  (void)done_arg;
+  gpr_free(storage);
+}
+
+static void listener_destroy_done(grpc_exec_ctx *exec_ctx, void *s,
+                                  bool success) {
+  grpc_server *server = s;
+  gpr_mu_lock(&server->mu_global);
+  server->listeners_destroyed++;
+  maybe_finish_shutdown(exec_ctx, server);
+  gpr_mu_unlock(&server->mu_global);
+}
+
+void grpc_server_shutdown_and_notify(grpc_server *server,
+                                     grpc_completion_queue *cq, void *tag) {
+  listener *l;
+  shutdown_tag *sdt;
+  channel_broadcaster broadcaster;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  GRPC_API_TRACE("grpc_server_shutdown_and_notify(server=%p, cq=%p, tag=%p)", 3,
+                 (server, cq, tag));
+
+  /* lock, and gather up some stuff to do */
+  gpr_mu_lock(&server->mu_global);
+  grpc_cq_begin_op(cq, tag);
+  if (server->shutdown_published) {
+    grpc_cq_end_op(&exec_ctx, cq, tag, 1, done_published_shutdown, NULL,
+                   gpr_malloc(sizeof(grpc_cq_completion)));
+    gpr_mu_unlock(&server->mu_global);
+    goto done;
+  }
+  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 (gpr_atm_acq_load(&server->shutdown_flag)) {
+    gpr_mu_unlock(&server->mu_global);
+    goto done;
+  }
+
+  server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME);
+
+  channel_broadcaster_init(server, &broadcaster);
+
+  gpr_atm_rel_store(&server->shutdown_flag, 1);
+
+  /* collect all unregistered then registered calls */
+  gpr_mu_lock(&server->mu_call);
+  kill_pending_work_locked(&exec_ctx, server);
+  gpr_mu_unlock(&server->mu_call);
+
+  maybe_finish_shutdown(&exec_ctx, server);
+  gpr_mu_unlock(&server->mu_global);
+
+  /* Shutdown listeners */
+  for (l = server->listeners; l; l = l->next) {
+    grpc_closure_init(&l->destroy_done, listener_destroy_done, server);
+    l->destroy(&exec_ctx, server, l->arg, &l->destroy_done);
+  }
+
+  channel_broadcaster_shutdown(&exec_ctx, &broadcaster, 1, 0);
+
+done:
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+void grpc_server_cancel_all_calls(grpc_server *server) {
+  channel_broadcaster broadcaster;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  GRPC_API_TRACE("grpc_server_cancel_all_calls(server=%p)", 1, (server));
+
+  gpr_mu_lock(&server->mu_global);
+  channel_broadcaster_init(server, &broadcaster);
+  gpr_mu_unlock(&server->mu_global);
+
+  channel_broadcaster_shutdown(&exec_ctx, &broadcaster, 0, 1);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+void grpc_server_destroy(grpc_server *server) {
+  listener *l;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  GRPC_API_TRACE("grpc_server_destroy(server=%p)", 1, (server));
+
+  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) {
+    l = server->listeners;
+    server->listeners = l->next;
+    gpr_free(l);
+  }
+
+  gpr_mu_unlock(&server->mu_global);
+
+  server_unref(&exec_ctx, server);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+void grpc_server_add_listener(
+    grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
+    void (*start)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
+                  grpc_pollset **pollsets, size_t pollset_count),
+    void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
+                    grpc_closure *on_done)) {
+  listener *l = gpr_malloc(sizeof(listener));
+  l->arg = arg;
+  l->start = start;
+  l->destroy = destroy;
+  l->next = server->listeners;
+  server->listeners = l;
+}
+
+static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx,
+                                          grpc_server *server,
+                                          requested_call *rc) {
+  call_data *calld = NULL;
+  request_matcher *rm = NULL;
+  int request_id;
+  if (gpr_atm_acq_load(&server->shutdown_flag)) {
+    fail_call(exec_ctx, 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(exec_ctx, server, rc);
+    return GRPC_CALL_OK;
+  }
+  switch (rc->type) {
+    case BATCH_CALL:
+      rm = &server->unregistered_request_matcher;
+      break;
+    case REGISTERED_CALL:
+      rm = &rc->data.registered.registered_method->request_matcher;
+      break;
+  }
+  server->requested_calls[request_id] = *rc;
+  gpr_free(rc);
+  if (gpr_stack_lockfree_push(rm->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 = rm->pending_head) != NULL) {
+      request_id = gpr_stack_lockfree_pop(rm->requests);
+      if (request_id == -1) break;
+      rm->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_closure_init(
+            &calld->kill_zombie_closure, kill_zombie,
+            grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
+        grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true,
+                              NULL);
+      } else {
+        GPR_ASSERT(calld->state == PENDING);
+        calld->state = ACTIVATED;
+        gpr_mu_unlock(&calld->mu_state);
+        begin_call(exec_ctx, 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(
+    grpc_server *server, grpc_call **call, grpc_call_details *details,
+    grpc_metadata_array *initial_metadata,
+    grpc_completion_queue *cq_bound_to_call,
+    grpc_completion_queue *cq_for_notification, void *tag) {
+  grpc_call_error error;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  requested_call *rc = gpr_malloc(sizeof(*rc));
+  GRPC_API_TRACE(
+      "grpc_server_request_call("
+      "server=%p, call=%p, details=%p, initial_metadata=%p, "
+      "cq_bound_to_call=%p, cq_for_notification=%p, tag=%p)",
+      7, (server, call, details, initial_metadata, cq_bound_to_call,
+          cq_for_notification, tag));
+  if (!grpc_cq_is_server_cq(cq_for_notification)) {
+    gpr_free(rc);
+    error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
+    goto done;
+  }
+  grpc_cq_begin_op(cq_for_notification, tag);
+  details->reserved = NULL;
+  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->initial_metadata = initial_metadata;
+  error = queue_call_request(&exec_ctx, server, rc);
+done:
+  grpc_exec_ctx_finish(&exec_ctx);
+  return error;
+}
+
+grpc_call_error grpc_server_request_registered_call(
+    grpc_server *server, void *rmp, grpc_call **call, gpr_timespec *deadline,
+    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) {
+  grpc_call_error error;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  requested_call *rc = gpr_malloc(sizeof(*rc));
+  registered_method *rm = rmp;
+  GRPC_API_TRACE(
+      "grpc_server_request_registered_call("
+      "server=%p, rmp=%p, call=%p, deadline=%p, initial_metadata=%p, "
+      "optional_payload=%p, cq_bound_to_call=%p, cq_for_notification=%p, "
+      "tag=%p)",
+      9, (server, rmp, call, deadline, initial_metadata, optional_payload,
+          cq_bound_to_call, cq_for_notification, tag));
+  if (!grpc_cq_is_server_cq(cq_for_notification)) {
+    gpr_free(rc);
+    error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
+    goto done;
+  }
+  grpc_cq_begin_op(cq_for_notification, tag);
+  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 = rm;
+  rc->data.registered.deadline = deadline;
+  rc->initial_metadata = initial_metadata;
+  rc->data.registered.optional_payload = optional_payload;
+  error = queue_call_request(&exec_ctx, server, rc);
+done:
+  grpc_exec_ctx_finish(&exec_ctx);
+  return error;
+}
+
+static void publish_registered_or_batch(grpc_exec_ctx *exec_ctx,
+                                        void *user_data, bool success);
+
+static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) {
+  gpr_slice slice = value->slice;
+  size_t len = GPR_SLICE_LENGTH(slice);
+
+  if (len + 1 > *capacity) {
+    *capacity = GPR_MAX(len + 1, *capacity * 2);
+    *dest = gpr_realloc(*dest, *capacity);
+  }
+  memcpy(*dest, grpc_mdstr_as_c_string(value), len + 1);
+}
+
+static void begin_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
+                       call_data *calld, requested_call *rc) {
+  grpc_op ops[1];
+  grpc_op *op = ops;
+
+  memset(ops, 0, sizeof(ops));
+
+  /* called once initial metadata has been read by the call, but BEFORE
+     the ioreq to fetch it out of the call has been executed.
+     This means metadata related fields can be relied on in calld, but to
+     fill in the metadata array passed by the client, we need to perform
+     an ioreq op, that should complete immediately. */
+
+  grpc_call_set_completion_queue(exec_ctx, calld->call, rc->cq_bound_to_call);
+  grpc_closure_init(&rc->publish, publish_registered_or_batch, rc);
+  *rc->call = calld->call;
+  calld->cq_new = rc->cq_for_notification;
+  GPR_SWAP(grpc_metadata_array, *rc->initial_metadata, calld->initial_metadata);
+  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,
+            &rc->data.batch.details->method_capacity, calld->path);
+      rc->data.batch.details->deadline = calld->deadline;
+      break;
+    case REGISTERED_CALL:
+      *rc->data.registered.deadline = calld->deadline;
+      if (rc->data.registered.optional_payload) {
+        op->op = GRPC_OP_RECV_MESSAGE;
+        op->data.recv_message = rc->data.registered.optional_payload;
+        op++;
+      }
+      break;
+    default:
+      GPR_UNREACHABLE_CODE(return );
+  }
+
+  GRPC_CALL_INTERNAL_REF(calld->call, "server");
+  grpc_call_start_batch_and_execute(exec_ctx, calld->call, ops,
+                                    (size_t)(op - ops), &rc->publish);
+}
+
+static void done_request_event(grpc_exec_ctx *exec_ctx, 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_ASSERT(rc - server->requested_calls <= INT_MAX);
+    gpr_stack_lockfree_push(server->request_freelist,
+                            (int)(rc - server->requested_calls));
+  } else {
+    gpr_free(req);
+  }
+
+  server_unref(exec_ctx, server);
+}
+
+static void fail_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
+                      requested_call *rc) {
+  *rc->call = NULL;
+  rc->initial_metadata->count = 0;
+
+  server_ref(server);
+  grpc_cq_end_op(exec_ctx, rc->cq_for_notification, rc->tag, 0,
+                 done_request_event, rc, &rc->completion);
+}
+
+static void publish_registered_or_batch(grpc_exec_ctx *exec_ctx, void *prc,
+                                        bool success) {
+  requested_call *rc = prc;
+  grpc_call *call = *rc->call;
+  grpc_call_element *elem =
+      grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
+  server_ref(chand->server);
+  grpc_cq_end_op(exec_ctx, calld->cq_new, rc->tag, success, done_request_event,
+                 rc, &rc->completion);
+  GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "server");
+}
+
+const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) {
+  return server->channel_args;
+}
+
+int grpc_server_has_open_connections(grpc_server *server) {
+  int r;
+  gpr_mu_lock(&server->mu_global);
+  r = server->root_channel_data.next != &server->root_channel_data;
+  gpr_mu_unlock(&server->mu_global);
+  return r;
+}
diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h
new file mode 100644
index 0000000..3845eb2
--- /dev/null
+++ b/src/core/lib/surface/server.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_SERVER_H
+#define GRPC_CORE_LIB_SURFACE_SERVER_H
+
+#include <grpc/grpc.h>
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/transport/transport.h"
+
+extern const grpc_channel_filter grpc_server_top_filter;
+
+/* Add a listener to the server: when the server starts, it will call start,
+   and when it shuts down, it will call destroy */
+void grpc_server_add_listener(
+    grpc_exec_ctx *exec_ctx, grpc_server *server, void *listener,
+    void (*start)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
+                  grpc_pollset **pollsets, size_t npollsets),
+    void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
+                    grpc_closure *on_done));
+
+/* Setup a transport - creates a channel stack, binds the transport to the
+   server */
+void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *server,
+                                 grpc_transport *transport,
+                                 const grpc_channel_args *args);
+
+const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);
+
+int grpc_server_has_open_connections(grpc_server *server);
+
+#endif /* GRPC_CORE_LIB_SURFACE_SERVER_H */
diff --git a/src/core/lib/surface/surface_trace.h b/src/core/lib/surface/surface_trace.h
new file mode 100644
index 0000000..6b3f673
--- /dev/null
+++ b/src/core/lib/surface/surface_trace.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SURFACE_SURFACE_TRACE_H
+#define GRPC_CORE_LIB_SURFACE_SURFACE_TRACE_H
+
+#include <grpc/support/log.h>
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/surface/api_trace.h"
+
+#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event)    \
+  if (grpc_api_trace) {                                 \
+    char *_ev = grpc_event_string(event);               \
+    gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \
+    gpr_free(_ev);                                      \
+  }
+
+#endif /* GRPC_CORE_LIB_SURFACE_SURFACE_TRACE_H */
diff --git a/src/core/surface/validate_metadata.c b/src/core/lib/surface/validate_metadata.c
similarity index 100%
rename from src/core/surface/validate_metadata.c
rename to src/core/lib/surface/validate_metadata.c
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
new file mode 100644
index 0000000..7723f39
--- /dev/null
+++ b/src/core/lib/surface/version.c
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* This file is autogenerated from:
+   templates/src/core/surface/version.c.template */
+
+#include <grpc/grpc.h>
+
+const char *grpc_version_string(void) { return "0.14.0-dev"; }
diff --git a/src/core/lib/transport/byte_stream.c b/src/core/lib/transport/byte_stream.c
new file mode 100644
index 0000000..79981aa
--- /dev/null
+++ b/src/core/lib/transport/byte_stream.c
@@ -0,0 +1,78 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/transport/byte_stream.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/log.h>
+
+int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
+                          grpc_byte_stream *byte_stream, gpr_slice *slice,
+                          size_t max_size_hint, grpc_closure *on_complete) {
+  return byte_stream->next(exec_ctx, byte_stream, slice, max_size_hint,
+                           on_complete);
+}
+
+void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
+                              grpc_byte_stream *byte_stream) {
+  byte_stream->destroy(exec_ctx, byte_stream);
+}
+
+/* slice_buffer_stream */
+
+static int slice_buffer_stream_next(grpc_exec_ctx *exec_ctx,
+                                    grpc_byte_stream *byte_stream,
+                                    gpr_slice *slice, size_t max_size_hint,
+                                    grpc_closure *on_complete) {
+  grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream;
+  GPR_ASSERT(stream->cursor < stream->backing_buffer->count);
+  *slice = gpr_slice_ref(stream->backing_buffer->slices[stream->cursor]);
+  stream->cursor++;
+  return 1;
+}
+
+static void slice_buffer_stream_destroy(grpc_exec_ctx *exec_ctx,
+                                        grpc_byte_stream *byte_stream) {}
+
+void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream,
+                                   gpr_slice_buffer *slice_buffer,
+                                   uint32_t flags) {
+  GPR_ASSERT(slice_buffer->length <= UINT32_MAX);
+  stream->base.length = (uint32_t)slice_buffer->length;
+  stream->base.flags = flags;
+  stream->base.next = slice_buffer_stream_next;
+  stream->base.destroy = slice_buffer_stream_destroy;
+  stream->backing_buffer = slice_buffer;
+  stream->cursor = 0;
+}
diff --git a/src/core/lib/transport/byte_stream.h b/src/core/lib/transport/byte_stream.h
new file mode 100644
index 0000000..e7346da
--- /dev/null
+++ b/src/core/lib/transport/byte_stream.h
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H
+#define GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H
+
+#include <grpc/support/slice_buffer.h>
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+/** Internal bit flag for grpc_begin_message's \a flags signaling the use of
+ * compression for the message */
+#define GRPC_WRITE_INTERNAL_COMPRESS (0x80000000u)
+/** Mask of all valid internal flags. */
+#define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS)
+
+struct grpc_byte_stream;
+typedef struct grpc_byte_stream grpc_byte_stream;
+
+struct grpc_byte_stream {
+  uint32_t length;
+  uint32_t flags;
+  int (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream,
+              gpr_slice *slice, size_t max_size_hint,
+              grpc_closure *on_complete);
+  void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream);
+};
+
+/* returns 1 if the bytes are available immediately (in which case
+ * on_complete will not be called), 0 if the bytes will be available
+ * asynchronously.
+ *
+ * on entry, *remaining can be set as a hint as to the maximum number
+ * of bytes that would be acceptable to read.
+ *
+ * fills *buffer, *length, *remaining with the bytes, length of bytes
+ * and length of data remaining to be read before either returning 1
+ * or calling on_complete.
+ *
+ * once a slice is returned into *slice, it is owned by the caller.
+ */
+int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
+                          grpc_byte_stream *byte_stream, gpr_slice *slice,
+                          size_t max_size_hint, grpc_closure *on_complete);
+
+void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
+                              grpc_byte_stream *byte_stream);
+
+/* grpc_byte_stream that wraps a slice buffer */
+typedef struct grpc_slice_buffer_stream {
+  grpc_byte_stream base;
+  gpr_slice_buffer *backing_buffer;
+  size_t cursor;
+} grpc_slice_buffer_stream;
+
+void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream,
+                                   gpr_slice_buffer *slice_buffer,
+                                   uint32_t flags);
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H */
diff --git a/src/core/lib/transport/connectivity_state.c b/src/core/lib/transport/connectivity_state.c
new file mode 100644
index 0000000..123eab8
--- /dev/null
+++ b/src/core/lib/transport/connectivity_state.c
@@ -0,0 +1,164 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/transport/connectivity_state.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+int grpc_connectivity_state_trace = 0;
+
+const char *grpc_connectivity_state_name(grpc_connectivity_state state) {
+  switch (state) {
+    case GRPC_CHANNEL_IDLE:
+      return "IDLE";
+    case GRPC_CHANNEL_CONNECTING:
+      return "CONNECTING";
+    case GRPC_CHANNEL_READY:
+      return "READY";
+    case GRPC_CHANNEL_TRANSIENT_FAILURE:
+      return "TRANSIENT_FAILURE";
+    case GRPC_CHANNEL_FATAL_FAILURE:
+      return "FATAL_FAILURE";
+  }
+  GPR_UNREACHABLE_CODE(return "UNKNOWN");
+}
+
+void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
+                                  grpc_connectivity_state init_state,
+                                  const char *name) {
+  tracker->current_state = init_state;
+  tracker->watchers = NULL;
+  tracker->name = gpr_strdup(name);
+}
+
+void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx,
+                                     grpc_connectivity_state_tracker *tracker) {
+  int success;
+  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;
+      success = 1;
+    } else {
+      success = 0;
+    }
+    grpc_exec_ctx_enqueue(exec_ctx, w->notify, success, NULL);
+    gpr_free(w);
+  }
+  gpr_free(tracker->name);
+}
+
+grpc_connectivity_state grpc_connectivity_state_check(
+    grpc_connectivity_state_tracker *tracker) {
+  if (grpc_connectivity_state_trace) {
+    gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
+            grpc_connectivity_state_name(tracker->current_state));
+  }
+  return tracker->current_state;
+}
+
+int grpc_connectivity_state_notify_on_state_change(
+    grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
+    grpc_connectivity_state *current, grpc_closure *notify) {
+  if (grpc_connectivity_state_trace) {
+    if (current == NULL) {
+      gpr_log(GPR_DEBUG, "CONWATCH: %p %s: unsubscribe notify=%p", tracker,
+              tracker->name, notify);
+    } else {
+      gpr_log(GPR_DEBUG, "CONWATCH: %p %s: from %s [cur=%s] notify=%p", tracker,
+              tracker->name, grpc_connectivity_state_name(*current),
+              grpc_connectivity_state_name(tracker->current_state), notify);
+    }
+  }
+  if (current == NULL) {
+    grpc_connectivity_state_watcher *w = tracker->watchers;
+    if (w != NULL && w->notify == notify) {
+      grpc_exec_ctx_enqueue(exec_ctx, notify, false, NULL);
+      tracker->watchers = w->next;
+      gpr_free(w);
+      return 0;
+    }
+    while (w != NULL) {
+      grpc_connectivity_state_watcher *rm_candidate = w->next;
+      if (rm_candidate != NULL && rm_candidate->notify == notify) {
+        grpc_exec_ctx_enqueue(exec_ctx, notify, false, NULL);
+        w->next = w->next->next;
+        gpr_free(rm_candidate);
+        return 0;
+      }
+      w = w->next;
+    }
+    return 0;
+  } else {
+    if (tracker->current_state != *current) {
+      *current = tracker->current_state;
+      grpc_exec_ctx_enqueue(exec_ctx, notify, true, NULL);
+    } 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(grpc_exec_ctx *exec_ctx,
+                                 grpc_connectivity_state_tracker *tracker,
+                                 grpc_connectivity_state state,
+                                 const char *reason) {
+  grpc_connectivity_state_watcher *w;
+  if (grpc_connectivity_state_trace) {
+    gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s]", tracker, tracker->name,
+            grpc_connectivity_state_name(tracker->current_state),
+            grpc_connectivity_state_name(state), reason);
+  }
+  if (tracker->current_state == state) {
+    return;
+  }
+  GPR_ASSERT(tracker->current_state != GRPC_CHANNEL_FATAL_FAILURE);
+  tracker->current_state = state;
+  while ((w = tracker->watchers) != NULL) {
+    *w->current = tracker->current_state;
+    tracker->watchers = w->next;
+    grpc_exec_ctx_enqueue(exec_ctx, w->notify, true, NULL);
+    gpr_free(w);
+  }
+}
diff --git a/src/core/lib/transport/connectivity_state.h b/src/core/lib/transport/connectivity_state.h
new file mode 100644
index 0000000..6f92132
--- /dev/null
+++ b/src/core/lib/transport/connectivity_state.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H
+#define GRPC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H
+
+#include <grpc/grpc.h>
+#include "src/core/lib/iomgr/exec_ctx.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_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;
+  /** a name to help debugging */
+  char *name;
+} grpc_connectivity_state_tracker;
+
+extern int grpc_connectivity_state_trace;
+
+const char *grpc_connectivity_state_name(grpc_connectivity_state state);
+
+void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
+                                  grpc_connectivity_state init_state,
+                                  const char *name);
+void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx,
+                                     grpc_connectivity_state_tracker *tracker);
+
+/** Set connectivity state; not thread safe; access must be serialized with an
+ * external lock */
+void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
+                                 grpc_connectivity_state_tracker *tracker,
+                                 grpc_connectivity_state state,
+                                 const char *reason);
+
+grpc_connectivity_state grpc_connectivity_state_check(
+    grpc_connectivity_state_tracker *tracker);
+
+/** Return 1 if the channel should start connecting, 0 otherwise.
+    If current==NULL cancel notify if it is already queued (success==0 in that
+    case) */
+int grpc_connectivity_state_notify_on_state_change(
+    grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
+    grpc_connectivity_state *current, grpc_closure *notify);
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H */
diff --git a/src/core/lib/transport/metadata.c b/src/core/lib/transport/metadata.c
new file mode 100644
index 0000000..451c8d1
--- /dev/null
+++ b/src/core/lib/transport/metadata.c
@@ -0,0 +1,698 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/transport/metadata.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <grpc/compression.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/murmur_hash.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+/* There are two kinds of mdelem and mdstr instances.
+ * Static instances are declared in static_metadata.{h,c} and
+ * are initialized by grpc_mdctx_global_init().
+ * Dynamic instances are stored in hash tables on grpc_mdctx, and are backed
+ * by internal_string and internal_element structures.
+ * Internal helper functions here-in (is_mdstr_static, is_mdelem_static) are
+ * used to determine which kind of element a pointer refers to.
+ */
+
+#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 REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s), __FILE__, __LINE__)
+#else
+#define DEBUG_ARGS
+#define FWD_DEBUG_ARGS
+#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s))
+#endif
+
+#define TABLE_IDX(hash, log2_shards, capacity) \
+  (((hash) >> (log2_shards)) % (capacity))
+#define SHARD_IDX(hash, log2_shards) ((hash) & ((1 << (log2_shards)) - 1))
+
+typedef void (*destroy_user_data_func)(void *user_data);
+
+/* Shadow structure for grpc_mdstr for non-static values */
+typedef struct internal_string {
+  /* must be byte compatible with grpc_mdstr */
+  gpr_slice slice;
+  uint32_t hash;
+
+  /* private only data */
+  gpr_atm refcnt;
+
+  uint8_t has_base64_and_huffman_encoded;
+  gpr_slice_refcount refcount;
+
+  gpr_slice base64_and_huffman;
+
+  struct internal_string *bucket_next;
+} internal_string;
+
+/* Shadow structure for grpc_mdelem for non-static elements */
+typedef struct internal_metadata {
+  /* must be byte compatible with grpc_mdelem */
+  internal_string *key;
+  internal_string *value;
+
+  /* private only data */
+  gpr_atm refcnt;
+
+  gpr_mu mu_user_data;
+  gpr_atm destroy_user_data;
+  gpr_atm user_data;
+
+  struct internal_metadata *bucket_next;
+} internal_metadata;
+
+typedef struct strtab_shard {
+  gpr_mu mu;
+  internal_string **strs;
+  size_t count;
+  size_t capacity;
+} strtab_shard;
+
+typedef struct mdtab_shard {
+  gpr_mu mu;
+  internal_metadata **elems;
+  size_t count;
+  size_t capacity;
+  size_t free;
+} mdtab_shard;
+
+#define LOG2_STRTAB_SHARD_COUNT 5
+#define LOG2_MDTAB_SHARD_COUNT 4
+#define STRTAB_SHARD_COUNT ((size_t)(1 << LOG2_STRTAB_SHARD_COUNT))
+#define MDTAB_SHARD_COUNT ((size_t)(1 << LOG2_MDTAB_SHARD_COUNT))
+
+/* hash seed: decided at initialization time */
+static uint32_t g_hash_seed;
+static int g_forced_hash_seed = 0;
+
+/* linearly probed hash tables for static element lookup */
+static grpc_mdstr *g_static_strtab[GRPC_STATIC_MDSTR_COUNT * 2];
+static grpc_mdelem *g_static_mdtab[GRPC_STATIC_MDELEM_COUNT * 2];
+static size_t g_static_strtab_maxprobe;
+static size_t g_static_mdtab_maxprobe;
+
+static strtab_shard g_strtab_shard[STRTAB_SHARD_COUNT];
+static mdtab_shard g_mdtab_shard[MDTAB_SHARD_COUNT];
+
+static void gc_mdtab(mdtab_shard *shard);
+
+void grpc_test_only_set_metadata_hash_seed(uint32_t seed) {
+  g_hash_seed = seed;
+  g_forced_hash_seed = 1;
+}
+
+void grpc_mdctx_global_init(void) {
+  size_t i, j;
+  if (!g_forced_hash_seed) {
+    g_hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
+  }
+  g_static_strtab_maxprobe = 0;
+  g_static_mdtab_maxprobe = 0;
+  /* build static tables */
+  memset(g_static_mdtab, 0, sizeof(g_static_mdtab));
+  memset(g_static_strtab, 0, sizeof(g_static_strtab));
+  for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
+    grpc_mdstr *elem = &grpc_static_mdstr_table[i];
+    const char *str = grpc_static_metadata_strings[i];
+    uint32_t hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed);
+    *(gpr_slice *)&elem->slice = gpr_slice_from_static_string(str);
+    *(uint32_t *)&elem->hash = hash;
+    for (j = 0;; j++) {
+      size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_strtab);
+      if (g_static_strtab[idx] == NULL) {
+        g_static_strtab[idx] = &grpc_static_mdstr_table[i];
+        break;
+      }
+    }
+    if (j > g_static_strtab_maxprobe) {
+      g_static_strtab_maxprobe = j;
+    }
+  }
+  for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) {
+    grpc_mdelem *elem = &grpc_static_mdelem_table[i];
+    grpc_mdstr *key =
+        &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 0]];
+    grpc_mdstr *value =
+        &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 1]];
+    uint32_t hash = GRPC_MDSTR_KV_HASH(key->hash, value->hash);
+    *(grpc_mdstr **)&elem->key = key;
+    *(grpc_mdstr **)&elem->value = value;
+    for (j = 0;; j++) {
+      size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_mdtab);
+      if (g_static_mdtab[idx] == NULL) {
+        g_static_mdtab[idx] = elem;
+        break;
+      }
+    }
+    if (j > g_static_mdtab_maxprobe) {
+      g_static_mdtab_maxprobe = j;
+    }
+  }
+  /* initialize shards */
+  for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
+    strtab_shard *shard = &g_strtab_shard[i];
+    gpr_mu_init(&shard->mu);
+    shard->count = 0;
+    shard->capacity = INITIAL_STRTAB_CAPACITY;
+    shard->strs = gpr_malloc(sizeof(*shard->strs) * shard->capacity);
+    memset(shard->strs, 0, sizeof(*shard->strs) * shard->capacity);
+  }
+  for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
+    mdtab_shard *shard = &g_mdtab_shard[i];
+    gpr_mu_init(&shard->mu);
+    shard->count = 0;
+    shard->free = 0;
+    shard->capacity = INITIAL_MDTAB_CAPACITY;
+    shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity);
+    memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity);
+  }
+}
+
+void grpc_mdctx_global_shutdown(void) {
+  size_t i;
+  for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
+    mdtab_shard *shard = &g_mdtab_shard[i];
+    gpr_mu_destroy(&shard->mu);
+    gc_mdtab(shard);
+    /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
+    if (shard->count != 0) {
+      gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked",
+              shard->count);
+      if (grpc_iomgr_abort_on_leaks()) {
+        abort();
+      }
+    }
+    gpr_free(shard->elems);
+  }
+  for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
+    strtab_shard *shard = &g_strtab_shard[i];
+    gpr_mu_destroy(&shard->mu);
+    /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
+    if (shard->count != 0) {
+      gpr_log(GPR_DEBUG, "WARNING: %d metadata strings were leaked",
+              shard->count);
+      if (grpc_iomgr_abort_on_leaks()) {
+        abort();
+      }
+    }
+    gpr_free(shard->strs);
+  }
+}
+
+static int is_mdstr_static(grpc_mdstr *s) {
+  return s >= &grpc_static_mdstr_table[0] &&
+         s < &grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
+}
+
+static int is_mdelem_static(grpc_mdelem *e) {
+  return e >= &grpc_static_mdelem_table[0] &&
+         e < &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
+}
+
+static void ref_md_locked(mdtab_shard *shard,
+                          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, 2)) {
+    shard->free--;
+  } else {
+    GPR_ASSERT(1 != gpr_atm_no_barrier_fetch_add(&md->refcnt, -1));
+  }
+}
+
+static void grow_strtab(strtab_shard *shard) {
+  size_t capacity = shard->capacity * 2;
+  size_t i;
+  internal_string **strtab;
+  internal_string *s, *next;
+
+  GPR_TIMER_BEGIN("grow_strtab", 0);
+
+  strtab = gpr_malloc(sizeof(internal_string *) * capacity);
+  memset(strtab, 0, sizeof(internal_string *) * capacity);
+
+  for (i = 0; i < shard->capacity; i++) {
+    for (s = shard->strs[i]; s; s = next) {
+      size_t idx = TABLE_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT, capacity);
+      next = s->bucket_next;
+      s->bucket_next = strtab[idx];
+      strtab[idx] = s;
+    }
+  }
+
+  gpr_free(shard->strs);
+  shard->strs = strtab;
+  shard->capacity = capacity;
+
+  GPR_TIMER_END("grow_strtab", 0);
+}
+
+static void internal_destroy_string(strtab_shard *shard, internal_string *is) {
+  internal_string **prev_next;
+  internal_string *cur;
+  GPR_TIMER_BEGIN("internal_destroy_string", 0);
+  if (is->has_base64_and_huffman_encoded) {
+    gpr_slice_unref(is->base64_and_huffman);
+  }
+  for (prev_next = &shard->strs[TABLE_IDX(is->hash, LOG2_STRTAB_SHARD_COUNT,
+                                          shard->capacity)],
+      cur = *prev_next;
+       cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next)
+    ;
+  *prev_next = cur->bucket_next;
+  shard->count--;
+  gpr_free(is);
+  GPR_TIMER_END("internal_destroy_string", 0);
+}
+
+static void slice_ref(void *p) {
+  internal_string *is =
+      (internal_string *)((char *)p - offsetof(internal_string, refcount));
+  GRPC_MDSTR_REF((grpc_mdstr *)(is));
+}
+
+static void slice_unref(void *p) {
+  internal_string *is =
+      (internal_string *)((char *)p - offsetof(internal_string, refcount));
+  GRPC_MDSTR_UNREF((grpc_mdstr *)(is));
+}
+
+grpc_mdstr *grpc_mdstr_from_string(const char *str) {
+  return grpc_mdstr_from_buffer((const uint8_t *)str, strlen(str));
+}
+
+grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice) {
+  grpc_mdstr *result = grpc_mdstr_from_buffer(GPR_SLICE_START_PTR(slice),
+                                              GPR_SLICE_LENGTH(slice));
+  gpr_slice_unref(slice);
+  return result;
+}
+
+grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *buf, size_t length) {
+  uint32_t hash = gpr_murmur_hash3(buf, length, g_hash_seed);
+  internal_string *s;
+  strtab_shard *shard =
+      &g_strtab_shard[SHARD_IDX(hash, LOG2_STRTAB_SHARD_COUNT)];
+  size_t i;
+  size_t idx;
+
+  GPR_TIMER_BEGIN("grpc_mdstr_from_buffer", 0);
+
+  /* search for a static string */
+  for (i = 0; i <= g_static_strtab_maxprobe; i++) {
+    grpc_mdstr *ss;
+    idx = (hash + i) % GPR_ARRAY_SIZE(g_static_strtab);
+    ss = g_static_strtab[idx];
+    if (ss == NULL) break;
+    if (ss->hash == hash && GPR_SLICE_LENGTH(ss->slice) == length &&
+        0 == memcmp(buf, GPR_SLICE_START_PTR(ss->slice), length)) {
+      GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
+      return ss;
+    }
+  }
+
+  gpr_mu_lock(&shard->mu);
+
+  /* search for an existing string */
+  idx = TABLE_IDX(hash, LOG2_STRTAB_SHARD_COUNT, shard->capacity);
+  for (s = shard->strs[idx]; 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)) {
+      GRPC_MDSTR_REF((grpc_mdstr *)s);
+      gpr_mu_unlock(&shard->mu);
+      GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
+      return (grpc_mdstr *)s;
+    }
+  }
+
+  /* not found: create a new string */
+  if (length + 1 < GPR_SLICE_INLINED_SIZE) {
+    /* string data goes directly into the slice */
+    s = gpr_malloc(sizeof(internal_string));
+    gpr_atm_rel_store(&s->refcnt, 2);
+    s->slice.refcount = NULL;
+    memcpy(s->slice.data.inlined.bytes, buf, length);
+    s->slice.data.inlined.bytes[length] = 0;
+    s->slice.data.inlined.length = (uint8_t)length;
+  } else {
+    /* string data goes after the internal_string header, and we +1 for null
+       terminator */
+    s = gpr_malloc(sizeof(internal_string) + length + 1);
+    gpr_atm_rel_store(&s->refcnt, 2);
+    s->refcount.ref = slice_ref;
+    s->refcount.unref = slice_unref;
+    s->slice.refcount = &s->refcount;
+    s->slice.data.refcounted.bytes = (uint8_t *)(s + 1);
+    s->slice.data.refcounted.length = length;
+    memcpy(s->slice.data.refcounted.bytes, buf, length);
+    /* add a null terminator for cheap c string conversion when desired */
+    s->slice.data.refcounted.bytes[length] = 0;
+  }
+  s->has_base64_and_huffman_encoded = 0;
+  s->hash = hash;
+  s->bucket_next = shard->strs[idx];
+  shard->strs[idx] = s;
+
+  shard->count++;
+
+  if (shard->count > shard->capacity * 2) {
+    grow_strtab(shard);
+  }
+
+  gpr_mu_unlock(&shard->mu);
+  GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
+
+  return (grpc_mdstr *)s;
+}
+
+static void gc_mdtab(mdtab_shard *shard) {
+  size_t i;
+  internal_metadata **prev_next;
+  internal_metadata *md, *next;
+
+  GPR_TIMER_BEGIN("gc_mdtab", 0);
+  for (i = 0; i < shard->capacity; i++) {
+    prev_next = &shard->elems[i];
+    for (md = shard->elems[i]; md; md = next) {
+      void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data);
+      next = md->bucket_next;
+      if (gpr_atm_acq_load(&md->refcnt) == 0) {
+        GRPC_MDSTR_UNREF((grpc_mdstr *)md->key);
+        GRPC_MDSTR_UNREF((grpc_mdstr *)md->value);
+        if (md->user_data) {
+          ((destroy_user_data_func)gpr_atm_no_barrier_load(
+              &md->destroy_user_data))(user_data);
+        }
+        gpr_free(md);
+        *prev_next = next;
+        shard->free--;
+        shard->count--;
+      } else {
+        prev_next = &md->bucket_next;
+      }
+    }
+  }
+  GPR_TIMER_END("gc_mdtab", 0);
+}
+
+static void grow_mdtab(mdtab_shard *shard) {
+  size_t capacity = shard->capacity * 2;
+  size_t i;
+  internal_metadata **mdtab;
+  internal_metadata *md, *next;
+  uint32_t hash;
+
+  GPR_TIMER_BEGIN("grow_mdtab", 0);
+
+  mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity);
+  memset(mdtab, 0, sizeof(internal_metadata *) * capacity);
+
+  for (i = 0; i < shard->capacity; i++) {
+    for (md = shard->elems[i]; md; md = next) {
+      size_t idx;
+      hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
+      next = md->bucket_next;
+      idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, capacity);
+      md->bucket_next = mdtab[idx];
+      mdtab[idx] = md;
+    }
+  }
+
+  gpr_free(shard->elems);
+  shard->elems = mdtab;
+  shard->capacity = capacity;
+
+  GPR_TIMER_END("grow_mdtab", 0);
+}
+
+static void rehash_mdtab(mdtab_shard *shard) {
+  if (shard->free > shard->capacity / 4) {
+    gc_mdtab(shard);
+  } else {
+    grow_mdtab(shard);
+  }
+}
+
+grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *mkey,
+                                               grpc_mdstr *mvalue) {
+  internal_string *key = (internal_string *)mkey;
+  internal_string *value = (internal_string *)mvalue;
+  uint32_t hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash);
+  internal_metadata *md;
+  mdtab_shard *shard = &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
+  size_t i;
+  size_t idx;
+
+  GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0);
+
+  if (is_mdstr_static(mkey) && is_mdstr_static(mvalue)) {
+    for (i = 0; i <= g_static_mdtab_maxprobe; i++) {
+      grpc_mdelem *smd;
+      idx = (hash + i) % GPR_ARRAY_SIZE(g_static_mdtab);
+      smd = g_static_mdtab[idx];
+      if (smd == NULL) break;
+      if (smd->key == mkey && smd->value == mvalue) {
+        GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
+        return smd;
+      }
+    }
+  }
+
+  gpr_mu_lock(&shard->mu);
+
+  idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, shard->capacity);
+  /* search for an existing pair */
+  for (md = shard->elems[idx]; md; md = md->bucket_next) {
+    if (md->key == key && md->value == value) {
+      REF_MD_LOCKED(shard, md);
+      GRPC_MDSTR_UNREF((grpc_mdstr *)key);
+      GRPC_MDSTR_UNREF((grpc_mdstr *)value);
+      gpr_mu_unlock(&shard->mu);
+      GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
+      return (grpc_mdelem *)md;
+    }
+  }
+
+  /* not found: create a new pair */
+  md = gpr_malloc(sizeof(internal_metadata));
+  gpr_atm_rel_store(&md->refcnt, 2);
+  md->key = key;
+  md->value = value;
+  md->user_data = 0;
+  md->destroy_user_data = 0;
+  md->bucket_next = shard->elems[idx];
+  shard->elems[idx] = md;
+  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
+  shard->count++;
+
+  if (shard->count > shard->capacity * 2) {
+    rehash_mdtab(shard);
+  }
+
+  gpr_mu_unlock(&shard->mu);
+
+  GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
+
+  return (grpc_mdelem *)md;
+}
+
+grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value) {
+  return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_string(key),
+                                           grpc_mdstr_from_string(value));
+}
+
+grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value) {
+  return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_slice(key),
+                                           grpc_mdstr_from_slice(value));
+}
+
+grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
+                                                const uint8_t *value,
+                                                size_t value_length) {
+  return grpc_mdelem_from_metadata_strings(
+      grpc_mdstr_from_string(key), grpc_mdstr_from_buffer(value, value_length));
+}
+
+grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
+  internal_metadata *md = (internal_metadata *)gmd;
+  if (is_mdelem_static(gmd)) return 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 */
+  /* use C assert to have this removed in opt builds */
+  assert(gpr_atm_no_barrier_load(&md->refcnt) >= 2);
+  gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
+  return gmd;
+}
+
+void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
+  internal_metadata *md = (internal_metadata *)gmd;
+  if (!md) return;
+  if (is_mdelem_static(gmd)) return;
+#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
+  if (2 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
+    uint32_t hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
+    mdtab_shard *shard =
+        &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
+    GPR_TIMER_BEGIN("grpc_mdelem_unref.to_zero", 0);
+    gpr_mu_lock(&shard->mu);
+    if (1 == gpr_atm_no_barrier_load(&md->refcnt)) {
+      shard->free++;
+      gpr_atm_no_barrier_store(&md->refcnt, 0);
+    }
+    gpr_mu_unlock(&shard->mu);
+    GPR_TIMER_END("grpc_mdelem_unref.to_zero", 0);
+  }
+}
+
+const char *grpc_mdstr_as_c_string(grpc_mdstr *s) {
+  return (const char *)GPR_SLICE_START_PTR(s->slice);
+}
+
+grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
+  internal_string *s = (internal_string *)gs;
+  if (is_mdstr_static(gs)) return gs;
+  GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) != 0);
+  return gs;
+}
+
+void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
+  internal_string *s = (internal_string *)gs;
+  if (is_mdstr_static(gs)) return;
+  if (2 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
+    strtab_shard *shard =
+        &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
+    gpr_mu_lock(&shard->mu);
+    if (1 == gpr_atm_no_barrier_load(&s->refcnt)) {
+      internal_destroy_string(shard, s);
+    }
+    gpr_mu_unlock(&shard->mu);
+  }
+}
+
+void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) {
+  internal_metadata *im = (internal_metadata *)md;
+  void *result;
+  if (is_mdelem_static(md)) {
+    return (void *)grpc_static_mdelem_user_data[md - grpc_static_mdelem_table];
+  }
+  if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) {
+    return (void *)gpr_atm_no_barrier_load(&im->user_data);
+  } else {
+    return NULL;
+  }
+  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(!is_mdelem_static(md));
+  GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
+  gpr_mu_lock(&im->mu_user_data);
+  if (gpr_atm_no_barrier_load(&im->destroy_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;
+  }
+  gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data);
+  gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func);
+  gpr_mu_unlock(&im->mu_user_data);
+}
+
+gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
+  internal_string *s = (internal_string *)gs;
+  gpr_slice slice;
+  strtab_shard *shard =
+      &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
+  gpr_mu_lock(&shard->mu);
+  if (!s->has_base64_and_huffman_encoded) {
+    s->base64_and_huffman =
+        grpc_chttp2_base64_encode_and_huffman_compress(s->slice);
+    s->has_base64_and_huffman_encoded = 1;
+  }
+  slice = s->base64_and_huffman;
+  gpr_mu_unlock(&shard->mu);
+  return slice;
+}
diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h
new file mode 100644
index 0000000..d72ec9a
--- /dev/null
+++ b/src/core/lib/transport/metadata.h
@@ -0,0 +1,156 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_METADATA_H
+#define GRPC_CORE_LIB_TRANSPORT_METADATA_H
+
+#include <grpc/support/slice.h>
+#include <grpc/support/useful.h>
+
+/* This file provides a mechanism for tracking metadata through the grpc stack.
+   It's not intended for consumption outside of the library.
+
+   Metadata is tracked in the context of a grpc_mdctx. For the time being there
+   is one of these per-channel, avoiding cross channel interference with memory
+   use and lock contention.
+
+   The context tracks unique strings (grpc_mdstr) and pairs of strings
+   (grpc_mdelem). Any of these objects can be checked for equality by comparing
+   their pointers. These objects are reference counted.
+
+   grpc_mdelem can additionally store a (non-NULL) user data pointer. This
+   pointer is intended to be used to cache semantic meaning of a metadata
+   element. For example, an OAuth token may cache the credentials it represents
+   and the time at which it expires in the mdelem user data.
+
+   Combining this metadata cache and the hpack compression table allows us to
+   simply lookup complete preparsed objects quickly, incurring a few atomic
+   ops per metadata element on the fast path.
+
+   grpc_mdelem instances MAY live longer than their refcount implies, and are
+   garbage collected periodically, meaning cached data can easily outlive a
+   single request.
+
+   STATIC METADATA: in static_metadata.h we declare a set of static metadata.
+   These mdelems and mdstrs are available via pre-declared code generated macros
+   and are available to code anywhere between grpc_init() and grpc_shutdown().
+   They are not refcounted, but can be passed to _ref and _unref functions
+   declared here - in which case those functions are effectively no-ops. */
+
+/* Forward declarations */
+typedef struct grpc_mdstr grpc_mdstr;
+typedef struct grpc_mdelem grpc_mdelem;
+
+/* if changing this, make identical changes in internal_string in metadata.c */
+struct grpc_mdstr {
+  const gpr_slice slice;
+  const uint32_t hash;
+  /* there is a private part to this in metadata.c */
+};
+
+/* if changing this, make identical changes in internal_metadata in
+   metadata.c */
+struct grpc_mdelem {
+  grpc_mdstr *const key;
+  grpc_mdstr *const value;
+  /* there is a private part to this in metadata.c */
+};
+
+void grpc_test_only_set_metadata_hash_seed(uint32_t seed);
+
+/* Constructors for grpc_mdstr instances; take a variety of data types that
+   clients may have handy */
+grpc_mdstr *grpc_mdstr_from_string(const char *str);
+/* Unrefs the slice. */
+grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice);
+grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *str, size_t length);
+
+/* Returns a borrowed slice from the mdstr with its contents base64 encoded
+   and huffman compressed */
+gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *str);
+
+/* Constructors for grpc_mdelem instances; take a variety of data types that
+   clients may have handy */
+grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *key,
+                                               grpc_mdstr *value);
+grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value);
+/* Unrefs the slices. */
+grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value);
+grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
+                                                const uint8_t *value,
+                                                size_t value_length);
+
+/* Mutator and accessor for grpc_mdelem user data. The destructor function
+   is used as a type tag and is checked during user_data fetch. */
+void *grpc_mdelem_get_user_data(grpc_mdelem *md,
+                                void (*if_destroy_func)(void *));
+void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
+                               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. */
+const char *grpc_mdstr_as_c_string(grpc_mdstr *s);
+
+#define GRPC_MDSTR_LENGTH(s) (GPR_SLICE_LENGTH(s->slice))
+
+int grpc_mdstr_is_legal_header(grpc_mdstr *s);
+int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s);
+int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s);
+
+#define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash))
+
+void grpc_mdctx_global_init(void);
+void grpc_mdctx_global_shutdown(void);
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_METADATA_H */
diff --git a/src/core/lib/transport/metadata_batch.c b/src/core/lib/transport/metadata_batch.c
new file mode 100644
index 0000000..bb79b8f
--- /dev/null
+++ b/src/core/lib/transport/metadata_batch.c
@@ -0,0 +1,194 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/transport/metadata_batch.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/profiling/timers.h"
+
+static void assert_valid_list(grpc_mdelem_list *list) {
+#ifndef NDEBUG
+  grpc_linked_mdelem *l;
+
+  GPR_ASSERT((list->head == NULL) == (list->tail == NULL));
+  if (!list->head) return;
+  GPR_ASSERT(list->head->prev == NULL);
+  GPR_ASSERT(list->tail->next == NULL);
+  GPR_ASSERT((list->head == list->tail) == (list->head->next == NULL));
+
+  for (l = list->head; l; l = l->next) {
+    GPR_ASSERT(l->md);
+    GPR_ASSERT((l->prev == NULL) == (l == list->head));
+    GPR_ASSERT((l->next == NULL) == (l == list->tail));
+    if (l->next) GPR_ASSERT(l->next->prev == l);
+    if (l->prev) GPR_ASSERT(l->prev->next == l);
+  }
+#endif /* NDEBUG */
+}
+
+#ifndef NDEBUG
+void grpc_metadata_batch_assert_ok(grpc_metadata_batch *batch) {
+  assert_valid_list(&batch->list);
+}
+#endif /* NDEBUG */
+
+void grpc_metadata_batch_init(grpc_metadata_batch *batch) {
+  batch->list.head = batch->list.tail = NULL;
+  batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+}
+
+void grpc_metadata_batch_destroy(grpc_metadata_batch *batch) {
+  grpc_linked_mdelem *l;
+  for (l = batch->list.head; l; l = l->next) {
+    GRPC_MDELEM_UNREF(l->md);
+  }
+}
+
+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(batch, storage);
+}
+
+static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
+  assert_valid_list(list);
+  GPR_ASSERT(storage->md);
+  storage->prev = NULL;
+  storage->next = list->head;
+  if (list->head != NULL) {
+    list->head->prev = storage;
+  } else {
+    list->tail = storage;
+  }
+  list->head = storage;
+  assert_valid_list(list);
+}
+
+void grpc_metadata_batch_link_head(grpc_metadata_batch *batch,
+                                   grpc_linked_mdelem *storage) {
+  link_head(&batch->list, storage);
+}
+
+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(batch, storage);
+}
+
+static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
+  assert_valid_list(list);
+  GPR_ASSERT(storage->md);
+  storage->prev = list->tail;
+  storage->next = NULL;
+  storage->reserved = NULL;
+  if (list->tail != NULL) {
+    list->tail->next = storage;
+  } else {
+    list->head = storage;
+  }
+  list->tail = storage;
+  assert_valid_list(list);
+}
+
+void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch,
+                                   grpc_linked_mdelem *storage) {
+  link_tail(&batch->list, storage);
+}
+
+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;
+
+  GPR_TIMER_BEGIN("grpc_metadata_batch_filter", 0);
+
+  assert_valid_list(&batch->list);
+  for (l = batch->list.head; l; l = next) {
+    grpc_mdelem *orig = l->md;
+    grpc_mdelem *filt = filter(user_data, orig);
+    next = l->next;
+    if (filt == NULL) {
+      if (l->prev) {
+        l->prev->next = l->next;
+      }
+      if (l->next) {
+        l->next->prev = l->prev;
+      }
+      if (batch->list.head == l) {
+        batch->list.head = l->next;
+      }
+      if (batch->list.tail == l) {
+        batch->list.tail = l->prev;
+      }
+      assert_valid_list(&batch->list);
+      GRPC_MDELEM_UNREF(l->md);
+    } else if (filt != orig) {
+      GRPC_MDELEM_UNREF(orig);
+      l->md = filt;
+    }
+  }
+  assert_valid_list(&batch->list);
+
+  GPR_TIMER_END("grpc_metadata_batch_filter", 0);
+}
+
+static grpc_mdelem *no_metadata_for_you(void *user_data, grpc_mdelem *elem) {
+  return NULL;
+}
+
+void grpc_metadata_batch_clear(grpc_metadata_batch *batch) {
+  batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+  grpc_metadata_batch_filter(batch, no_metadata_for_you, NULL);
+}
+
+int grpc_metadata_batch_is_empty(grpc_metadata_batch *batch) {
+  return batch->list.head == NULL &&
+         gpr_time_cmp(gpr_inf_future(batch->deadline.clock_type),
+                      batch->deadline) == 0;
+}
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
new file mode 100644
index 0000000..f1d4726
--- /dev/null
+++ b/src/core/lib/transport/metadata_batch.h
@@ -0,0 +1,125 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_METADATA_BATCH_H
+#define GRPC_CORE_LIB_TRANSPORT_METADATA_BATCH_H
+
+#include <grpc/grpc.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/time.h>
+#include "src/core/lib/transport/metadata.h"
+
+typedef struct grpc_linked_mdelem {
+  grpc_mdelem *md;
+  struct grpc_linked_mdelem *next;
+  struct grpc_linked_mdelem *prev;
+  void *reserved;
+} grpc_linked_mdelem;
+
+typedef struct grpc_mdelem_list {
+  grpc_linked_mdelem *head;
+  grpc_linked_mdelem *tail;
+} grpc_mdelem_list;
+
+typedef struct grpc_metadata_batch {
+  /** Metadata elements in this batch */
+  grpc_mdelem_list list;
+  /** 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 *batch);
+void grpc_metadata_batch_destroy(grpc_metadata_batch *batch);
+void grpc_metadata_batch_clear(grpc_metadata_batch *batch);
+int grpc_metadata_batch_is_empty(grpc_metadata_batch *batch);
+
+/** 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);
+/** 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);
+
+/** 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);
+/** 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);
+
+/** 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);
+
+#ifndef NDEBUG
+void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd);
+#else
+#define grpc_metadata_batch_assert_ok(comd) \
+  do {                                      \
+  } while (0)
+#endif
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_METADATA_BATCH_H */
diff --git a/src/core/lib/transport/static_metadata.c b/src/core/lib/transport/static_metadata.c
new file mode 100644
index 0000000..eda277b
--- /dev/null
+++ b/src/core/lib/transport/static_metadata.c
@@ -0,0 +1,160 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * WARNING: Auto-generated code.
+ *
+ * To make changes to this file, change
+ * tools/codegen/core/gen_static_metadata.py,
+ * and then re-run it.
+ *
+ * See metadata.h for an explanation of the interface here, and metadata.c for
+ * an
+ * explanation of what's going on.
+ */
+
+#include "src/core/lib/transport/static_metadata.h"
+
+grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
+
+grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
+uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 4, 8, 6, 2, 4, 8, 6, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] =
+    {11, 35, 10, 35, 12, 35, 12, 49, 13, 35, 14, 35, 15, 35, 16, 35, 17, 35,
+     19, 35, 20, 35, 21, 35, 24, 35, 25, 35, 26, 35, 27, 35, 28, 35, 29, 35,
+     30, 18, 30, 35, 31, 35, 32, 35, 36, 35, 37, 35, 38, 35, 39, 35, 42, 33,
+     42, 34, 42, 48, 42, 53, 42, 54, 42, 55, 42, 56, 43, 33, 43, 48, 43, 53,
+     46, 0,  46, 1,  46, 2,  50, 35, 57, 35, 58, 35, 59, 35, 60, 35, 61, 35,
+     62, 35, 63, 35, 64, 35, 65, 35, 66, 40, 66, 68, 67, 78, 67, 79, 69, 35,
+     70, 35, 71, 35, 72, 35, 73, 35, 74, 35, 75, 41, 75, 51, 75, 52, 76, 35,
+     77, 35, 80, 3,  80, 4,  80, 5,  80, 6,  80, 7,  80, 8,  80, 9,  81, 35,
+     82, 83, 84, 35, 85, 35, 86, 35, 87, 35, 88, 35};
+
+const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = {
+    "0",
+    "1",
+    "2",
+    "200",
+    "204",
+    "206",
+    "304",
+    "400",
+    "404",
+    "500",
+    "accept",
+    "accept-charset",
+    "accept-encoding",
+    "accept-language",
+    "accept-ranges",
+    "access-control-allow-origin",
+    "age",
+    "allow",
+    "application/grpc",
+    ":authority",
+    "authorization",
+    "cache-control",
+    "census-bin",
+    "census-binary-bin",
+    "content-disposition",
+    "content-encoding",
+    "content-language",
+    "content-length",
+    "content-location",
+    "content-range",
+    "content-type",
+    "cookie",
+    "date",
+    "deflate",
+    "deflate,gzip",
+    "",
+    "etag",
+    "expect",
+    "expires",
+    "from",
+    "GET",
+    "grpc",
+    "grpc-accept-encoding",
+    "grpc-encoding",
+    "grpc-internal-encoding-request",
+    "grpc-message",
+    "grpc-status",
+    "grpc-timeout",
+    "gzip",
+    "gzip, deflate",
+    "host",
+    "http",
+    "https",
+    "identity",
+    "identity,deflate",
+    "identity,deflate,gzip",
+    "identity,gzip",
+    "if-match",
+    "if-modified-since",
+    "if-none-match",
+    "if-range",
+    "if-unmodified-since",
+    "last-modified",
+    "link",
+    "location",
+    "max-forwards",
+    ":method",
+    ":path",
+    "POST",
+    "proxy-authenticate",
+    "proxy-authorization",
+    "range",
+    "referer",
+    "refresh",
+    "retry-after",
+    ":scheme",
+    "server",
+    "set-cookie",
+    "/",
+    "/index.html",
+    ":status",
+    "strict-transport-security",
+    "te",
+    "trailers",
+    "transfer-encoding",
+    "user-agent",
+    "vary",
+    "via",
+    "www-authenticate"};
+
+const uint8_t grpc_static_accept_encoding_metadata[8] = {0,  29, 26, 30,
+                                                         28, 32, 27, 31};
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
new file mode 100644
index 0000000..aff136a
--- /dev/null
+++ b/src/core/lib/transport/static_metadata.h
@@ -0,0 +1,408 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * WARNING: Auto-generated code.
+ *
+ * To make changes to this file, change
+ * tools/codegen/core/gen_static_metadata.py,
+ * and then re-run it.
+ *
+ * See metadata.h for an explanation of the interface here, and metadata.c for
+ * an
+ * explanation of what's going on.
+ */
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H
+#define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H
+
+#include "src/core/lib/transport/metadata.h"
+
+#define GRPC_STATIC_MDSTR_COUNT 89
+extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
+/* "0" */
+#define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0])
+/* "1" */
+#define GRPC_MDSTR_1 (&grpc_static_mdstr_table[1])
+/* "2" */
+#define GRPC_MDSTR_2 (&grpc_static_mdstr_table[2])
+/* "200" */
+#define GRPC_MDSTR_200 (&grpc_static_mdstr_table[3])
+/* "204" */
+#define GRPC_MDSTR_204 (&grpc_static_mdstr_table[4])
+/* "206" */
+#define GRPC_MDSTR_206 (&grpc_static_mdstr_table[5])
+/* "304" */
+#define GRPC_MDSTR_304 (&grpc_static_mdstr_table[6])
+/* "400" */
+#define GRPC_MDSTR_400 (&grpc_static_mdstr_table[7])
+/* "404" */
+#define GRPC_MDSTR_404 (&grpc_static_mdstr_table[8])
+/* "500" */
+#define GRPC_MDSTR_500 (&grpc_static_mdstr_table[9])
+/* "accept" */
+#define GRPC_MDSTR_ACCEPT (&grpc_static_mdstr_table[10])
+/* "accept-charset" */
+#define GRPC_MDSTR_ACCEPT_CHARSET (&grpc_static_mdstr_table[11])
+/* "accept-encoding" */
+#define GRPC_MDSTR_ACCEPT_ENCODING (&grpc_static_mdstr_table[12])
+/* "accept-language" */
+#define GRPC_MDSTR_ACCEPT_LANGUAGE (&grpc_static_mdstr_table[13])
+/* "accept-ranges" */
+#define GRPC_MDSTR_ACCEPT_RANGES (&grpc_static_mdstr_table[14])
+/* "access-control-allow-origin" */
+#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (&grpc_static_mdstr_table[15])
+/* "age" */
+#define GRPC_MDSTR_AGE (&grpc_static_mdstr_table[16])
+/* "allow" */
+#define GRPC_MDSTR_ALLOW (&grpc_static_mdstr_table[17])
+/* "application/grpc" */
+#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (&grpc_static_mdstr_table[18])
+/* ":authority" */
+#define GRPC_MDSTR_AUTHORITY (&grpc_static_mdstr_table[19])
+/* "authorization" */
+#define GRPC_MDSTR_AUTHORIZATION (&grpc_static_mdstr_table[20])
+/* "cache-control" */
+#define GRPC_MDSTR_CACHE_CONTROL (&grpc_static_mdstr_table[21])
+/* "census-bin" */
+#define GRPC_MDSTR_CENSUS_BIN (&grpc_static_mdstr_table[22])
+/* "census-binary-bin" */
+#define GRPC_MDSTR_CENSUS_BINARY_BIN (&grpc_static_mdstr_table[23])
+/* "content-disposition" */
+#define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[24])
+/* "content-encoding" */
+#define GRPC_MDSTR_CONTENT_ENCODING (&grpc_static_mdstr_table[25])
+/* "content-language" */
+#define GRPC_MDSTR_CONTENT_LANGUAGE (&grpc_static_mdstr_table[26])
+/* "content-length" */
+#define GRPC_MDSTR_CONTENT_LENGTH (&grpc_static_mdstr_table[27])
+/* "content-location" */
+#define GRPC_MDSTR_CONTENT_LOCATION (&grpc_static_mdstr_table[28])
+/* "content-range" */
+#define GRPC_MDSTR_CONTENT_RANGE (&grpc_static_mdstr_table[29])
+/* "content-type" */
+#define GRPC_MDSTR_CONTENT_TYPE (&grpc_static_mdstr_table[30])
+/* "cookie" */
+#define GRPC_MDSTR_COOKIE (&grpc_static_mdstr_table[31])
+/* "date" */
+#define GRPC_MDSTR_DATE (&grpc_static_mdstr_table[32])
+/* "deflate" */
+#define GRPC_MDSTR_DEFLATE (&grpc_static_mdstr_table[33])
+/* "deflate,gzip" */
+#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (&grpc_static_mdstr_table[34])
+/* "" */
+#define GRPC_MDSTR_EMPTY (&grpc_static_mdstr_table[35])
+/* "etag" */
+#define GRPC_MDSTR_ETAG (&grpc_static_mdstr_table[36])
+/* "expect" */
+#define GRPC_MDSTR_EXPECT (&grpc_static_mdstr_table[37])
+/* "expires" */
+#define GRPC_MDSTR_EXPIRES (&grpc_static_mdstr_table[38])
+/* "from" */
+#define GRPC_MDSTR_FROM (&grpc_static_mdstr_table[39])
+/* "GET" */
+#define GRPC_MDSTR_GET (&grpc_static_mdstr_table[40])
+/* "grpc" */
+#define GRPC_MDSTR_GRPC (&grpc_static_mdstr_table[41])
+/* "grpc-accept-encoding" */
+#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (&grpc_static_mdstr_table[42])
+/* "grpc-encoding" */
+#define GRPC_MDSTR_GRPC_ENCODING (&grpc_static_mdstr_table[43])
+/* "grpc-internal-encoding-request" */
+#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[44])
+/* "grpc-message" */
+#define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[45])
+/* "grpc-status" */
+#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[46])
+/* "grpc-timeout" */
+#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[47])
+/* "gzip" */
+#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[48])
+/* "gzip, deflate" */
+#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[49])
+/* "host" */
+#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[50])
+/* "http" */
+#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[51])
+/* "https" */
+#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[52])
+/* "identity" */
+#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[53])
+/* "identity,deflate" */
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[54])
+/* "identity,deflate,gzip" */
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
+  (&grpc_static_mdstr_table[55])
+/* "identity,gzip" */
+#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[56])
+/* "if-match" */
+#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[57])
+/* "if-modified-since" */
+#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[58])
+/* "if-none-match" */
+#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[59])
+/* "if-range" */
+#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[60])
+/* "if-unmodified-since" */
+#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[61])
+/* "last-modified" */
+#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[62])
+/* "link" */
+#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[63])
+/* "location" */
+#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[64])
+/* "max-forwards" */
+#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[65])
+/* ":method" */
+#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[66])
+/* ":path" */
+#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[67])
+/* "POST" */
+#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[68])
+/* "proxy-authenticate" */
+#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[69])
+/* "proxy-authorization" */
+#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[70])
+/* "range" */
+#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[71])
+/* "referer" */
+#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[72])
+/* "refresh" */
+#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[73])
+/* "retry-after" */
+#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[74])
+/* ":scheme" */
+#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[75])
+/* "server" */
+#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[76])
+/* "set-cookie" */
+#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[77])
+/* "/" */
+#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[78])
+/* "/index.html" */
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[79])
+/* ":status" */
+#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[80])
+/* "strict-transport-security" */
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[81])
+/* "te" */
+#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[82])
+/* "trailers" */
+#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[83])
+/* "transfer-encoding" */
+#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[84])
+/* "user-agent" */
+#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[85])
+/* "vary" */
+#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[86])
+/* "via" */
+#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[87])
+/* "www-authenticate" */
+#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[88])
+
+#define GRPC_STATIC_MDELEM_COUNT 78
+extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
+extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
+/* "accept-charset": "" */
+#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY (&grpc_static_mdelem_table[0])
+/* "accept": "" */
+#define GRPC_MDELEM_ACCEPT_EMPTY (&grpc_static_mdelem_table[1])
+/* "accept-encoding": "" */
+#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY (&grpc_static_mdelem_table[2])
+/* "accept-encoding": "gzip, deflate" */
+#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \
+  (&grpc_static_mdelem_table[3])
+/* "accept-language": "" */
+#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[4])
+/* "accept-ranges": "" */
+#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY (&grpc_static_mdelem_table[5])
+/* "access-control-allow-origin": "" */
+#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \
+  (&grpc_static_mdelem_table[6])
+/* "age": "" */
+#define GRPC_MDELEM_AGE_EMPTY (&grpc_static_mdelem_table[7])
+/* "allow": "" */
+#define GRPC_MDELEM_ALLOW_EMPTY (&grpc_static_mdelem_table[8])
+/* ":authority": "" */
+#define GRPC_MDELEM_AUTHORITY_EMPTY (&grpc_static_mdelem_table[9])
+/* "authorization": "" */
+#define GRPC_MDELEM_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[10])
+/* "cache-control": "" */
+#define GRPC_MDELEM_CACHE_CONTROL_EMPTY (&grpc_static_mdelem_table[11])
+/* "content-disposition": "" */
+#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY (&grpc_static_mdelem_table[12])
+/* "content-encoding": "" */
+#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY (&grpc_static_mdelem_table[13])
+/* "content-language": "" */
+#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[14])
+/* "content-length": "" */
+#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY (&grpc_static_mdelem_table[15])
+/* "content-location": "" */
+#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY (&grpc_static_mdelem_table[16])
+/* "content-range": "" */
+#define GRPC_MDELEM_CONTENT_RANGE_EMPTY (&grpc_static_mdelem_table[17])
+/* "content-type": "application/grpc" */
+#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
+  (&grpc_static_mdelem_table[18])
+/* "content-type": "" */
+#define GRPC_MDELEM_CONTENT_TYPE_EMPTY (&grpc_static_mdelem_table[19])
+/* "cookie": "" */
+#define GRPC_MDELEM_COOKIE_EMPTY (&grpc_static_mdelem_table[20])
+/* "date": "" */
+#define GRPC_MDELEM_DATE_EMPTY (&grpc_static_mdelem_table[21])
+/* "etag": "" */
+#define GRPC_MDELEM_ETAG_EMPTY (&grpc_static_mdelem_table[22])
+/* "expect": "" */
+#define GRPC_MDELEM_EXPECT_EMPTY (&grpc_static_mdelem_table[23])
+/* "expires": "" */
+#define GRPC_MDELEM_EXPIRES_EMPTY (&grpc_static_mdelem_table[24])
+/* "from": "" */
+#define GRPC_MDELEM_FROM_EMPTY (&grpc_static_mdelem_table[25])
+/* "grpc-accept-encoding": "deflate" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE (&grpc_static_mdelem_table[26])
+/* "grpc-accept-encoding": "deflate,gzip" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \
+  (&grpc_static_mdelem_table[27])
+/* "grpc-accept-encoding": "gzip" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP (&grpc_static_mdelem_table[28])
+/* "grpc-accept-encoding": "identity" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
+  (&grpc_static_mdelem_table[29])
+/* "grpc-accept-encoding": "identity,deflate" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \
+  (&grpc_static_mdelem_table[30])
+/* "grpc-accept-encoding": "identity,deflate,gzip" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
+  (&grpc_static_mdelem_table[31])
+/* "grpc-accept-encoding": "identity,gzip" */
+#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
+  (&grpc_static_mdelem_table[32])
+/* "grpc-encoding": "deflate" */
+#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE (&grpc_static_mdelem_table[33])
+/* "grpc-encoding": "gzip" */
+#define GRPC_MDELEM_GRPC_ENCODING_GZIP (&grpc_static_mdelem_table[34])
+/* "grpc-encoding": "identity" */
+#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY (&grpc_static_mdelem_table[35])
+/* "grpc-status": "0" */
+#define GRPC_MDELEM_GRPC_STATUS_0 (&grpc_static_mdelem_table[36])
+/* "grpc-status": "1" */
+#define GRPC_MDELEM_GRPC_STATUS_1 (&grpc_static_mdelem_table[37])
+/* "grpc-status": "2" */
+#define GRPC_MDELEM_GRPC_STATUS_2 (&grpc_static_mdelem_table[38])
+/* "host": "" */
+#define GRPC_MDELEM_HOST_EMPTY (&grpc_static_mdelem_table[39])
+/* "if-match": "" */
+#define GRPC_MDELEM_IF_MATCH_EMPTY (&grpc_static_mdelem_table[40])
+/* "if-modified-since": "" */
+#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[41])
+/* "if-none-match": "" */
+#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY (&grpc_static_mdelem_table[42])
+/* "if-range": "" */
+#define GRPC_MDELEM_IF_RANGE_EMPTY (&grpc_static_mdelem_table[43])
+/* "if-unmodified-since": "" */
+#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[44])
+/* "last-modified": "" */
+#define GRPC_MDELEM_LAST_MODIFIED_EMPTY (&grpc_static_mdelem_table[45])
+/* "link": "" */
+#define GRPC_MDELEM_LINK_EMPTY (&grpc_static_mdelem_table[46])
+/* "location": "" */
+#define GRPC_MDELEM_LOCATION_EMPTY (&grpc_static_mdelem_table[47])
+/* "max-forwards": "" */
+#define GRPC_MDELEM_MAX_FORWARDS_EMPTY (&grpc_static_mdelem_table[48])
+/* ":method": "GET" */
+#define GRPC_MDELEM_METHOD_GET (&grpc_static_mdelem_table[49])
+/* ":method": "POST" */
+#define GRPC_MDELEM_METHOD_POST (&grpc_static_mdelem_table[50])
+/* ":path": "/" */
+#define GRPC_MDELEM_PATH_SLASH (&grpc_static_mdelem_table[51])
+/* ":path": "/index.html" */
+#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (&grpc_static_mdelem_table[52])
+/* "proxy-authenticate": "" */
+#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[53])
+/* "proxy-authorization": "" */
+#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[54])
+/* "range": "" */
+#define GRPC_MDELEM_RANGE_EMPTY (&grpc_static_mdelem_table[55])
+/* "referer": "" */
+#define GRPC_MDELEM_REFERER_EMPTY (&grpc_static_mdelem_table[56])
+/* "refresh": "" */
+#define GRPC_MDELEM_REFRESH_EMPTY (&grpc_static_mdelem_table[57])
+/* "retry-after": "" */
+#define GRPC_MDELEM_RETRY_AFTER_EMPTY (&grpc_static_mdelem_table[58])
+/* ":scheme": "grpc" */
+#define GRPC_MDELEM_SCHEME_GRPC (&grpc_static_mdelem_table[59])
+/* ":scheme": "http" */
+#define GRPC_MDELEM_SCHEME_HTTP (&grpc_static_mdelem_table[60])
+/* ":scheme": "https" */
+#define GRPC_MDELEM_SCHEME_HTTPS (&grpc_static_mdelem_table[61])
+/* "server": "" */
+#define GRPC_MDELEM_SERVER_EMPTY (&grpc_static_mdelem_table[62])
+/* "set-cookie": "" */
+#define GRPC_MDELEM_SET_COOKIE_EMPTY (&grpc_static_mdelem_table[63])
+/* ":status": "200" */
+#define GRPC_MDELEM_STATUS_200 (&grpc_static_mdelem_table[64])
+/* ":status": "204" */
+#define GRPC_MDELEM_STATUS_204 (&grpc_static_mdelem_table[65])
+/* ":status": "206" */
+#define GRPC_MDELEM_STATUS_206 (&grpc_static_mdelem_table[66])
+/* ":status": "304" */
+#define GRPC_MDELEM_STATUS_304 (&grpc_static_mdelem_table[67])
+/* ":status": "400" */
+#define GRPC_MDELEM_STATUS_400 (&grpc_static_mdelem_table[68])
+/* ":status": "404" */
+#define GRPC_MDELEM_STATUS_404 (&grpc_static_mdelem_table[69])
+/* ":status": "500" */
+#define GRPC_MDELEM_STATUS_500 (&grpc_static_mdelem_table[70])
+/* "strict-transport-security": "" */
+#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
+  (&grpc_static_mdelem_table[71])
+/* "te": "trailers" */
+#define GRPC_MDELEM_TE_TRAILERS (&grpc_static_mdelem_table[72])
+/* "transfer-encoding": "" */
+#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (&grpc_static_mdelem_table[73])
+/* "user-agent": "" */
+#define GRPC_MDELEM_USER_AGENT_EMPTY (&grpc_static_mdelem_table[74])
+/* "vary": "" */
+#define GRPC_MDELEM_VARY_EMPTY (&grpc_static_mdelem_table[75])
+/* "via": "" */
+#define GRPC_MDELEM_VIA_EMPTY (&grpc_static_mdelem_table[76])
+/* "www-authenticate": "" */
+#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[77])
+
+extern const uint8_t
+    grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2];
+extern const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT];
+extern const uint8_t grpc_static_accept_encoding_metadata[8];
+#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \
+  (&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]])
+#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */
diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c
new file mode 100644
index 0000000..18256aa
--- /dev/null
+++ b/src/core/lib/transport/transport.c
@@ -0,0 +1,184 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/transport/transport.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/log.h>
+#include "src/core/lib/transport/transport_impl.h"
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason) {
+  gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count);
+  gpr_log(GPR_DEBUG, "%s %p:%p   REF %d->%d %s", refcount->object_type,
+          refcount, refcount->destroy.cb_arg, val, val + 1, reason);
+#else
+void grpc_stream_ref(grpc_stream_refcount *refcount) {
+#endif
+  gpr_ref_non_zero(&refcount->refs);
+}
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount,
+                       const char *reason) {
+  gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count);
+  gpr_log(GPR_DEBUG, "%s %p:%p UNREF %d->%d %s", refcount->object_type,
+          refcount, refcount->destroy.cb_arg, val, val - 1, reason);
+#else
+void grpc_stream_unref(grpc_exec_ctx *exec_ctx,
+                       grpc_stream_refcount *refcount) {
+#endif
+  if (gpr_unref(&refcount->refs)) {
+    grpc_exec_ctx_enqueue(exec_ctx, &refcount->destroy, true, NULL);
+  }
+}
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
+                          grpc_iomgr_cb_func cb, void *cb_arg,
+                          const char *object_type) {
+  refcount->object_type = object_type;
+#else
+void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
+                          grpc_iomgr_cb_func cb, void *cb_arg) {
+#endif
+  gpr_ref_init(&refcount->refs, initial_refs);
+  grpc_closure_init(&refcount->destroy, cb, cb_arg);
+}
+
+size_t grpc_transport_stream_size(grpc_transport *transport) {
+  return transport->vtable->sizeof_stream;
+}
+
+void grpc_transport_destroy(grpc_exec_ctx *exec_ctx,
+                            grpc_transport *transport) {
+  transport->vtable->destroy(exec_ctx, transport);
+}
+
+int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx,
+                               grpc_transport *transport, grpc_stream *stream,
+                               grpc_stream_refcount *refcount,
+                               const void *server_data) {
+  return transport->vtable->init_stream(exec_ctx, transport, stream, refcount,
+                                        server_data);
+}
+
+void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx,
+                                      grpc_transport *transport,
+                                      grpc_stream *stream,
+                                      grpc_transport_stream_op *op) {
+  transport->vtable->perform_stream_op(exec_ctx, transport, stream, op);
+}
+
+void grpc_transport_perform_op(grpc_exec_ctx *exec_ctx,
+                               grpc_transport *transport,
+                               grpc_transport_op *op) {
+  transport->vtable->perform_op(exec_ctx, transport, op);
+}
+
+void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx,
+                                grpc_transport *transport, grpc_stream *stream,
+                                grpc_pollset *pollset) {
+  transport->vtable->set_pollset(exec_ctx, transport, stream, pollset);
+}
+
+void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
+                                   grpc_transport *transport,
+                                   grpc_stream *stream) {
+  transport->vtable->destroy_stream(exec_ctx, transport, stream);
+}
+
+char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
+                              grpc_transport *transport) {
+  return transport->vtable->get_peer(exec_ctx, transport);
+}
+
+void grpc_transport_stream_op_finish_with_failure(
+    grpc_exec_ctx *exec_ctx, grpc_transport_stream_op *op) {
+  grpc_exec_ctx_enqueue(exec_ctx, op->recv_message_ready, false, NULL);
+  grpc_exec_ctx_enqueue(exec_ctx, op->recv_initial_metadata_ready, false, NULL);
+  grpc_exec_ctx_enqueue(exec_ctx, op->on_complete, false, NULL);
+}
+
+void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
+                                               grpc_status_code status) {
+  GPR_ASSERT(status != GRPC_STATUS_OK);
+  if (op->cancel_with_status == GRPC_STATUS_OK) {
+    op->cancel_with_status = status;
+  }
+  if (op->close_with_status != GRPC_STATUS_OK) {
+    op->close_with_status = GRPC_STATUS_OK;
+    if (op->optional_close_message != NULL) {
+      gpr_slice_unref(*op->optional_close_message);
+      op->optional_close_message = NULL;
+    }
+  }
+}
+
+typedef struct {
+  gpr_slice message;
+  grpc_closure *then_call;
+  grpc_closure closure;
+} close_message_data;
+
+static void free_message(grpc_exec_ctx *exec_ctx, void *p, bool iomgr_success) {
+  close_message_data *cmd = p;
+  gpr_slice_unref(cmd->message);
+  if (cmd->then_call != NULL) {
+    cmd->then_call->cb(exec_ctx, cmd->then_call->cb_arg, iomgr_success);
+  }
+  gpr_free(cmd);
+}
+
+void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op,
+                                        grpc_status_code status,
+                                        gpr_slice *optional_message) {
+  close_message_data *cmd;
+  GPR_ASSERT(status != GRPC_STATUS_OK);
+  if (op->cancel_with_status != GRPC_STATUS_OK ||
+      op->close_with_status != GRPC_STATUS_OK) {
+    if (optional_message) {
+      gpr_slice_unref(*optional_message);
+    }
+    return;
+  }
+  if (optional_message) {
+    cmd = gpr_malloc(sizeof(*cmd));
+    cmd->message = *optional_message;
+    cmd->then_call = op->on_complete;
+    grpc_closure_init(&cmd->closure, free_message, cmd);
+    op->on_complete = &cmd->closure;
+    op->optional_close_message = &cmd->message;
+  }
+  op->close_with_status = status;
+}
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
new file mode 100644
index 0000000..e98cfe9
--- /dev/null
+++ b/src/core/lib/transport/transport.h
@@ -0,0 +1,242 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_TRANSPORT_H
+#define GRPC_CORE_LIB_TRANSPORT_TRANSPORT_H
+
+#include <stddef.h>
+
+#include "src/core/lib/channel/context.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/pollset_set.h"
+#include "src/core/lib/transport/byte_stream.h"
+#include "src/core/lib/transport/metadata_batch.h"
+
+/* forward declarations */
+typedef struct grpc_transport grpc_transport;
+
+/* grpc_stream doesn't actually exist. It's used as a typesafe
+   opaque pointer for whatever data the transport wants to track
+   for a stream. */
+typedef struct grpc_stream grpc_stream;
+
+/*#define GRPC_STREAM_REFCOUNT_DEBUG*/
+
+typedef struct grpc_stream_refcount {
+  gpr_refcount refs;
+  grpc_closure destroy;
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+  const char *object_type;
+#endif
+} grpc_stream_refcount;
+
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
+                          grpc_iomgr_cb_func cb, void *cb_arg,
+                          const char *object_type);
+void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason);
+void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount,
+                       const char *reason);
+#define GRPC_STREAM_REF_INIT(rc, ir, cb, cb_arg, objtype) \
+  grpc_stream_ref_init(rc, ir, cb, cb_arg, objtype)
+#else
+void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
+                          grpc_iomgr_cb_func cb, void *cb_arg);
+void grpc_stream_ref(grpc_stream_refcount *refcount);
+void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount);
+#define GRPC_STREAM_REF_INIT(rc, ir, cb, cb_arg, objtype) \
+  grpc_stream_ref_init(rc, ir, cb, cb_arg)
+#endif
+
+/* Transport stream op: a set of operations to perform on a transport
+   against a single stream */
+typedef struct grpc_transport_stream_op {
+  /** Send initial metadata to the peer, from the provided metadata batch. */
+  grpc_metadata_batch *send_initial_metadata;
+
+  /** Send trailing metadata to the peer, from the provided metadata batch. */
+  grpc_metadata_batch *send_trailing_metadata;
+
+  /** Send message data to the peer, from the provided byte stream. */
+  grpc_byte_stream *send_message;
+
+  /** Receive initial metadata from the stream, into provided metadata batch. */
+  grpc_metadata_batch *recv_initial_metadata;
+  /** Should be enqueued when initial metadata is ready to be processed. */
+  grpc_closure *recv_initial_metadata_ready;
+
+  /** Receive message data from the stream, into provided byte stream. */
+  grpc_byte_stream **recv_message;
+  /** Should be enqueued when one message is ready to be processed. */
+  grpc_closure *recv_message_ready;
+
+  /** Receive trailing metadata from the stream, into provided metadata batch.
+   */
+  grpc_metadata_batch *recv_trailing_metadata;
+
+  /** Should be enqueued when all requested operations (excluding recv_message
+      and recv_initial_metadata which have their own closures) in a given batch
+      have been completed. */
+  grpc_closure *on_complete;
+
+  /** If != GRPC_STATUS_OK, cancel this stream */
+  grpc_status_code cancel_with_status;
+
+  /** If != GRPC_STATUS_OK, send grpc-status, grpc-message, and close this
+      stream for both reading and writing */
+  grpc_status_code close_with_status;
+  gpr_slice *optional_close_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_closure *on_consumed;
+  /** connectivity monitoring - set connectivity_state to NULL to unsubscribe */
+  grpc_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.
+      If true, the callback is set to set_accept_stream_fn, with its
+      user_data argument set to set_accept_stream_user_data */
+  bool set_accept_stream;
+  void (*set_accept_stream_fn)(grpc_exec_ctx *exec_ctx, 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;
+  /** add this transport to a pollset_set */
+  grpc_pollset_set *bind_pollset_set;
+  /** send a ping, call this back if not NULL */
+  grpc_closure *send_ping;
+} grpc_transport_op;
+
+/* Returns the amount of memory required to store a grpc_stream for this
+   transport */
+size_t grpc_transport_stream_size(grpc_transport *transport);
+
+/* Initialize transport data for a stream.
+
+   Returns 0 on success, any other (transport-defined) value for failure.
+
+   Arguments:
+     transport   - the transport on which to create this stream
+     stream      - a pointer to uninitialized memory to initialize
+     server_data - either NULL for a client initiated stream, or a pointer
+                   supplied from the accept_stream callback function */
+int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx,
+                               grpc_transport *transport, grpc_stream *stream,
+                               grpc_stream_refcount *refcount,
+                               const void *server_data);
+
+void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx,
+                                grpc_transport *transport, grpc_stream *stream,
+                                grpc_pollset *pollset);
+
+/* Destroy transport data for a stream.
+
+   Requires: a recv_batch with final_state == GRPC_STREAM_CLOSED has been
+   received by the up-layer. Must not be called in the same call stack as
+   recv_frame.
+
+   Arguments:
+     transport - the transport on which to create this stream
+     stream    - the grpc_stream to destroy (memory is still owned by the
+                 caller, but any child memory must be cleaned up) */
+void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
+                                   grpc_transport *transport,
+                                   grpc_stream *stream);
+
+void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
+                                                  grpc_transport_stream_op *op);
+
+void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
+                                               grpc_status_code status);
+
+void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op,
+                                        grpc_status_code status,
+                                        gpr_slice *optional_message);
+
+char *grpc_transport_stream_op_string(grpc_transport_stream_op *op);
+
+/* Send a batch of operations on a transport
+
+   Takes ownership of any objects contained in ops.
+
+   Arguments:
+     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_stream_op specifying the op to perform */
+void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx,
+                                      grpc_transport *transport,
+                                      grpc_stream *stream,
+                                      grpc_transport_stream_op *op);
+
+void grpc_transport_perform_op(grpc_exec_ctx *exec_ctx,
+                               grpc_transport *transport,
+                               grpc_transport_op *op);
+
+/* Send a ping on a transport
+
+   Calls cb with user data when a response is received. */
+void grpc_transport_ping(grpc_transport *transport, grpc_closure *cb);
+
+/* Advise peer of pending connection termination. */
+void grpc_transport_goaway(grpc_transport *transport, grpc_status_code status,
+                           gpr_slice debug_data);
+
+/* Close a transport. Aborts all open streams. */
+void grpc_transport_close(grpc_transport *transport);
+
+/* Destroy the transport */
+void grpc_transport_destroy(grpc_exec_ctx *exec_ctx, grpc_transport *transport);
+
+/* Get the transports peer */
+char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
+                              grpc_transport *transport);
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_TRANSPORT_H */
diff --git a/src/core/lib/transport/transport_impl.h b/src/core/lib/transport/transport_impl.h
new file mode 100644
index 0000000..92fa5d5
--- /dev/null
+++ b/src/core/lib/transport/transport_impl.h
@@ -0,0 +1,81 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_TRANSPORT_IMPL_H
+#define GRPC_CORE_LIB_TRANSPORT_TRANSPORT_IMPL_H
+
+#include "src/core/lib/transport/transport.h"
+
+typedef struct grpc_transport_vtable {
+  /* Memory required for a single stream element - this is allocated by upper
+     layers and initialized by the transport */
+  size_t sizeof_stream; /* = sizeof(transport stream) */
+
+  /* name of this transport implementation */
+  const char *name;
+
+  /* implementation of grpc_transport_init_stream */
+  int (*init_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
+                     grpc_stream *stream, grpc_stream_refcount *refcount,
+                     const void *server_data);
+
+  /* implementation of grpc_transport_set_pollset */
+  void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
+                      grpc_stream *stream, grpc_pollset *pollset);
+
+  /* implementation of grpc_transport_perform_stream_op */
+  void (*perform_stream_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
+                            grpc_stream *stream, grpc_transport_stream_op *op);
+
+  /* implementation of grpc_transport_perform_op */
+  void (*perform_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
+                     grpc_transport_op *op);
+
+  /* implementation of grpc_transport_destroy_stream */
+  void (*destroy_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
+                         grpc_stream *stream);
+
+  /* implementation of grpc_transport_destroy */
+  void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_transport *self);
+
+  /* implementation of grpc_transport_get_peer */
+  char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_transport *self);
+} grpc_transport_vtable;
+
+/* an instance of a grpc transport */
+struct grpc_transport {
+  /* pointer to a vtable defining operations on this transport */
+  const grpc_transport_vtable *vtable;
+};
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_TRANSPORT_IMPL_H */
diff --git a/src/core/lib/transport/transport_op_string.c b/src/core/lib/transport/transport_op_string.c
new file mode 100644
index 0000000..1fa8fa5
--- /dev/null
+++ b/src/core/lib/transport/transport_op_string.c
@@ -0,0 +1,140 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/channel/channel_stack.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
+
+/* These routines are here to facilitate debugging - they produce string
+   representations of various transport data structures */
+
+static void put_metadata(gpr_strvec *b, grpc_mdelem *md) {
+  gpr_strvec_add(b, gpr_strdup("key="));
+  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_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
+}
+
+static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) {
+  grpc_linked_mdelem *m;
+  for (m = md.list.head; m != NULL; m = m->next) {
+    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(md.deadline.clock_type)) != 0) {
+    char *tmp;
+    gpr_asprintf(&tmp, " deadline=%lld.%09d", (long long)md.deadline.tv_sec,
+                 (int)md.deadline.tv_nsec);
+    gpr_strvec_add(b, tmp);
+  }
+}
+
+char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) {
+  char *tmp;
+  char *out;
+  int first = 1;
+
+  gpr_strvec b;
+  gpr_strvec_init(&b);
+
+  if (op->send_initial_metadata != NULL) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA{"));
+    put_metadata_list(&b, *op->send_initial_metadata);
+    gpr_strvec_add(&b, gpr_strdup("}"));
+  }
+
+  if (op->send_message != NULL) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d",
+                 op->send_message->flags, op->send_message->length);
+    gpr_strvec_add(&b, tmp);
+  }
+
+  if (op->send_trailing_metadata != NULL) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    gpr_strvec_add(&b, gpr_strdup("SEND_TRAILING_METADATA{"));
+    put_metadata_list(&b, *op->send_trailing_metadata);
+    gpr_strvec_add(&b, gpr_strdup("}"));
+  }
+
+  if (op->recv_initial_metadata != NULL) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    gpr_strvec_add(&b, gpr_strdup("RECV_INITIAL_METADATA"));
+  }
+
+  if (op->recv_message != NULL) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE"));
+  }
+
+  if (op->recv_trailing_metadata != NULL) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    gpr_strvec_add(&b, gpr_strdup("RECV_TRAILING_METADATA"));
+  }
+
+  if (op->cancel_with_status != GRPC_STATUS_OK) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    gpr_asprintf(&tmp, "CANCEL:%d", op->cancel_with_status);
+    gpr_strvec_add(&b, tmp);
+  }
+
+  out = gpr_strvec_flatten(&b, NULL);
+  gpr_strvec_destroy(&b);
+
+  return out;
+}
+
+void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
+                      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/lib/tsi/fake_transport_security.c b/src/core/lib/tsi/fake_transport_security.c
new file mode 100644
index 0000000..4b812f4
--- /dev/null
+++ b/src/core/lib/tsi/fake_transport_security.c
@@ -0,0 +1,527 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/tsi/fake_transport_security.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/tsi/transport_security.h"
+
+/* --- Constants. ---*/
+#define TSI_FAKE_FRAME_HEADER_SIZE 4
+#define TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE 64
+#define TSI_FAKE_DEFAULT_FRAME_SIZE 16384
+
+/* --- Structure definitions. ---*/
+
+/* a frame is encoded like this:
+   | size |     data    |
+   where the size field value is the size of the size field plus the size of
+   the data encoded in little endian on 4 bytes.  */
+typedef struct {
+  unsigned char *data;
+  size_t size;
+  size_t allocated_size;
+  size_t offset;
+  int needs_draining;
+} tsi_fake_frame;
+
+typedef enum {
+  TSI_FAKE_CLIENT_INIT = 0,
+  TSI_FAKE_SERVER_INIT = 1,
+  TSI_FAKE_CLIENT_FINISHED = 2,
+  TSI_FAKE_SERVER_FINISHED = 3,
+  TSI_FAKE_HANDSHAKE_MESSAGE_MAX = 4
+} tsi_fake_handshake_message;
+
+typedef struct {
+  tsi_handshaker base;
+  int is_client;
+  tsi_fake_handshake_message next_message_to_send;
+  int needs_incoming_message;
+  tsi_fake_frame incoming;
+  tsi_fake_frame outgoing;
+  tsi_result result;
+} tsi_fake_handshaker;
+
+typedef struct {
+  tsi_frame_protector base;
+  tsi_fake_frame protect_frame;
+  tsi_fake_frame unprotect_frame;
+  size_t max_frame_size;
+} tsi_fake_frame_protector;
+
+/* --- Utils. ---*/
+
+static const char *tsi_fake_handshake_message_strings[] = {
+    "CLIENT_INIT", "SERVER_INIT", "CLIENT_FINISHED", "SERVER_FINISHED"};
+
+static const char *tsi_fake_handshake_message_to_string(int msg) {
+  if (msg < 0 || msg >= TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
+    gpr_log(GPR_ERROR, "Invalid message %d", msg);
+    return "UNKNOWN";
+  }
+  return tsi_fake_handshake_message_strings[msg];
+}
+
+static tsi_result tsi_fake_handshake_message_from_string(
+    const char *msg_string, tsi_fake_handshake_message *msg) {
+  tsi_fake_handshake_message i;
+  for (i = 0; i < TSI_FAKE_HANDSHAKE_MESSAGE_MAX; i++) {
+    if (strncmp(msg_string, tsi_fake_handshake_message_strings[i],
+                strlen(tsi_fake_handshake_message_strings[i])) == 0) {
+      *msg = i;
+      return TSI_OK;
+    }
+  }
+  gpr_log(GPR_ERROR, "Invalid handshake message.");
+  return TSI_DATA_CORRUPTED;
+}
+
+static uint32_t load32_little_endian(const unsigned char *buf) {
+  return ((uint32_t)(buf[0]) | (uint32_t)(buf[1] << 8) |
+          (uint32_t)(buf[2] << 16) | (uint32_t)(buf[3] << 24));
+}
+
+static void store32_little_endian(uint32_t value, unsigned char *buf) {
+  buf[3] = (unsigned char)((value >> 24) & 0xFF);
+  buf[2] = (unsigned char)((value >> 16) & 0xFF);
+  buf[1] = (unsigned char)((value >> 8) & 0xFF);
+  buf[0] = (unsigned char)((value)&0xFF);
+}
+
+static void tsi_fake_frame_reset(tsi_fake_frame *frame, int needs_draining) {
+  frame->offset = 0;
+  frame->needs_draining = needs_draining;
+  if (!needs_draining) frame->size = 0;
+}
+
+/* Returns 1 if successful, 0 otherwise. */
+static int tsi_fake_frame_ensure_size(tsi_fake_frame *frame) {
+  if (frame->data == NULL) {
+    frame->allocated_size = frame->size;
+    frame->data = malloc(frame->allocated_size);
+    if (frame->data == NULL) return 0;
+  } else if (frame->size > frame->allocated_size) {
+    unsigned char *new_data = realloc(frame->data, frame->size);
+    if (new_data == NULL) {
+      free(frame->data);
+      frame->data = NULL;
+      return 0;
+    }
+    frame->data = new_data;
+    frame->allocated_size = frame->size;
+  }
+  return 1;
+}
+
+/* This method should not be called if frame->needs_framing is not 0.  */
+static tsi_result fill_frame_from_bytes(const unsigned char *incoming_bytes,
+                                        size_t *incoming_bytes_size,
+                                        tsi_fake_frame *frame) {
+  size_t available_size = *incoming_bytes_size;
+  size_t to_read_size = 0;
+  const unsigned char *bytes_cursor = incoming_bytes;
+
+  if (frame->needs_draining) return TSI_INTERNAL_ERROR;
+  if (frame->data == NULL) {
+    frame->allocated_size = TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE;
+    frame->data = malloc(frame->allocated_size);
+    if (frame->data == NULL) return TSI_OUT_OF_RESOURCES;
+  }
+
+  if (frame->offset < TSI_FAKE_FRAME_HEADER_SIZE) {
+    to_read_size = TSI_FAKE_FRAME_HEADER_SIZE - frame->offset;
+    if (to_read_size > available_size) {
+      /* Just fill what we can and exit. */
+      memcpy(frame->data + frame->offset, bytes_cursor, available_size);
+      bytes_cursor += available_size;
+      frame->offset += available_size;
+      *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes);
+      return TSI_INCOMPLETE_DATA;
+    }
+    memcpy(frame->data + frame->offset, bytes_cursor, to_read_size);
+    bytes_cursor += to_read_size;
+    frame->offset += to_read_size;
+    available_size -= to_read_size;
+    frame->size = load32_little_endian(frame->data);
+    if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES;
+  }
+
+  to_read_size = frame->size - frame->offset;
+  if (to_read_size > available_size) {
+    memcpy(frame->data + frame->offset, bytes_cursor, available_size);
+    frame->offset += available_size;
+    bytes_cursor += available_size;
+    *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes);
+    return TSI_INCOMPLETE_DATA;
+  }
+  memcpy(frame->data + frame->offset, bytes_cursor, to_read_size);
+  bytes_cursor += to_read_size;
+  *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes);
+  tsi_fake_frame_reset(frame, 1 /* needs_draining */);
+  return TSI_OK;
+}
+
+/* This method should not be called if frame->needs_framing is 0.  */
+static tsi_result drain_frame_to_bytes(unsigned char *outgoing_bytes,
+                                       size_t *outgoing_bytes_size,
+                                       tsi_fake_frame *frame) {
+  size_t to_write_size = frame->size - frame->offset;
+  if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
+  if (*outgoing_bytes_size < to_write_size) {
+    memcpy(outgoing_bytes, frame->data + frame->offset, *outgoing_bytes_size);
+    frame->offset += *outgoing_bytes_size;
+    return TSI_INCOMPLETE_DATA;
+  }
+  memcpy(outgoing_bytes, frame->data + frame->offset, to_write_size);
+  *outgoing_bytes_size = to_write_size;
+  tsi_fake_frame_reset(frame, 0 /* needs_draining */);
+  return TSI_OK;
+}
+
+static tsi_result bytes_to_frame(unsigned char *bytes, size_t bytes_size,
+                                 tsi_fake_frame *frame) {
+  frame->offset = 0;
+  frame->size = bytes_size + TSI_FAKE_FRAME_HEADER_SIZE;
+  if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES;
+  store32_little_endian((uint32_t)frame->size, frame->data);
+  memcpy(frame->data + TSI_FAKE_FRAME_HEADER_SIZE, bytes, bytes_size);
+  tsi_fake_frame_reset(frame, 1 /* needs draining */);
+  return TSI_OK;
+}
+
+static void tsi_fake_frame_destruct(tsi_fake_frame *frame) {
+  if (frame->data != NULL) free(frame->data);
+}
+
+/* --- tsi_frame_protector methods implementation. ---*/
+
+static tsi_result fake_protector_protect(tsi_frame_protector *self,
+                                         const unsigned char *unprotected_bytes,
+                                         size_t *unprotected_bytes_size,
+                                         unsigned char *protected_output_frames,
+                                         size_t *protected_output_frames_size) {
+  tsi_result result = TSI_OK;
+  tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
+  unsigned char frame_header[TSI_FAKE_FRAME_HEADER_SIZE];
+  tsi_fake_frame *frame = &impl->protect_frame;
+  size_t saved_output_size = *protected_output_frames_size;
+  size_t drained_size = 0;
+  size_t *num_bytes_written = protected_output_frames_size;
+  *num_bytes_written = 0;
+
+  /* Try to drain first. */
+  if (frame->needs_draining) {
+    drained_size = saved_output_size - *num_bytes_written;
+    result =
+        drain_frame_to_bytes(protected_output_frames, &drained_size, frame);
+    *num_bytes_written += drained_size;
+    protected_output_frames += drained_size;
+    if (result != TSI_OK) {
+      if (result == TSI_INCOMPLETE_DATA) {
+        *unprotected_bytes_size = 0;
+        result = TSI_OK;
+      }
+      return result;
+    }
+  }
+
+  /* Now process the unprotected_bytes. */
+  if (frame->needs_draining) return TSI_INTERNAL_ERROR;
+  if (frame->size == 0) {
+    /* New frame, create a header. */
+    size_t written_in_frame_size = 0;
+    store32_little_endian((uint32_t)impl->max_frame_size, frame_header);
+    written_in_frame_size = TSI_FAKE_FRAME_HEADER_SIZE;
+    result = fill_frame_from_bytes(frame_header, &written_in_frame_size, frame);
+    if (result != TSI_INCOMPLETE_DATA) {
+      gpr_log(GPR_ERROR, "fill_frame_from_bytes returned %s",
+              tsi_result_to_string(result));
+      return result;
+    }
+  }
+  result =
+      fill_frame_from_bytes(unprotected_bytes, unprotected_bytes_size, frame);
+  if (result != TSI_OK) {
+    if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
+    return result;
+  }
+
+  /* Try to drain again. */
+  if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
+  if (frame->offset != 0) return TSI_INTERNAL_ERROR;
+  drained_size = saved_output_size - *num_bytes_written;
+  result = drain_frame_to_bytes(protected_output_frames, &drained_size, frame);
+  *num_bytes_written += drained_size;
+  if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
+  return result;
+}
+
+static tsi_result fake_protector_protect_flush(
+    tsi_frame_protector *self, unsigned char *protected_output_frames,
+    size_t *protected_output_frames_size, size_t *still_pending_size) {
+  tsi_result result = TSI_OK;
+  tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
+  tsi_fake_frame *frame = &impl->protect_frame;
+  if (!frame->needs_draining) {
+    /* Create a short frame. */
+    frame->size = frame->offset;
+    frame->offset = 0;
+    frame->needs_draining = 1;
+    store32_little_endian((uint32_t)frame->size,
+                          frame->data); /* Overwrite header. */
+  }
+  result = drain_frame_to_bytes(protected_output_frames,
+                                protected_output_frames_size, frame);
+  if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
+  *still_pending_size = frame->size - frame->offset;
+  return result;
+}
+
+static tsi_result fake_protector_unprotect(
+    tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
+    size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
+    size_t *unprotected_bytes_size) {
+  tsi_result result = TSI_OK;
+  tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
+  tsi_fake_frame *frame = &impl->unprotect_frame;
+  size_t saved_output_size = *unprotected_bytes_size;
+  size_t drained_size = 0;
+  size_t *num_bytes_written = unprotected_bytes_size;
+  *num_bytes_written = 0;
+
+  /* Try to drain first. */
+  if (frame->needs_draining) {
+    /* Go past the header if needed. */
+    if (frame->offset == 0) frame->offset = TSI_FAKE_FRAME_HEADER_SIZE;
+    drained_size = saved_output_size - *num_bytes_written;
+    result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame);
+    unprotected_bytes += drained_size;
+    *num_bytes_written += drained_size;
+    if (result != TSI_OK) {
+      if (result == TSI_INCOMPLETE_DATA) {
+        *protected_frames_bytes_size = 0;
+        result = TSI_OK;
+      }
+      return result;
+    }
+  }
+
+  /* Now process the protected_bytes. */
+  if (frame->needs_draining) return TSI_INTERNAL_ERROR;
+  result = fill_frame_from_bytes(protected_frames_bytes,
+                                 protected_frames_bytes_size, frame);
+  if (result != TSI_OK) {
+    if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
+    return result;
+  }
+
+  /* Try to drain again. */
+  if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
+  if (frame->offset != 0) return TSI_INTERNAL_ERROR;
+  frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; /* Go past the header. */
+  drained_size = saved_output_size - *num_bytes_written;
+  result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame);
+  *num_bytes_written += drained_size;
+  if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
+  return result;
+}
+
+static void fake_protector_destroy(tsi_frame_protector *self) {
+  tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
+  tsi_fake_frame_destruct(&impl->protect_frame);
+  tsi_fake_frame_destruct(&impl->unprotect_frame);
+  free(self);
+}
+
+static const tsi_frame_protector_vtable frame_protector_vtable = {
+    fake_protector_protect, fake_protector_protect_flush,
+    fake_protector_unprotect, fake_protector_destroy,
+};
+
+/* --- tsi_handshaker methods implementation. ---*/
+
+static tsi_result fake_handshaker_get_bytes_to_send_to_peer(
+    tsi_handshaker *self, unsigned char *bytes, size_t *bytes_size) {
+  tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
+  tsi_result result = TSI_OK;
+  if (impl->needs_incoming_message || impl->result == TSI_OK) {
+    *bytes_size = 0;
+    return TSI_OK;
+  }
+  if (!impl->outgoing.needs_draining) {
+    tsi_fake_handshake_message next_message_to_send =
+        impl->next_message_to_send + 2;
+    const char *msg_string =
+        tsi_fake_handshake_message_to_string(impl->next_message_to_send);
+    result = bytes_to_frame((unsigned char *)msg_string, strlen(msg_string),
+                            &impl->outgoing);
+    if (result != TSI_OK) return result;
+    if (next_message_to_send > TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
+      next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX;
+    }
+    if (tsi_tracing_enabled) {
+      gpr_log(GPR_INFO, "%s prepared %s.",
+              impl->is_client ? "Client" : "Server",
+              tsi_fake_handshake_message_to_string(impl->next_message_to_send));
+    }
+    impl->next_message_to_send = next_message_to_send;
+  }
+  result = drain_frame_to_bytes(bytes, bytes_size, &impl->outgoing);
+  if (result != TSI_OK) return result;
+  if (!impl->is_client &&
+      impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
+    /* We're done. */
+    if (tsi_tracing_enabled) {
+      gpr_log(GPR_INFO, "Server is done.");
+    }
+    impl->result = TSI_OK;
+  } else {
+    impl->needs_incoming_message = 1;
+  }
+  return TSI_OK;
+}
+
+static tsi_result fake_handshaker_process_bytes_from_peer(
+    tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) {
+  tsi_result result = TSI_OK;
+  tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
+  tsi_fake_handshake_message expected_msg = impl->next_message_to_send - 1;
+  tsi_fake_handshake_message received_msg;
+
+  if (!impl->needs_incoming_message || impl->result == TSI_OK) {
+    *bytes_size = 0;
+    return TSI_OK;
+  }
+  result = fill_frame_from_bytes(bytes, bytes_size, &impl->incoming);
+  if (result != TSI_OK) return result;
+
+  /* We now have a complete frame. */
+  result = tsi_fake_handshake_message_from_string(
+      (const char *)impl->incoming.data + TSI_FAKE_FRAME_HEADER_SIZE,
+      &received_msg);
+  if (result != TSI_OK) {
+    impl->result = result;
+    return result;
+  }
+  if (received_msg != expected_msg) {
+    gpr_log(GPR_ERROR, "Invalid received message (%s instead of %s)",
+            tsi_fake_handshake_message_to_string(received_msg),
+            tsi_fake_handshake_message_to_string(expected_msg));
+  }
+  if (tsi_tracing_enabled) {
+    gpr_log(GPR_INFO, "%s received %s.", impl->is_client ? "Client" : "Server",
+            tsi_fake_handshake_message_to_string(received_msg));
+  }
+  tsi_fake_frame_reset(&impl->incoming, 0 /* needs_draining */);
+  impl->needs_incoming_message = 0;
+  if (impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
+    /* We're done. */
+    if (tsi_tracing_enabled) {
+      gpr_log(GPR_INFO, "%s is done.", impl->is_client ? "Client" : "Server");
+    }
+    impl->result = TSI_OK;
+  }
+  return TSI_OK;
+}
+
+static tsi_result fake_handshaker_get_result(tsi_handshaker *self) {
+  tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
+  return impl->result;
+}
+
+static tsi_result fake_handshaker_extract_peer(tsi_handshaker *self,
+                                               tsi_peer *peer) {
+  tsi_result result = tsi_construct_peer(1, peer);
+  if (result != TSI_OK) return result;
+  result = tsi_construct_string_peer_property_from_cstring(
+      TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_FAKE_CERTIFICATE_TYPE,
+      &peer->properties[0]);
+  if (result != TSI_OK) tsi_peer_destruct(peer);
+  return result;
+}
+
+static tsi_result fake_handshaker_create_frame_protector(
+    tsi_handshaker *self, size_t *max_protected_frame_size,
+    tsi_frame_protector **protector) {
+  *protector = tsi_create_fake_protector(max_protected_frame_size);
+  if (*protector == NULL) return TSI_OUT_OF_RESOURCES;
+  return TSI_OK;
+}
+
+static void fake_handshaker_destroy(tsi_handshaker *self) {
+  tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
+  tsi_fake_frame_destruct(&impl->incoming);
+  tsi_fake_frame_destruct(&impl->outgoing);
+  free(self);
+}
+
+static const tsi_handshaker_vtable handshaker_vtable = {
+    fake_handshaker_get_bytes_to_send_to_peer,
+    fake_handshaker_process_bytes_from_peer,
+    fake_handshaker_get_result,
+    fake_handshaker_extract_peer,
+    fake_handshaker_create_frame_protector,
+    fake_handshaker_destroy,
+};
+
+tsi_handshaker *tsi_create_fake_handshaker(int is_client) {
+  tsi_fake_handshaker *impl = calloc(1, sizeof(tsi_fake_handshaker));
+  impl->base.vtable = &handshaker_vtable;
+  impl->is_client = is_client;
+  impl->result = TSI_HANDSHAKE_IN_PROGRESS;
+  if (is_client) {
+    impl->needs_incoming_message = 0;
+    impl->next_message_to_send = TSI_FAKE_CLIENT_INIT;
+  } else {
+    impl->needs_incoming_message = 1;
+    impl->next_message_to_send = TSI_FAKE_SERVER_INIT;
+  }
+  return &impl->base;
+}
+
+tsi_frame_protector *tsi_create_fake_protector(
+    size_t *max_protected_frame_size) {
+  tsi_fake_frame_protector *impl = calloc(1, sizeof(tsi_fake_frame_protector));
+  if (impl == NULL) return NULL;
+  impl->max_frame_size = (max_protected_frame_size == NULL)
+                             ? TSI_FAKE_DEFAULT_FRAME_SIZE
+                             : *max_protected_frame_size;
+  impl->base.vtable = &frame_protector_vtable;
+  return &impl->base;
+}
diff --git a/src/core/lib/tsi/fake_transport_security.h b/src/core/lib/tsi/fake_transport_security.h
new file mode 100644
index 0000000..b887dfc
--- /dev/null
+++ b/src/core/lib/tsi/fake_transport_security.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TSI_FAKE_TRANSPORT_SECURITY_H
+#define GRPC_CORE_LIB_TSI_FAKE_TRANSPORT_SECURITY_H
+
+#include "src/core/lib/tsi/transport_security_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */
+#define TSI_FAKE_CERTIFICATE_TYPE "FAKE"
+
+/* Creates a fake handshaker that will create a fake frame protector.
+
+   No cryptography is performed in these objects. They just simulate handshake
+   messages going back and forth for the handshaker and do some framing on
+   cleartext data for the protector.  */
+tsi_handshaker *tsi_create_fake_handshaker(int is_client);
+
+/* Creates a protector directly without going through the handshake phase. */
+tsi_frame_protector *tsi_create_fake_protector(
+    size_t *max_protected_frame_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_TSI_FAKE_TRANSPORT_SECURITY_H */
diff --git a/src/core/lib/tsi/ssl_transport_security.c b/src/core/lib/tsi/ssl_transport_security.c
new file mode 100644
index 0000000..d03201e
--- /dev/null
+++ b/src/core/lib/tsi/ssl_transport_security.c
@@ -0,0 +1,1536 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/tsi/ssl_transport_security.h"
+
+#include <grpc/support/port_platform.h>
+
+#include <limits.h>
+#include <string.h>
+
+/* TODO(jboeuf): refactor inet_ntop into a portability header. */
+#ifdef GPR_WINSOCK_SOCKET
+#include <ws2tcpip.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+
+#include <openssl/bio.h>
+#include <openssl/crypto.h> /* For OPENSSL_free */
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "src/core/lib/tsi/ssl_types.h"
+#include "src/core/lib/tsi/transport_security.h"
+
+/* --- Constants. ---*/
+
+#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... */
+#define TSI_SSL_MAX_PROTECTION_OVERHEAD 100
+
+/* --- Structure definitions. ---*/
+
+struct tsi_ssl_handshaker_factory {
+  tsi_result (*create_handshaker)(tsi_ssl_handshaker_factory *self,
+                                  const char *server_name_indication,
+                                  tsi_handshaker **handshaker);
+  void (*destroy)(tsi_ssl_handshaker_factory *self);
+};
+
+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 {
+  tsi_ssl_handshaker_factory base;
+
+  /* Several contexts to support SNI.
+     The tsi_peer array contains the subject names of the server certificates
+     associated with the contexts at the same index.  */
+  SSL_CTX **ssl_contexts;
+  tsi_peer *ssl_context_x509_subject_names;
+  size_t ssl_context_count;
+  unsigned char *alpn_protocol_list;
+  size_t alpn_protocol_list_length;
+} tsi_ssl_server_handshaker_factory;
+
+typedef struct {
+  tsi_handshaker base;
+  SSL *ssl;
+  BIO *into_ssl;
+  BIO *from_ssl;
+  tsi_result result;
+} tsi_ssl_handshaker;
+
+typedef struct {
+  tsi_frame_protector base;
+  SSL *ssl;
+  BIO *into_ssl;
+  BIO *from_ssl;
+  unsigned char *buffer;
+  size_t buffer_size;
+  size_t buffer_offset;
+} tsi_ssl_frame_protector;
+
+/* --- Library Initialization. ---*/
+
+static gpr_once init_openssl_once = GPR_ONCE_INIT;
+static gpr_mu *openssl_mutexes = NULL;
+
+static void openssl_locking_cb(int mode, int type, const char *file, int line) {
+  if (mode & CRYPTO_LOCK) {
+    gpr_mu_lock(&openssl_mutexes[type]);
+  } else {
+    gpr_mu_unlock(&openssl_mutexes[type]);
+  }
+}
+
+static unsigned long openssl_thread_id_cb(void) {
+  return (unsigned long)gpr_thd_currentid();
+}
+
+static void init_openssl(void) {
+  int i;
+  int num_locks;
+  SSL_library_init();
+  SSL_load_error_strings();
+  OpenSSL_add_all_algorithms();
+  num_locks = CRYPTO_num_locks();
+  GPR_ASSERT(num_locks > 0);
+  openssl_mutexes = malloc((size_t)num_locks * sizeof(gpr_mu));
+  GPR_ASSERT(openssl_mutexes != NULL);
+  for (i = 0; i < CRYPTO_num_locks(); i++) {
+    gpr_mu_init(&openssl_mutexes[i]);
+  }
+  CRYPTO_set_locking_callback(openssl_locking_cb);
+  CRYPTO_set_id_callback(openssl_thread_id_cb);
+}
+
+/* --- Ssl utils. ---*/
+
+static const char *ssl_error_string(int error) {
+  switch (error) {
+    case SSL_ERROR_NONE:
+      return "SSL_ERROR_NONE";
+    case SSL_ERROR_ZERO_RETURN:
+      return "SSL_ERROR_ZERO_RETURN";
+    case SSL_ERROR_WANT_READ:
+      return "SSL_ERROR_WANT_READ";
+    case SSL_ERROR_WANT_WRITE:
+      return "SSL_ERROR_WANT_WRITE";
+    case SSL_ERROR_WANT_CONNECT:
+      return "SSL_ERROR_WANT_CONNECT";
+    case SSL_ERROR_WANT_ACCEPT:
+      return "SSL_ERROR_WANT_ACCEPT";
+    case SSL_ERROR_WANT_X509_LOOKUP:
+      return "SSL_ERROR_WANT_X509_LOOKUP";
+    case SSL_ERROR_SYSCALL:
+      return "SSL_ERROR_SYSCALL";
+    case SSL_ERROR_SSL:
+      return "SSL_ERROR_SSL";
+    default:
+      return "Unknown error";
+  }
+}
+
+/* TODO(jboeuf): Remove when we are past the debugging phase with this code. */
+static void ssl_log_where_info(const SSL *ssl, int where, int flag,
+                               const char *msg) {
+  if ((where & flag) && tsi_tracing_enabled) {
+    gpr_log(GPR_INFO, "%20.20s - %30.30s  - %5.10s", msg,
+            SSL_state_string_long(ssl), SSL_state_string(ssl));
+  }
+}
+
+/* Used for debugging. TODO(jboeuf): Remove when code is mature enough. */
+static void ssl_info_callback(const SSL *ssl, int where, int ret) {
+  if (ret == 0) {
+    gpr_log(GPR_ERROR, "ssl_info_callback: error occured.\n");
+    return;
+  }
+
+  ssl_log_where_info(ssl, where, SSL_CB_LOOP, "LOOP");
+  ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_START, "HANDSHAKE START");
+  ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_DONE, "HANDSHAKE DONE");
+}
+
+/* Returns 1 if name looks like an IP address, 0 otherwise.
+   This is a very rough heuristic, and only handles IPv6 in hexadecimal form. */
+static int looks_like_ip_address(const char *name) {
+  size_t i;
+  size_t dot_count = 0;
+  size_t num_size = 0;
+  for (i = 0; i < strlen(name); i++) {
+    if (name[i] == ':') {
+      /* IPv6 Address in hexadecimal form, : is not allowed in DNS names. */
+      return 1;
+    }
+    if (name[i] >= '0' && name[i] <= '9') {
+      if (num_size > 3) return 0;
+      num_size++;
+    } else if (name[i] == '.') {
+      if (dot_count > 3 || num_size == 0) return 0;
+      dot_count++;
+      num_size = 0;
+    } else {
+      return 0;
+    }
+  }
+  if (dot_count < 3 || num_size == 0) return 0;
+  return 1;
+}
+
+/* Gets the subject CN from an X509 cert. */
+static tsi_result ssl_get_x509_common_name(X509 *cert, unsigned char **utf8,
+                                           size_t *utf8_size) {
+  int common_name_index = -1;
+  X509_NAME_ENTRY *common_name_entry = NULL;
+  ASN1_STRING *common_name_asn1 = NULL;
+  X509_NAME *subject_name = X509_get_subject_name(cert);
+  int utf8_returned_size = 0;
+  if (subject_name == NULL) {
+    gpr_log(GPR_ERROR, "Could not get subject name from certificate.");
+    return TSI_NOT_FOUND;
+  }
+  common_name_index =
+      X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
+  if (common_name_index == -1) {
+    gpr_log(GPR_ERROR,
+            "Could not get common name of subject from certificate.");
+    return TSI_NOT_FOUND;
+  }
+  common_name_entry = X509_NAME_get_entry(subject_name, common_name_index);
+  if (common_name_entry == NULL) {
+    gpr_log(GPR_ERROR, "Could not get common name entry from certificate.");
+    return TSI_INTERNAL_ERROR;
+  }
+  common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
+  if (common_name_asn1 == NULL) {
+    gpr_log(GPR_ERROR,
+            "Could not get common name entry asn1 from certificate.");
+    return TSI_INTERNAL_ERROR;
+  }
+  utf8_returned_size = ASN1_STRING_to_UTF8(utf8, common_name_asn1);
+  if (utf8_returned_size < 0) {
+    gpr_log(GPR_ERROR, "Could not extract utf8 from asn1 string.");
+    return TSI_OUT_OF_RESOURCES;
+  }
+  *utf8_size = (size_t)utf8_returned_size;
+  return TSI_OK;
+}
+
+/* Gets the subject CN of an X509 cert as a tsi_peer_property. */
+static tsi_result peer_property_from_x509_common_name(
+    X509 *cert, tsi_peer_property *property) {
+  unsigned char *common_name;
+  size_t common_name_size;
+  tsi_result result =
+      ssl_get_x509_common_name(cert, &common_name, &common_name_size);
+  if (result != TSI_OK) {
+    if (result == TSI_NOT_FOUND) {
+      common_name = NULL;
+      common_name_size = 0;
+    } else {
+      return result;
+    }
+  }
+  result = tsi_construct_string_peer_property(
+      TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY,
+      common_name == NULL ? "" : (const char *)common_name, common_name_size,
+      property);
+  OPENSSL_free(common_name);
+  return result;
+}
+
+/* Gets the X509 cert in PEM format as a tsi_peer_property. */
+static tsi_result add_pem_certificate(X509 *cert, tsi_peer_property *property) {
+  BIO *bio = BIO_new(BIO_s_mem());
+  if (!PEM_write_bio_X509(bio, cert)) {
+    BIO_free(bio);
+    return TSI_INTERNAL_ERROR;
+  }
+  char *contents;
+  long len = BIO_get_mem_data(bio, &contents);
+  if (len <= 0) {
+    BIO_free(bio);
+    return TSI_INTERNAL_ERROR;
+  }
+  tsi_result result = tsi_construct_string_peer_property(
+      TSI_X509_PEM_CERT_PROPERTY, (const char *)contents, (size_t)len,
+      property);
+  BIO_free(bio);
+  return result;
+}
+
+/* Gets the subject SANs from an X509 cert as a tsi_peer_property. */
+static tsi_result add_subject_alt_names_properties_to_peer(
+    tsi_peer *peer, GENERAL_NAMES *subject_alt_names,
+    size_t subject_alt_name_count) {
+  size_t i;
+  tsi_result result = TSI_OK;
+
+  /* Reset for DNS entries filtering. */
+  peer->property_count -= subject_alt_name_count;
+
+  for (i = 0; i < subject_alt_name_count; i++) {
+    GENERAL_NAME *subject_alt_name =
+        sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i));
+    /* Filter out the non-dns entries names. */
+    if (subject_alt_name->type == GEN_DNS) {
+      unsigned char *name = NULL;
+      int name_size;
+      name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.dNSName);
+      if (name_size < 0) {
+        gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string.");
+        result = TSI_INTERNAL_ERROR;
+        break;
+      }
+      result = tsi_construct_string_peer_property(
+          TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, (const char *)name,
+          (size_t)name_size, &peer->properties[peer->property_count++]);
+      OPENSSL_free(name);
+    } else if (subject_alt_name->type == GEN_IPADD) {
+      char ntop_buf[INET6_ADDRSTRLEN];
+      int af;
+
+      if (subject_alt_name->d.iPAddress->length == 4) {
+        af = AF_INET;
+      } else if (subject_alt_name->d.iPAddress->length == 16) {
+        af = AF_INET6;
+      } else {
+        gpr_log(GPR_ERROR, "SAN IP Address contained invalid IP");
+        result = TSI_INTERNAL_ERROR;
+        break;
+      }
+      const char *name = inet_ntop(af, subject_alt_name->d.iPAddress->data,
+                                   ntop_buf, INET6_ADDRSTRLEN);
+      if (name == NULL) {
+        gpr_log(GPR_ERROR, "Could not get IP string from asn1 octet.");
+        result = TSI_INTERNAL_ERROR;
+        break;
+      }
+
+      result = tsi_construct_string_peer_property_from_cstring(
+          TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, name,
+          &peer->properties[peer->property_count++]);
+    }
+    if (result != TSI_OK) break;
+  }
+  return result;
+}
+
+/* Gets information about the peer's X509 cert as a tsi_peer object. */
+static tsi_result peer_from_x509(X509 *cert, int include_certificate_type,
+                                 tsi_peer *peer) {
+  /* TODO(jboeuf): Maybe add more properties. */
+  GENERAL_NAMES *subject_alt_names =
+      X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
+  int subject_alt_name_count = (subject_alt_names != NULL)
+                                   ? (int)sk_GENERAL_NAME_num(subject_alt_names)
+                                   : 0;
+  size_t property_count;
+  tsi_result result;
+  GPR_ASSERT(subject_alt_name_count >= 0);
+  property_count = (include_certificate_type ? (size_t)1 : 0) +
+                   2 /* common name, certificate */ +
+                   (size_t)subject_alt_name_count;
+  result = tsi_construct_peer(property_count, peer);
+  if (result != TSI_OK) return result;
+  do {
+    if (include_certificate_type) {
+      result = tsi_construct_string_peer_property_from_cstring(
+          TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
+          &peer->properties[0]);
+      if (result != TSI_OK) break;
+    }
+    result = peer_property_from_x509_common_name(
+        cert, &peer->properties[include_certificate_type ? 1 : 0]);
+    if (result != TSI_OK) break;
+
+    result = add_pem_certificate(
+        cert, &peer->properties[include_certificate_type ? 2 : 1]);
+    if (result != TSI_OK) break;
+
+    if (subject_alt_name_count != 0) {
+      result = add_subject_alt_names_properties_to_peer(
+          peer, subject_alt_names, (size_t)subject_alt_name_count);
+      if (result != TSI_OK) break;
+    }
+  } while (0);
+
+  if (subject_alt_names != NULL) {
+    sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free);
+  }
+  if (result != TSI_OK) tsi_peer_destruct(peer);
+  return result;
+}
+
+/* Logs the SSL error stack. */
+static void log_ssl_error_stack(void) {
+  unsigned long err;
+  while ((err = ERR_get_error()) != 0) {
+    char details[256];
+    ERR_error_string_n((uint32_t)err, details, sizeof(details));
+    gpr_log(GPR_ERROR, "%s", details);
+  }
+}
+
+/* Performs an SSL_read and handle errors. */
+static tsi_result do_ssl_read(SSL *ssl, unsigned char *unprotected_bytes,
+                              size_t *unprotected_bytes_size) {
+  int read_from_ssl;
+  GPR_ASSERT(*unprotected_bytes_size <= INT_MAX);
+  read_from_ssl =
+      SSL_read(ssl, unprotected_bytes, (int)*unprotected_bytes_size);
+  if (read_from_ssl == 0) {
+    gpr_log(GPR_ERROR, "SSL_read returned 0 unexpectedly.");
+    return TSI_INTERNAL_ERROR;
+  }
+  if (read_from_ssl < 0) {
+    read_from_ssl = SSL_get_error(ssl, read_from_ssl);
+    switch (read_from_ssl) {
+      case SSL_ERROR_WANT_READ:
+        /* We need more data to finish the frame. */
+        *unprotected_bytes_size = 0;
+        return TSI_OK;
+      case SSL_ERROR_WANT_WRITE:
+        gpr_log(
+            GPR_ERROR,
+            "Peer tried to renegotiate SSL connection. This is unsupported.");
+        return TSI_UNIMPLEMENTED;
+      case SSL_ERROR_SSL:
+        gpr_log(GPR_ERROR, "Corruption detected.");
+        log_ssl_error_stack();
+        return TSI_DATA_CORRUPTED;
+      default:
+        gpr_log(GPR_ERROR, "SSL_read failed with error %s.",
+                ssl_error_string(read_from_ssl));
+        return TSI_PROTOCOL_FAILURE;
+    }
+  }
+  *unprotected_bytes_size = (size_t)read_from_ssl;
+  return TSI_OK;
+}
+
+/* Performs an SSL_write and handle errors. */
+static tsi_result do_ssl_write(SSL *ssl, unsigned char *unprotected_bytes,
+                               size_t unprotected_bytes_size) {
+  int ssl_write_result;
+  GPR_ASSERT(unprotected_bytes_size <= INT_MAX);
+  ssl_write_result =
+      SSL_write(ssl, unprotected_bytes, (int)unprotected_bytes_size);
+  if (ssl_write_result < 0) {
+    ssl_write_result = SSL_get_error(ssl, ssl_write_result);
+    if (ssl_write_result == SSL_ERROR_WANT_READ) {
+      gpr_log(GPR_ERROR,
+              "Peer tried to renegotiate SSL connection. This is unsupported.");
+      return TSI_UNIMPLEMENTED;
+    } else {
+      gpr_log(GPR_ERROR, "SSL_write failed with error %s.",
+              ssl_error_string(ssl_write_result));
+      return TSI_INTERNAL_ERROR;
+    }
+  }
+  return TSI_OK;
+}
+
+/* Loads an in-memory PEM certificate chain into the SSL context. */
+static tsi_result ssl_ctx_use_certificate_chain(
+    SSL_CTX *context, const unsigned char *pem_cert_chain,
+    size_t pem_cert_chain_size) {
+  tsi_result result = TSI_OK;
+  X509 *certificate = NULL;
+  BIO *pem;
+  GPR_ASSERT(pem_cert_chain_size <= INT_MAX);
+  pem = BIO_new_mem_buf((void *)pem_cert_chain, (int)pem_cert_chain_size);
+  if (pem == NULL) return TSI_OUT_OF_RESOURCES;
+
+  do {
+    certificate = PEM_read_bio_X509_AUX(pem, NULL, NULL, "");
+    if (certificate == NULL) {
+      result = TSI_INVALID_ARGUMENT;
+      break;
+    }
+    if (!SSL_CTX_use_certificate(context, certificate)) {
+      result = TSI_INVALID_ARGUMENT;
+      break;
+    }
+    while (1) {
+      X509 *certificate_authority = PEM_read_bio_X509(pem, NULL, NULL, "");
+      if (certificate_authority == NULL) {
+        ERR_clear_error();
+        break; /* Done reading. */
+      }
+      if (!SSL_CTX_add_extra_chain_cert(context, certificate_authority)) {
+        X509_free(certificate_authority);
+        result = TSI_INVALID_ARGUMENT;
+        break;
+      }
+      /* We don't need to free certificate_authority as its ownership has been
+         transfered to the context. That is not the case for certificate though.
+       */
+    }
+  } while (0);
+
+  if (certificate != NULL) X509_free(certificate);
+  BIO_free(pem);
+  return result;
+}
+
+/* Loads an in-memory PEM private key into the SSL context. */
+static tsi_result ssl_ctx_use_private_key(SSL_CTX *context,
+                                          const unsigned char *pem_key,
+                                          size_t pem_key_size) {
+  tsi_result result = TSI_OK;
+  EVP_PKEY *private_key = NULL;
+  BIO *pem;
+  GPR_ASSERT(pem_key_size <= INT_MAX);
+  pem = BIO_new_mem_buf((void *)pem_key, (int)pem_key_size);
+  if (pem == NULL) return TSI_OUT_OF_RESOURCES;
+  do {
+    private_key = PEM_read_bio_PrivateKey(pem, NULL, NULL, "");
+    if (private_key == NULL) {
+      result = TSI_INVALID_ARGUMENT;
+      break;
+    }
+    if (!SSL_CTX_use_PrivateKey(context, private_key)) {
+      result = TSI_INVALID_ARGUMENT;
+      break;
+    }
+  } while (0);
+  if (private_key != NULL) EVP_PKEY_free(private_key);
+  BIO_free(pem);
+  return result;
+}
+
+/* Loads in-memory PEM verification certs into the SSL context and optionally
+   returns the verification cert names (root_names can be NULL). */
+static tsi_result ssl_ctx_load_verification_certs(
+    SSL_CTX *context, const unsigned char *pem_roots, size_t pem_roots_size,
+    STACK_OF(X509_NAME) * *root_names) {
+  tsi_result result = TSI_OK;
+  size_t num_roots = 0;
+  X509 *root = NULL;
+  X509_NAME *root_name = NULL;
+  BIO *pem;
+  X509_STORE *root_store;
+  GPR_ASSERT(pem_roots_size <= INT_MAX);
+  pem = BIO_new_mem_buf((void *)pem_roots, (int)pem_roots_size);
+  root_store = SSL_CTX_get_cert_store(context);
+  if (root_store == NULL) return TSI_INVALID_ARGUMENT;
+  if (pem == NULL) return TSI_OUT_OF_RESOURCES;
+  if (root_names != NULL) {
+    *root_names = sk_X509_NAME_new_null();
+    if (*root_names == NULL) return TSI_OUT_OF_RESOURCES;
+  }
+
+  while (1) {
+    root = PEM_read_bio_X509_AUX(pem, NULL, NULL, "");
+    if (root == NULL) {
+      ERR_clear_error();
+      break; /* We're at the end of stream. */
+    }
+    if (root_names != NULL) {
+      root_name = X509_get_subject_name(root);
+      if (root_name == NULL) {
+        gpr_log(GPR_ERROR, "Could not get name from root certificate.");
+        result = TSI_INVALID_ARGUMENT;
+        break;
+      }
+      root_name = X509_NAME_dup(root_name);
+      if (root_name == NULL) {
+        result = TSI_OUT_OF_RESOURCES;
+        break;
+      }
+      sk_X509_NAME_push(*root_names, root_name);
+      root_name = NULL;
+    }
+    if (!X509_STORE_add_cert(root_store, root)) {
+      gpr_log(GPR_ERROR, "Could not add root certificate to ssl context.");
+      result = TSI_INTERNAL_ERROR;
+      break;
+    }
+    X509_free(root);
+    num_roots++;
+  }
+
+  if (num_roots == 0) {
+    gpr_log(GPR_ERROR, "Could not load any root certificate.");
+    result = TSI_INVALID_ARGUMENT;
+  }
+
+  if (result != TSI_OK) {
+    if (root != NULL) X509_free(root);
+    if (root_names != NULL) {
+      sk_X509_NAME_pop_free(*root_names, X509_NAME_free);
+      *root_names = NULL;
+      if (root_name != NULL) X509_NAME_free(root_name);
+    }
+  }
+  BIO_free(pem);
+  return result;
+}
+
+/* Populates the SSL context with a private key and a cert chain, and sets the
+   cipher list and the ephemeral ECDH key. */
+static tsi_result populate_ssl_context(
+    SSL_CTX *context, const unsigned char *pem_private_key,
+    size_t pem_private_key_size, const unsigned char *pem_certificate_chain,
+    size_t pem_certificate_chain_size, const char *cipher_list) {
+  tsi_result result = TSI_OK;
+  if (pem_certificate_chain != NULL) {
+    result = ssl_ctx_use_certificate_chain(context, pem_certificate_chain,
+                                           pem_certificate_chain_size);
+    if (result != TSI_OK) {
+      gpr_log(GPR_ERROR, "Invalid cert chain file.");
+      return result;
+    }
+  }
+  if (pem_private_key != NULL) {
+    result =
+        ssl_ctx_use_private_key(context, pem_private_key, pem_private_key_size);
+    if (result != TSI_OK || !SSL_CTX_check_private_key(context)) {
+      gpr_log(GPR_ERROR, "Invalid private key.");
+      return result != TSI_OK ? result : TSI_INVALID_ARGUMENT;
+    }
+  }
+  if ((cipher_list != NULL) && !SSL_CTX_set_cipher_list(context, cipher_list)) {
+    gpr_log(GPR_ERROR, "Invalid cipher list: %s.", cipher_list);
+    return TSI_INVALID_ARGUMENT;
+  }
+  {
+    EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+    if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) {
+      gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key.");
+      EC_KEY_free(ecdh);
+      return TSI_INTERNAL_ERROR;
+    }
+    SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
+    EC_KEY_free(ecdh);
+  }
+  return TSI_OK;
+}
+
+/* Extracts the CN and the SANs from an X509 cert as a peer object. */
+static tsi_result extract_x509_subject_names_from_pem_cert(
+    const unsigned char *pem_cert, size_t pem_cert_size, tsi_peer *peer) {
+  tsi_result result = TSI_OK;
+  X509 *cert = NULL;
+  BIO *pem;
+  GPR_ASSERT(pem_cert_size <= INT_MAX);
+  pem = BIO_new_mem_buf((void *)pem_cert, (int)pem_cert_size);
+  if (pem == NULL) return TSI_OUT_OF_RESOURCES;
+
+  cert = PEM_read_bio_X509(pem, NULL, NULL, "");
+  if (cert == NULL) {
+    gpr_log(GPR_ERROR, "Invalid certificate");
+    result = TSI_INVALID_ARGUMENT;
+  } else {
+    result = peer_from_x509(cert, 0, peer);
+  }
+  if (cert != NULL) X509_free(cert);
+  BIO_free(pem);
+  return result;
+}
+
+/* Builds the alpn protocol name list according to rfc 7301. */
+static tsi_result build_alpn_protocol_name_list(
+    const unsigned char **alpn_protocols,
+    const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
+    unsigned char **protocol_name_list, size_t *protocol_name_list_length) {
+  uint16_t i;
+  unsigned char *current;
+  *protocol_name_list = NULL;
+  *protocol_name_list_length = 0;
+  if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT;
+  for (i = 0; i < num_alpn_protocols; i++) {
+    if (alpn_protocols_lengths[i] == 0) {
+      gpr_log(GPR_ERROR, "Invalid 0-length protocol name.");
+      return TSI_INVALID_ARGUMENT;
+    }
+    *protocol_name_list_length += (size_t)alpn_protocols_lengths[i] + 1;
+  }
+  *protocol_name_list = malloc(*protocol_name_list_length);
+  if (*protocol_name_list == NULL) return TSI_OUT_OF_RESOURCES;
+  current = *protocol_name_list;
+  for (i = 0; i < num_alpn_protocols; i++) {
+    *(current++) = alpn_protocols_lengths[i];
+    memcpy(current, alpn_protocols[i], alpn_protocols_lengths[i]);
+    current += alpn_protocols_lengths[i];
+  }
+  /* Safety check. */
+  if ((current < *protocol_name_list) ||
+      ((uintptr_t)(current - *protocol_name_list) !=
+       *protocol_name_list_length)) {
+    return TSI_INTERNAL_ERROR;
+  }
+  return TSI_OK;
+}
+
+/* --- tsi_frame_protector methods implementation. ---*/
+
+static tsi_result ssl_protector_protect(tsi_frame_protector *self,
+                                        const unsigned char *unprotected_bytes,
+                                        size_t *unprotected_bytes_size,
+                                        unsigned char *protected_output_frames,
+                                        size_t *protected_output_frames_size) {
+  tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
+  int read_from_ssl;
+  size_t available;
+  tsi_result result = TSI_OK;
+
+  /* First see if we have some pending data in the SSL BIO. */
+  int pending_in_ssl = (int)BIO_pending(impl->from_ssl);
+  if (pending_in_ssl > 0) {
+    *unprotected_bytes_size = 0;
+    GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
+    read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
+                             (int)*protected_output_frames_size);
+    if (read_from_ssl < 0) {
+      gpr_log(GPR_ERROR,
+              "Could not read from BIO even though some data is pending");
+      return TSI_INTERNAL_ERROR;
+    }
+    *protected_output_frames_size = (size_t)read_from_ssl;
+    return TSI_OK;
+  }
+
+  /* Now see if we can send a complete frame. */
+  available = impl->buffer_size - impl->buffer_offset;
+  if (available > *unprotected_bytes_size) {
+    /* If we cannot, just copy the data in our internal buffer. */
+    memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes,
+           *unprotected_bytes_size);
+    impl->buffer_offset += *unprotected_bytes_size;
+    *protected_output_frames_size = 0;
+    return TSI_OK;
+  }
+
+  /* If we can, prepare the buffer, send it to SSL_write and read. */
+  memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, available);
+  result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_size);
+  if (result != TSI_OK) return result;
+
+  GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
+  read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
+                           (int)*protected_output_frames_size);
+  if (read_from_ssl < 0) {
+    gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
+    return TSI_INTERNAL_ERROR;
+  }
+  *protected_output_frames_size = (size_t)read_from_ssl;
+  *unprotected_bytes_size = available;
+  impl->buffer_offset = 0;
+  return TSI_OK;
+}
+
+static tsi_result ssl_protector_protect_flush(
+    tsi_frame_protector *self, unsigned char *protected_output_frames,
+    size_t *protected_output_frames_size, size_t *still_pending_size) {
+  tsi_result result = TSI_OK;
+  tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
+  int read_from_ssl = 0;
+  int pending;
+
+  if (impl->buffer_offset != 0) {
+    result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_offset);
+    if (result != TSI_OK) return result;
+    impl->buffer_offset = 0;
+  }
+
+  pending = (int)BIO_pending(impl->from_ssl);
+  GPR_ASSERT(pending >= 0);
+  *still_pending_size = (size_t)pending;
+  if (*still_pending_size == 0) return TSI_OK;
+
+  GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
+  read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
+                           (int)*protected_output_frames_size);
+  if (read_from_ssl <= 0) {
+    gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
+    return TSI_INTERNAL_ERROR;
+  }
+  *protected_output_frames_size = (size_t)read_from_ssl;
+  pending = (int)BIO_pending(impl->from_ssl);
+  GPR_ASSERT(pending >= 0);
+  *still_pending_size = (size_t)pending;
+  return TSI_OK;
+}
+
+static tsi_result ssl_protector_unprotect(
+    tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
+    size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
+    size_t *unprotected_bytes_size) {
+  tsi_result result = TSI_OK;
+  int written_into_ssl = 0;
+  size_t output_bytes_size = *unprotected_bytes_size;
+  size_t output_bytes_offset = 0;
+  tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
+
+  /* First, try to read remaining data from ssl. */
+  result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
+  if (result != TSI_OK) return result;
+  if (*unprotected_bytes_size == output_bytes_size) {
+    /* We have read everything we could and cannot process any more input. */
+    *protected_frames_bytes_size = 0;
+    return TSI_OK;
+  }
+  output_bytes_offset = *unprotected_bytes_size;
+  unprotected_bytes += output_bytes_offset;
+  *unprotected_bytes_size = output_bytes_size - output_bytes_offset;
+
+  /* Then, try to write some data to ssl. */
+  GPR_ASSERT(*protected_frames_bytes_size <= INT_MAX);
+  written_into_ssl = BIO_write(impl->into_ssl, protected_frames_bytes,
+                               (int)*protected_frames_bytes_size);
+  if (written_into_ssl < 0) {
+    gpr_log(GPR_ERROR, "Sending protected frame to ssl failed with %d",
+            written_into_ssl);
+    return TSI_INTERNAL_ERROR;
+  }
+  *protected_frames_bytes_size = (size_t)written_into_ssl;
+
+  /* Now try to read some data again. */
+  result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
+  if (result == TSI_OK) {
+    /* Don't forget to output the total number of bytes read. */
+    *unprotected_bytes_size += output_bytes_offset;
+  }
+  return result;
+}
+
+static void ssl_protector_destroy(tsi_frame_protector *self) {
+  tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
+  if (impl->buffer != NULL) free(impl->buffer);
+  if (impl->ssl != NULL) SSL_free(impl->ssl);
+  free(self);
+}
+
+static const tsi_frame_protector_vtable frame_protector_vtable = {
+    ssl_protector_protect, ssl_protector_protect_flush, ssl_protector_unprotect,
+    ssl_protector_destroy,
+};
+
+/* --- tsi_handshaker methods implementation. ---*/
+
+static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
+                                                           unsigned char *bytes,
+                                                           size_t *bytes_size) {
+  tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
+  int bytes_read_from_ssl = 0;
+  if (bytes == NULL || bytes_size == NULL || *bytes_size == 0 ||
+      *bytes_size > INT_MAX) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  GPR_ASSERT(*bytes_size <= INT_MAX);
+  bytes_read_from_ssl = BIO_read(impl->from_ssl, bytes, (int)*bytes_size);
+  if (bytes_read_from_ssl < 0) {
+    *bytes_size = 0;
+    if (!BIO_should_retry(impl->from_ssl)) {
+      impl->result = TSI_INTERNAL_ERROR;
+      return impl->result;
+    } else {
+      return TSI_OK;
+    }
+  }
+  *bytes_size = (size_t)bytes_read_from_ssl;
+  return BIO_pending(impl->from_ssl) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA;
+}
+
+static tsi_result ssl_handshaker_get_result(tsi_handshaker *self) {
+  tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
+  if ((impl->result == TSI_HANDSHAKE_IN_PROGRESS) &&
+      SSL_is_init_finished(impl->ssl)) {
+    impl->result = TSI_OK;
+  }
+  return impl->result;
+}
+
+static tsi_result ssl_handshaker_process_bytes_from_peer(
+    tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) {
+  tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
+  int bytes_written_into_ssl_size = 0;
+  if (bytes == NULL || bytes_size == 0 || *bytes_size > INT_MAX) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  GPR_ASSERT(*bytes_size <= INT_MAX);
+  bytes_written_into_ssl_size =
+      BIO_write(impl->into_ssl, bytes, (int)*bytes_size);
+  if (bytes_written_into_ssl_size < 0) {
+    gpr_log(GPR_ERROR, "Could not write to memory BIO.");
+    impl->result = TSI_INTERNAL_ERROR;
+    return impl->result;
+  }
+  *bytes_size = (size_t)bytes_written_into_ssl_size;
+
+  if (!tsi_handshaker_is_in_progress(self)) {
+    impl->result = TSI_OK;
+    return impl->result;
+  } else {
+    /* Get ready to get some bytes from SSL. */
+    int ssl_result = SSL_do_handshake(impl->ssl);
+    ssl_result = SSL_get_error(impl->ssl, ssl_result);
+    switch (ssl_result) {
+      case SSL_ERROR_WANT_READ:
+        if (BIO_pending(impl->from_ssl) == 0) {
+          /* We need more data. */
+          return TSI_INCOMPLETE_DATA;
+        } else {
+          return TSI_OK;
+        }
+      case SSL_ERROR_NONE:
+        return TSI_OK;
+      default: {
+        char err_str[256];
+        ERR_error_string_n(ERR_get_error(), err_str, sizeof(err_str));
+        gpr_log(GPR_ERROR, "Handshake failed with fatal error %s: %s.",
+                ssl_error_string(ssl_result), err_str);
+        impl->result = TSI_PROTOCOL_FAILURE;
+        return impl->result;
+      }
+    }
+  }
+}
+
+static tsi_result ssl_handshaker_extract_peer(tsi_handshaker *self,
+                                              tsi_peer *peer) {
+  tsi_result result = TSI_OK;
+  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);
+  if (peer_cert != NULL) {
+    result = peer_from_x509(peer_cert, 1, peer);
+    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 =
+        calloc(1, sizeof(tsi_peer_property) * (peer->property_count + 1));
+    if (new_properties == NULL) return TSI_OUT_OF_RESOURCES;
+    for (i = 0; i < peer->property_count; i++) {
+      new_properties[i] = peer->properties[i];
+    }
+    result = tsi_construct_string_peer_property(
+        TSI_SSL_ALPN_SELECTED_PROTOCOL, (const char *)alpn_selected,
+        alpn_selected_len, &new_properties[peer->property_count]);
+    if (result != TSI_OK) {
+      free(new_properties);
+      return result;
+    }
+    if (peer->properties != NULL) free(peer->properties);
+    peer->property_count++;
+    peer->properties = new_properties;
+  }
+  return result;
+}
+
+static tsi_result ssl_handshaker_create_frame_protector(
+    tsi_handshaker *self, size_t *max_output_protected_frame_size,
+    tsi_frame_protector **protector) {
+  size_t actual_max_output_protected_frame_size =
+      TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
+  tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
+  tsi_ssl_frame_protector *protector_impl =
+      calloc(1, sizeof(tsi_ssl_frame_protector));
+  if (protector_impl == NULL) {
+    return TSI_OUT_OF_RESOURCES;
+  }
+
+  if (max_output_protected_frame_size != NULL) {
+    if (*max_output_protected_frame_size >
+        TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND) {
+      *max_output_protected_frame_size =
+          TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
+    } else if (*max_output_protected_frame_size <
+               TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND) {
+      *max_output_protected_frame_size =
+          TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND;
+    }
+    actual_max_output_protected_frame_size = *max_output_protected_frame_size;
+  }
+  protector_impl->buffer_size =
+      actual_max_output_protected_frame_size - TSI_SSL_MAX_PROTECTION_OVERHEAD;
+  protector_impl->buffer = malloc(protector_impl->buffer_size);
+  if (protector_impl->buffer == NULL) {
+    gpr_log(GPR_ERROR,
+            "Could not allocated buffer for tsi_ssl_frame_protector.");
+    free(protector_impl);
+    return TSI_INTERNAL_ERROR;
+  }
+
+  /* Transfer ownership of ssl to the frame protector. It is OK as the caller
+   * cannot call anything else but destroy on the handshaker after this call. */
+  protector_impl->ssl = impl->ssl;
+  impl->ssl = NULL;
+  protector_impl->into_ssl = impl->into_ssl;
+  protector_impl->from_ssl = impl->from_ssl;
+
+  protector_impl->base.vtable = &frame_protector_vtable;
+  *protector = &protector_impl->base;
+  return TSI_OK;
+}
+
+static void ssl_handshaker_destroy(tsi_handshaker *self) {
+  tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
+  SSL_free(impl->ssl); /* The BIO objects are owned by ssl */
+  free(impl);
+}
+
+static const tsi_handshaker_vtable handshaker_vtable = {
+    ssl_handshaker_get_bytes_to_send_to_peer,
+    ssl_handshaker_process_bytes_from_peer,
+    ssl_handshaker_get_result,
+    ssl_handshaker_extract_peer,
+    ssl_handshaker_create_frame_protector,
+    ssl_handshaker_destroy,
+};
+
+/* --- tsi_ssl_handshaker_factory common methods. --- */
+
+tsi_result tsi_ssl_handshaker_factory_create_handshaker(
+    tsi_ssl_handshaker_factory *self, const char *server_name_indication,
+    tsi_handshaker **handshaker) {
+  if (self == NULL || handshaker == NULL) return TSI_INVALID_ARGUMENT;
+  return self->create_handshaker(self, server_name_indication, handshaker);
+}
+
+void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self) {
+  if (self == NULL) return;
+  self->destroy(self);
+}
+
+static tsi_result create_tsi_ssl_handshaker(SSL_CTX *ctx, int is_client,
+                                            const char *server_name_indication,
+                                            tsi_handshaker **handshaker) {
+  SSL *ssl = SSL_new(ctx);
+  BIO *into_ssl = NULL;
+  BIO *from_ssl = NULL;
+  tsi_ssl_handshaker *impl = NULL;
+  *handshaker = NULL;
+  if (ctx == NULL) {
+    gpr_log(GPR_ERROR, "SSL Context is null. Should never happen.");
+    return TSI_INTERNAL_ERROR;
+  }
+  if (ssl == NULL) {
+    return TSI_OUT_OF_RESOURCES;
+  }
+  SSL_set_info_callback(ssl, ssl_info_callback);
+
+  into_ssl = BIO_new(BIO_s_mem());
+  from_ssl = BIO_new(BIO_s_mem());
+  if (into_ssl == NULL || from_ssl == NULL) {
+    gpr_log(GPR_ERROR, "BIO_new failed.");
+    SSL_free(ssl);
+    if (into_ssl != NULL) BIO_free(into_ssl);
+    if (from_ssl != NULL) BIO_free(into_ssl);
+    return TSI_OUT_OF_RESOURCES;
+  }
+  SSL_set_bio(ssl, into_ssl, from_ssl);
+  if (is_client) {
+    int ssl_result;
+    SSL_set_connect_state(ssl);
+    if (server_name_indication != NULL) {
+      if (!SSL_set_tlsext_host_name(ssl, server_name_indication)) {
+        gpr_log(GPR_ERROR, "Invalid server name indication %s.",
+                server_name_indication);
+        SSL_free(ssl);
+        return TSI_INTERNAL_ERROR;
+      }
+    }
+    ssl_result = SSL_do_handshake(ssl);
+    ssl_result = SSL_get_error(ssl, ssl_result);
+    if (ssl_result != SSL_ERROR_WANT_READ) {
+      gpr_log(GPR_ERROR,
+              "Unexpected error received from first SSL_do_handshake call: %s",
+              ssl_error_string(ssl_result));
+      SSL_free(ssl);
+      return TSI_INTERNAL_ERROR;
+    }
+  } else {
+    SSL_set_accept_state(ssl);
+  }
+
+  impl = calloc(1, sizeof(tsi_ssl_handshaker));
+  if (impl == NULL) {
+    SSL_free(ssl);
+    return TSI_OUT_OF_RESOURCES;
+  }
+  impl->ssl = ssl;
+  impl->into_ssl = into_ssl;
+  impl->from_ssl = from_ssl;
+  impl->result = TSI_HANDSHAKE_IN_PROGRESS;
+  impl->base.vtable = &handshaker_vtable;
+  *handshaker = &impl->base;
+  return TSI_OK;
+}
+
+static int select_protocol_list(const unsigned char **out,
+                                unsigned char *outlen,
+                                const unsigned char *client_list,
+                                size_t client_list_len,
+                                const unsigned char *server_list,
+                                size_t 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) &&
+           (uintptr_t)(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(
+    tsi_ssl_handshaker_factory *self, const char *server_name_indication,
+    tsi_handshaker **handshaker) {
+  tsi_ssl_client_handshaker_factory *impl =
+      (tsi_ssl_client_handshaker_factory *)self;
+  return create_tsi_ssl_handshaker(impl->ssl_context, 1, server_name_indication,
+                                   handshaker);
+}
+
+static void ssl_client_handshaker_factory_destroy(
+    tsi_ssl_handshaker_factory *self) {
+  tsi_ssl_client_handshaker_factory *impl =
+      (tsi_ssl_client_handshaker_factory *)self;
+  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(
+    tsi_ssl_handshaker_factory *self, const char *server_name_indication,
+    tsi_handshaker **handshaker) {
+  tsi_ssl_server_handshaker_factory *impl =
+      (tsi_ssl_server_handshaker_factory *)self;
+  if (impl->ssl_context_count == 0 || server_name_indication != NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  /* Create the handshaker with the first context. We will switch if needed
+     because of SNI in ssl_server_handshaker_factory_servername_callback.  */
+  return create_tsi_ssl_handshaker(impl->ssl_contexts[0], 0, NULL, handshaker);
+}
+
+static void ssl_server_handshaker_factory_destroy(
+    tsi_ssl_handshaker_factory *self) {
+  tsi_ssl_server_handshaker_factory *impl =
+      (tsi_ssl_server_handshaker_factory *)self;
+  size_t i;
+  for (i = 0; i < impl->ssl_context_count; i++) {
+    if (impl->ssl_contexts[i] != NULL) {
+      SSL_CTX_free(impl->ssl_contexts[i]);
+      tsi_peer_destruct(&impl->ssl_context_x509_subject_names[i]);
+    }
+  }
+  if (impl->ssl_contexts != NULL) free(impl->ssl_contexts);
+  if (impl->ssl_context_x509_subject_names != NULL) {
+    free(impl->ssl_context_x509_subject_names);
+  }
+  if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list);
+  free(impl);
+}
+
+static int does_entry_match_name(const char *entry, size_t entry_length,
+                                 const char *name) {
+  const char *dot;
+  const char *name_subdomain = NULL;
+  size_t name_length = strlen(name);
+  size_t name_subdomain_length;
+  if (entry_length == 0) return 0;
+
+  /* Take care of '.' terminations. */
+  if (name[name_length - 1] == '.') {
+    name_length--;
+  }
+  if (entry[entry_length - 1] == '.') {
+    entry_length--;
+    if (entry_length == 0) return 0;
+  }
+
+  if ((name_length == entry_length) &&
+      strncmp(name, entry, entry_length) == 0) {
+    return 1; /* Perfect match. */
+  }
+  if (entry[0] != '*') return 0;
+
+  /* Wildchar subdomain matching. */
+  if (entry_length < 3 || entry[1] != '.') { /* At least *.x */
+    gpr_log(GPR_ERROR, "Invalid wildchar entry.");
+    return 0;
+  }
+  name_subdomain = strchr(name, '.');
+  if (name_subdomain == NULL) return 0;
+  name_subdomain_length = strlen(name_subdomain);
+  if (name_subdomain_length < 2) return 0;
+  name_subdomain++; /* Starts after the dot. */
+  name_subdomain_length--;
+  entry += 2; /* Remove *. */
+  entry_length -= 2;
+  dot = strchr(name_subdomain, '.');
+  if ((dot == NULL) || (dot == &name_subdomain[name_subdomain_length - 1])) {
+    gpr_log(GPR_ERROR, "Invalid toplevel subdomain: %s", name_subdomain);
+    return 0;
+  }
+  if (name_subdomain[name_subdomain_length - 1] == '.') {
+    name_subdomain_length--;
+  }
+  return ((entry_length > 0) && (name_subdomain_length == entry_length) &&
+          strncmp(entry, name_subdomain, entry_length) == 0);
+}
+
+static int ssl_server_handshaker_factory_servername_callback(SSL *ssl, int *ap,
+                                                             void *arg) {
+  tsi_ssl_server_handshaker_factory *impl =
+      (tsi_ssl_server_handshaker_factory *)arg;
+  size_t i = 0;
+  const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+  if (servername == NULL || strlen(servername) == 0) {
+    return SSL_TLSEXT_ERR_NOACK;
+  }
+
+  for (i = 0; i < impl->ssl_context_count; i++) {
+    if (tsi_ssl_peer_matches_name(&impl->ssl_context_x509_subject_names[i],
+                                  servername)) {
+      SSL_set_SSL_CTX(ssl, impl->ssl_contexts[i]);
+      return SSL_TLSEXT_ERR_OK;
+    }
+  }
+  gpr_log(GPR_ERROR, "No match found for server name: %s.", servername);
+  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;
+  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;
+  GPR_ASSERT(factory->alpn_protocol_list_length <= UINT_MAX);
+  *outlen = (unsigned int)factory->alpn_protocol_list_length;
+  return SSL_TLSEXT_ERR_OK;
+}
+
+/* --- tsi_ssl_handshaker_factory constructors. --- */
+
+tsi_result tsi_create_ssl_client_handshaker_factory(
+    const unsigned char *pem_private_key, size_t pem_private_key_size,
+    const unsigned char *pem_cert_chain, size_t pem_cert_chain_size,
+    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
+    const char *cipher_list, const unsigned char **alpn_protocols,
+    const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
+    tsi_ssl_handshaker_factory **factory) {
+  SSL_CTX *ssl_context = NULL;
+  tsi_ssl_client_handshaker_factory *impl = NULL;
+  tsi_result result = TSI_OK;
+
+  gpr_once_init(&init_openssl_once, init_openssl);
+
+  if (factory == NULL) return TSI_INVALID_ARGUMENT;
+  *factory = NULL;
+  if (pem_root_certs == NULL) return TSI_INVALID_ARGUMENT;
+
+  ssl_context = SSL_CTX_new(TLSv1_2_method());
+  if (ssl_context == NULL) {
+    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,
+                             pem_cert_chain, pem_cert_chain_size, cipher_list);
+    if (result != TSI_OK) break;
+    result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs,
+                                             pem_root_certs_size, NULL);
+    if (result != TSI_OK) {
+      gpr_log(GPR_ERROR, "Cannot load server root certificates.");
+      break;
+    }
+
+    if (num_alpn_protocols != 0) {
+      result = build_alpn_protocol_name_list(
+          alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
+          &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));
+        break;
+      }
+#if TSI_OPENSSL_ALPN_SUPPORT
+      GPR_ASSERT(impl->alpn_protocol_list_length < UINT_MAX);
+      if (SSL_CTX_set_alpn_protos(
+              ssl_context, impl->alpn_protocol_list,
+              (unsigned int)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_client_handshaker_factory_destroy(&impl->base);
+    return result;
+  }
+  SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL);
+  /* TODO(jboeuf): Add revocation verification. */
+
+  impl->base.create_handshaker =
+      ssl_client_handshaker_factory_create_handshaker;
+  impl->base.destroy = ssl_client_handshaker_factory_destroy;
+  *factory = &impl->base;
+  return TSI_OK;
+}
+
+tsi_result tsi_create_ssl_server_handshaker_factory(
+    const unsigned char **pem_private_keys,
+    const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains,
+    const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count,
+    const unsigned char *pem_client_root_certs,
+    size_t pem_client_root_certs_size, int force_client_auth,
+    const char *cipher_list, const unsigned char **alpn_protocols,
+    const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
+    tsi_ssl_handshaker_factory **factory) {
+  tsi_ssl_server_handshaker_factory *impl = NULL;
+  tsi_result result = TSI_OK;
+  size_t i = 0;
+
+  gpr_once_init(&init_openssl_once, init_openssl);
+
+  if (factory == NULL) return TSI_INVALID_ARGUMENT;
+  *factory = NULL;
+  if (key_cert_pair_count == 0 || pem_private_keys == NULL ||
+      pem_cert_chains == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+
+  impl = calloc(1, sizeof(tsi_ssl_server_handshaker_factory));
+  if (impl == NULL) return TSI_OUT_OF_RESOURCES;
+  impl->base.create_handshaker =
+      ssl_server_handshaker_factory_create_handshaker;
+  impl->base.destroy = ssl_server_handshaker_factory_destroy;
+  impl->ssl_contexts = calloc(key_cert_pair_count, sizeof(SSL_CTX *));
+  impl->ssl_context_x509_subject_names =
+      calloc(key_cert_pair_count, sizeof(tsi_peer));
+  if (impl->ssl_contexts == NULL ||
+      impl->ssl_context_x509_subject_names == NULL) {
+    tsi_ssl_handshaker_factory_destroy(&impl->base);
+    return TSI_OUT_OF_RESOURCES;
+  }
+  impl->ssl_context_count = key_cert_pair_count;
+
+  if (num_alpn_protocols > 0) {
+    result = build_alpn_protocol_name_list(
+        alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
+        &impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
+    if (result != TSI_OK) {
+      tsi_ssl_handshaker_factory_destroy(&impl->base);
+      return result;
+    }
+  }
+
+  for (i = 0; i < key_cert_pair_count; i++) {
+    do {
+      impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
+      if (impl->ssl_contexts[i] == NULL) {
+        gpr_log(GPR_ERROR, "Could not create ssl context.");
+        result = TSI_OUT_OF_RESOURCES;
+        break;
+      }
+      result = populate_ssl_context(
+          impl->ssl_contexts[i], pem_private_keys[i], pem_private_keys_sizes[i],
+          pem_cert_chains[i], pem_cert_chains_sizes[i], cipher_list);
+      if (result != TSI_OK) break;
+
+      if (pem_client_root_certs != NULL) {
+        int flags = SSL_VERIFY_PEER;
+        STACK_OF(X509_NAME) *root_names = NULL;
+        result = ssl_ctx_load_verification_certs(
+            impl->ssl_contexts[i], pem_client_root_certs,
+            pem_client_root_certs_size, &root_names);
+        if (result != TSI_OK) {
+          gpr_log(GPR_ERROR, "Invalid verification certs.");
+          break;
+        }
+        SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names);
+        if (force_client_auth) flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+        SSL_CTX_set_verify(impl->ssl_contexts[i], flags, NULL);
+        /* TODO(jboeuf): Add revocation verification. */
+      }
+
+      result = extract_x509_subject_names_from_pem_cert(
+          pem_cert_chains[i], pem_cert_chains_sizes[i],
+          &impl->ssl_context_x509_subject_names[i]);
+      if (result != TSI_OK) break;
+
+      SSL_CTX_set_tlsext_servername_callback(
+          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) {
+      tsi_ssl_handshaker_factory_destroy(&impl->base);
+      return result;
+    }
+  }
+  *factory = &impl->base;
+  return TSI_OK;
+}
+
+/* --- tsi_ssl utils. --- */
+
+int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name) {
+  size_t i = 0;
+  size_t san_count = 0;
+  const tsi_peer_property *cn_property = NULL;
+  int like_ip = looks_like_ip_address(name);
+
+  /* Check the SAN first. */
+  for (i = 0; i < peer->property_count; i++) {
+    const tsi_peer_property *property = &peer->properties[i];
+    if (property->name == NULL) continue;
+    if (strcmp(property->name,
+               TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
+      san_count++;
+
+      if (!like_ip && does_entry_match_name(property->value.data,
+                                            property->value.length, name)) {
+        return 1;
+      } else if (like_ip &&
+                 strncmp(name, property->value.data, property->value.length) ==
+                     0 &&
+                 strlen(name) == property->value.length) {
+        /* IP Addresses are exact matches only. */
+        return 1;
+      }
+    } else if (strcmp(property->name,
+                      TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
+      cn_property = property;
+    }
+  }
+
+  /* If there's no SAN, try the CN, but only if its not like an IP Address */
+  if (san_count == 0 && cn_property != NULL && !like_ip) {
+    if (does_entry_match_name(cn_property->value.data,
+                              cn_property->value.length, name)) {
+      return 1;
+    }
+  }
+
+  return 0; /* Not found. */
+}
diff --git a/src/core/lib/tsi/ssl_transport_security.h b/src/core/lib/tsi/ssl_transport_security.h
new file mode 100644
index 0000000..c9b9e8f
--- /dev/null
+++ b/src/core/lib/tsi/ssl_transport_security.h
@@ -0,0 +1,174 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TSI_SSL_TRANSPORT_SECURITY_H
+#define GRPC_CORE_LIB_TSI_SSL_TRANSPORT_SECURITY_H
+
+#include "src/core/lib/tsi/transport_security_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */
+#define TSI_X509_CERTIFICATE_TYPE "X509"
+
+/* This property is of type TSI_PEER_PROPERTY_STRING.  */
+#define TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY "x509_subject_common_name"
+#define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \
+  "x509_subject_alternative_name"
+
+#define TSI_X509_PEM_CERT_PROPERTY "x509_pem_cert"
+
+#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
+
+/* --- tsi_ssl_handshaker_factory object ---
+
+   This object creates tsi_handshaker objects implemented in terms of the
+   TLS 1.2 specificiation.  */
+
+typedef struct tsi_ssl_handshaker_factory tsi_ssl_handshaker_factory;
+
+/* Creates a client handshaker factory.
+   - pem_private_key is the buffer containing the PEM encoding of the client's
+     private key. This parameter can be NULL if the client does not have a
+     private key.
+   - pem_private_key_size is the size of the associated buffer.
+   - pem_cert_chain is the buffer containing the PEM encoding of the client's
+     certificate chain. This parameter can be NULL if the client does not have
+     a certificate chain.
+   - pem_cert_chain_size is the size of the associated buffer.
+   - pem_roots_cert is the buffer containing the PEM encoding of the server
+     root certificates. This parameter cannot be NULL.
+   - pem_roots_cert_size is the size of the associated buffer.
+   - cipher_suites contains an optional list of the ciphers that the client
+     supports. The format of this string is described in:
+     https://www.openssl.org/docs/apps/ciphers.html.
+     This parameter can be set to NULL to use the default set of ciphers.
+     TODO(jboeuf): Revisit the format of this parameter.
+   - alpn_protocols is an array containing the protocol names that the
+     handshakers created with this factory support. This parameter can be NULL.
+   - alpn_protocols_lengths is an array containing the lengths of the alpn
+     protocols specified in alpn_protocols. This parameter can be NULL.
+   - num_alpn_protocols is the number of alpn protocols and associated lengths
+     specified. If this parameter is 0, the other alpn parameters must be NULL.
+   - factory is the address of the factory pointer to be created.
+
+   - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
+     where a parameter is invalid.  */
+tsi_result tsi_create_ssl_client_handshaker_factory(
+    const unsigned char *pem_private_key, size_t pem_private_key_size,
+    const unsigned char *pem_cert_chain, size_t pem_cert_chain_size,
+    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
+    const char *cipher_suites, const unsigned char **alpn_protocols,
+    const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
+    tsi_ssl_handshaker_factory **factory);
+
+/* Creates a server handshaker factory.
+   - version indicates which version of the specification to use.
+   - pem_private_keys is an array containing the PEM encoding of the server's
+     private keys.  This parameter cannot be NULL. The size of the array is
+     given by the key_cert_pair_count parameter.
+   - pem_private_keys_sizes is the array containing the sizes of the associated
+     buffers.
+   - pem_cert_chains is an array containing the PEM encoding of the server's
+     cert chains.  This parameter cannot be NULL. The size of the array is
+     given by the key_cert_pair_count parameter.
+   - pem_cert_chains_sizes is the array containing the sizes of the associated
+     buffers.
+   - key_cert_pair_count indicates the number of items in the private_key_files
+     and cert_chain_files parameters.
+   - pem_client_roots is the buffer containing the PEM encoding of the client
+     root certificates. This parameter may be NULL in which case the server will
+     not authenticate the client. If not NULL, the force_client_auth parameter
+     specifies if the server will accept only authenticated clients or both
+     authenticated and non-authenticated clients.
+   - pem_client_root_certs_size is the size of the associated buffer.
+   - force_client_auth, if set to non-zero will force the client to authenticate
+     with an SSL cert. Note that this option is ignored if pem_client_root_certs
+     is NULL or pem_client_roots_certs_size is 0
+   - cipher_suites contains an optional list of the ciphers that the server
+     supports. The format of this string is described in:
+     https://www.openssl.org/docs/apps/ciphers.html.
+     This parameter can be set to NULL to use the default set of ciphers.
+     TODO(jboeuf): Revisit the format of this parameter.
+   - alpn_protocols is an array containing the protocol names that the
+     handshakers created with this factory support. This parameter can be NULL.
+   - alpn_protocols_lengths is an array containing the lengths of the alpn
+     protocols specified in alpn_protocols. This parameter can be NULL.
+   - num_alpn_protocols is the number of alpn protocols and associated lengths
+     specified. If this parameter is 0, the other alpn parameters must be NULL.
+   - factory is the address of the factory pointer to be created.
+
+   - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
+     where a parameter is invalid.  */
+tsi_result tsi_create_ssl_server_handshaker_factory(
+    const unsigned char **pem_private_keys,
+    const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains,
+    const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count,
+    const unsigned char *pem_client_root_certs,
+    size_t pem_client_root_certs_size, int force_client_auth,
+    const char *cipher_suites, const unsigned char **alpn_protocols,
+    const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
+    tsi_ssl_handshaker_factory **factory);
+
+/* Creates a handshaker.
+  - self is the factory from which the handshaker will be created.
+  - server_name_indication indicates the name of the server the client is
+    trying to connect to which will be relayed to the server using the SNI
+    extension.
+    This parameter must be NULL for a server handshaker factory.
+  - handhshaker is the address of the handshaker pointer to be created.
+
+  - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
+    where a parameter is invalid.  */
+tsi_result tsi_ssl_handshaker_factory_create_handshaker(
+    tsi_ssl_handshaker_factory *self, const char *server_name_indication,
+    tsi_handshaker **handshaker);
+
+/* Destroys the handshaker factory. WARNING: it is unsafe to destroy a factory
+   while handshakers created with this factory are still in use.  */
+void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self);
+
+/* Util that checks that an ssl peer matches a specific name.
+   Still TODO(jboeuf):
+   - handle mixed case.
+   - handle %encoded chars.
+   - handle public suffix wildchar more strictly (e.g. *.co.uk) */
+int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_TSI_SSL_TRANSPORT_SECURITY_H */
diff --git a/src/core/lib/tsi/ssl_types.h b/src/core/lib/tsi/ssl_types.h
new file mode 100644
index 0000000..c6e68c0
--- /dev/null
+++ b/src/core/lib/tsi/ssl_types.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TSI_SSL_TYPES_H
+#define GRPC_CORE_LIB_TSI_SSL_TYPES_H
+
+/* A collection of macros to cast between various integer types that are
+ * used differently between BoringSSL and OpenSSL:
+ * TSI_INT_AS_SIZE(x):  convert 'int x' to a length parameter for an OpenSSL
+ *                      function
+ * TSI_SIZE_AS_SIZE(x): convert 'size_t x' to a length parameter for an OpenSSL
+ *                      function
+ */
+
+#include <openssl/ssl.h>
+
+#ifdef OPENSSL_IS_BORINGSSL
+#define TSI_INT_AS_SIZE(x) ((size_t)(x))
+#define TSI_SIZE_AS_SIZE(x) (x)
+#else
+#define TSI_INT_AS_SIZE(x) (x)
+#define TSI_SIZE_AS_SIZE(x) ((int)(x))
+#endif
+
+#endif /* GRPC_CORE_LIB_TSI_SSL_TYPES_H */
diff --git a/src/core/tsi/test_creds/README b/src/core/lib/tsi/test_creds/README
similarity index 100%
rename from src/core/tsi/test_creds/README
rename to src/core/lib/tsi/test_creds/README
diff --git a/src/core/tsi/test_creds/badclient.key b/src/core/lib/tsi/test_creds/badclient.key
similarity index 100%
rename from src/core/tsi/test_creds/badclient.key
rename to src/core/lib/tsi/test_creds/badclient.key
diff --git a/src/core/tsi/test_creds/badclient.pem b/src/core/lib/tsi/test_creds/badclient.pem
similarity index 100%
rename from src/core/tsi/test_creds/badclient.pem
rename to src/core/lib/tsi/test_creds/badclient.pem
diff --git a/src/core/tsi/test_creds/badserver.key b/src/core/lib/tsi/test_creds/badserver.key
similarity index 100%
rename from src/core/tsi/test_creds/badserver.key
rename to src/core/lib/tsi/test_creds/badserver.key
diff --git a/src/core/tsi/test_creds/badserver.pem b/src/core/lib/tsi/test_creds/badserver.pem
similarity index 100%
rename from src/core/tsi/test_creds/badserver.pem
rename to src/core/lib/tsi/test_creds/badserver.pem
diff --git a/src/core/tsi/test_creds/ca-openssl.cnf b/src/core/lib/tsi/test_creds/ca-openssl.cnf
similarity index 100%
rename from src/core/tsi/test_creds/ca-openssl.cnf
rename to src/core/lib/tsi/test_creds/ca-openssl.cnf
diff --git a/src/core/tsi/test_creds/ca.key b/src/core/lib/tsi/test_creds/ca.key
similarity index 100%
rename from src/core/tsi/test_creds/ca.key
rename to src/core/lib/tsi/test_creds/ca.key
diff --git a/src/core/tsi/test_creds/ca.pem b/src/core/lib/tsi/test_creds/ca.pem
similarity index 100%
rename from src/core/tsi/test_creds/ca.pem
rename to src/core/lib/tsi/test_creds/ca.pem
diff --git a/src/core/tsi/test_creds/client.key b/src/core/lib/tsi/test_creds/client.key
similarity index 100%
rename from src/core/tsi/test_creds/client.key
rename to src/core/lib/tsi/test_creds/client.key
diff --git a/src/core/tsi/test_creds/client.pem b/src/core/lib/tsi/test_creds/client.pem
similarity index 100%
rename from src/core/tsi/test_creds/client.pem
rename to src/core/lib/tsi/test_creds/client.pem
diff --git a/src/core/tsi/test_creds/server0.key b/src/core/lib/tsi/test_creds/server0.key
similarity index 100%
rename from src/core/tsi/test_creds/server0.key
rename to src/core/lib/tsi/test_creds/server0.key
diff --git a/src/core/tsi/test_creds/server0.pem b/src/core/lib/tsi/test_creds/server0.pem
similarity index 100%
rename from src/core/tsi/test_creds/server0.pem
rename to src/core/lib/tsi/test_creds/server0.pem
diff --git a/src/core/tsi/test_creds/server1-openssl.cnf b/src/core/lib/tsi/test_creds/server1-openssl.cnf
similarity index 100%
rename from src/core/tsi/test_creds/server1-openssl.cnf
rename to src/core/lib/tsi/test_creds/server1-openssl.cnf
diff --git a/src/core/tsi/test_creds/server1.key b/src/core/lib/tsi/test_creds/server1.key
similarity index 100%
rename from src/core/tsi/test_creds/server1.key
rename to src/core/lib/tsi/test_creds/server1.key
diff --git a/src/core/tsi/test_creds/server1.pem b/src/core/lib/tsi/test_creds/server1.pem
similarity index 100%
rename from src/core/tsi/test_creds/server1.pem
rename to src/core/lib/tsi/test_creds/server1.pem
diff --git a/src/core/lib/tsi/transport_security.c b/src/core/lib/tsi/transport_security.c
new file mode 100644
index 0000000..a2c0d46
--- /dev/null
+++ b/src/core/lib/tsi/transport_security.c
@@ -0,0 +1,284 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/tsi/transport_security.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* --- Tracing. --- */
+
+int tsi_tracing_enabled = 0;
+
+/* --- Utils. --- */
+
+char *tsi_strdup(const char *src) {
+  char *dst;
+  size_t len;
+  if (!src) return NULL;
+  len = strlen(src) + 1;
+  dst = malloc(len);
+  if (!dst) return NULL;
+  memcpy(dst, src, len);
+  return dst;
+}
+
+/* --- tsi_result common implementation. --- */
+
+const char *tsi_result_to_string(tsi_result result) {
+  switch (result) {
+    case TSI_OK:
+      return "TSI_OK";
+    case TSI_UNKNOWN_ERROR:
+      return "TSI_UNKNOWN_ERROR";
+    case TSI_INVALID_ARGUMENT:
+      return "TSI_INVALID_ARGUMENT";
+    case TSI_PERMISSION_DENIED:
+      return "TSI_PERMISSION_DENIED";
+    case TSI_INCOMPLETE_DATA:
+      return "TSI_INCOMPLETE_DATA";
+    case TSI_FAILED_PRECONDITION:
+      return "TSI_FAILED_PRECONDITION";
+    case TSI_UNIMPLEMENTED:
+      return "TSI_UNIMPLEMENTED";
+    case TSI_INTERNAL_ERROR:
+      return "TSI_INTERNAL_ERROR";
+    case TSI_DATA_CORRUPTED:
+      return "TSI_DATA_CORRUPTED";
+    case TSI_NOT_FOUND:
+      return "TSI_NOT_FOUND";
+    case TSI_PROTOCOL_FAILURE:
+      return "TSI_PROTOCOL_FAILURE";
+    case TSI_HANDSHAKE_IN_PROGRESS:
+      return "TSI_HANDSHAKE_IN_PROGRESS";
+    case TSI_OUT_OF_RESOURCES:
+      return "TSI_OUT_OF_RESOURCES";
+    default:
+      return "UNKNOWN";
+  }
+}
+
+/* --- tsi_frame_protector common implementation. ---
+
+   Calls specific implementation after state/input validation. */
+
+tsi_result tsi_frame_protector_protect(tsi_frame_protector *self,
+                                       const unsigned char *unprotected_bytes,
+                                       size_t *unprotected_bytes_size,
+                                       unsigned char *protected_output_frames,
+                                       size_t *protected_output_frames_size) {
+  if (self == NULL || unprotected_bytes == NULL ||
+      unprotected_bytes_size == NULL || protected_output_frames == NULL ||
+      protected_output_frames_size == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size,
+                               protected_output_frames,
+                               protected_output_frames_size);
+}
+
+tsi_result tsi_frame_protector_protect_flush(
+    tsi_frame_protector *self, unsigned char *protected_output_frames,
+    size_t *protected_output_frames_size, size_t *still_pending_size) {
+  if (self == NULL || protected_output_frames == NULL ||
+      protected_output_frames == NULL || still_pending_size == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  return self->vtable->protect_flush(self, protected_output_frames,
+                                     protected_output_frames_size,
+                                     still_pending_size);
+}
+
+tsi_result tsi_frame_protector_unprotect(
+    tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
+    size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
+    size_t *unprotected_bytes_size) {
+  if (self == NULL || protected_frames_bytes == NULL ||
+      protected_frames_bytes_size == NULL || unprotected_bytes == NULL ||
+      unprotected_bytes_size == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  return self->vtable->unprotect(self, protected_frames_bytes,
+                                 protected_frames_bytes_size, unprotected_bytes,
+                                 unprotected_bytes_size);
+}
+
+void tsi_frame_protector_destroy(tsi_frame_protector *self) {
+  if (self == NULL) return;
+  self->vtable->destroy(self);
+}
+
+/* --- tsi_handshaker common implementation. ---
+
+   Calls specific implementation after state/input validation. */
+
+tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
+                                                    unsigned char *bytes,
+                                                    size_t *bytes_size) {
+  if (self == NULL || bytes == NULL || bytes_size == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
+  return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
+}
+
+tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self,
+                                                  const unsigned char *bytes,
+                                                  size_t *bytes_size) {
+  if (self == NULL || bytes == NULL || bytes_size == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
+  return self->vtable->process_bytes_from_peer(self, bytes, bytes_size);
+}
+
+tsi_result tsi_handshaker_get_result(tsi_handshaker *self) {
+  if (self == NULL) return TSI_INVALID_ARGUMENT;
+  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
+  return self->vtable->get_result(self);
+}
+
+tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer) {
+  if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT;
+  memset(peer, 0, sizeof(tsi_peer));
+  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
+  if (tsi_handshaker_get_result(self) != TSI_OK) {
+    return TSI_FAILED_PRECONDITION;
+  }
+  return self->vtable->extract_peer(self, peer);
+}
+
+tsi_result tsi_handshaker_create_frame_protector(
+    tsi_handshaker *self, size_t *max_protected_frame_size,
+    tsi_frame_protector **protector) {
+  tsi_result result;
+  if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT;
+  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
+  if (tsi_handshaker_get_result(self) != TSI_OK) {
+    return TSI_FAILED_PRECONDITION;
+  }
+  result = self->vtable->create_frame_protector(self, max_protected_frame_size,
+                                                protector);
+  if (result == TSI_OK) {
+    self->frame_protector_created = 1;
+  }
+  return result;
+}
+
+void tsi_handshaker_destroy(tsi_handshaker *self) {
+  if (self == NULL) return;
+  self->vtable->destroy(self);
+}
+
+/* --- tsi_peer implementation. --- */
+
+tsi_peer_property tsi_init_peer_property(void) {
+  tsi_peer_property property;
+  memset(&property, 0, sizeof(tsi_peer_property));
+  return property;
+}
+
+static void tsi_peer_destroy_list_property(tsi_peer_property *children,
+                                           size_t child_count) {
+  size_t i;
+  for (i = 0; i < child_count; i++) {
+    tsi_peer_property_destruct(&children[i]);
+  }
+  free(children);
+}
+
+void tsi_peer_property_destruct(tsi_peer_property *property) {
+  if (property->name != NULL) {
+    free(property->name);
+  }
+  if (property->value.data != NULL) {
+    free(property->value.data);
+  }
+  *property = tsi_init_peer_property(); /* Reset everything to 0. */
+}
+
+void tsi_peer_destruct(tsi_peer *self) {
+  if (self == NULL) return;
+  if (self->properties != NULL) {
+    tsi_peer_destroy_list_property(self->properties, self->property_count);
+    self->properties = NULL;
+  }
+  self->property_count = 0;
+}
+
+tsi_result tsi_construct_allocated_string_peer_property(
+    const char *name, size_t value_length, tsi_peer_property *property) {
+  *property = tsi_init_peer_property();
+  if (name != NULL) {
+    property->name = tsi_strdup(name);
+    if (property->name == NULL) return TSI_OUT_OF_RESOURCES;
+  }
+  if (value_length > 0) {
+    property->value.data = calloc(1, value_length);
+    if (property->value.data == NULL) {
+      tsi_peer_property_destruct(property);
+      return TSI_OUT_OF_RESOURCES;
+    }
+    property->value.length = value_length;
+  }
+  return TSI_OK;
+}
+
+tsi_result tsi_construct_string_peer_property_from_cstring(
+    const char *name, const char *value, tsi_peer_property *property) {
+  return tsi_construct_string_peer_property(name, value, strlen(value),
+                                            property);
+}
+
+tsi_result tsi_construct_string_peer_property(const char *name,
+                                              const char *value,
+                                              size_t value_length,
+                                              tsi_peer_property *property) {
+  tsi_result result = tsi_construct_allocated_string_peer_property(
+      name, value_length, property);
+  if (result != TSI_OK) return result;
+  if (value_length > 0) {
+    memcpy(property->value.data, value, value_length);
+  }
+  return TSI_OK;
+}
+
+tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer) {
+  memset(peer, 0, sizeof(tsi_peer));
+  if (property_count > 0) {
+    peer->properties = calloc(property_count, sizeof(tsi_peer_property));
+    if (peer->properties == NULL) return TSI_OUT_OF_RESOURCES;
+    peer->property_count = property_count;
+  }
+  return TSI_OK;
+}
diff --git a/src/core/lib/tsi/transport_security.h b/src/core/lib/tsi/transport_security.h
new file mode 100644
index 0000000..349dd0a
--- /dev/null
+++ b/src/core/lib/tsi/transport_security.h
@@ -0,0 +1,111 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_H
+#define GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_H
+
+#include "src/core/lib/tsi/transport_security_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int tsi_tracing_enabled;
+
+/* Base for tsi_frame_protector implementations.
+   See transport_security_interface.h for documentation. */
+typedef struct {
+  tsi_result (*protect)(tsi_frame_protector *self,
+                        const unsigned char *unprotected_bytes,
+                        size_t *unprotected_bytes_size,
+                        unsigned char *protected_output_frames,
+                        size_t *protected_output_frames_size);
+  tsi_result (*protect_flush)(tsi_frame_protector *self,
+                              unsigned char *protected_output_frames,
+                              size_t *protected_output_frames_size,
+                              size_t *still_pending_size);
+  tsi_result (*unprotect)(tsi_frame_protector *self,
+                          const unsigned char *protected_frames_bytes,
+                          size_t *protected_frames_bytes_size,
+                          unsigned char *unprotected_bytes,
+                          size_t *unprotected_bytes_size);
+  void (*destroy)(tsi_frame_protector *self);
+} tsi_frame_protector_vtable;
+
+struct tsi_frame_protector {
+  const tsi_frame_protector_vtable *vtable;
+};
+
+/* Base for tsi_handshaker implementations.
+   See transport_security_interface.h for documentation. */
+typedef struct {
+  tsi_result (*get_bytes_to_send_to_peer)(tsi_handshaker *self,
+                                          unsigned char *bytes,
+                                          size_t *bytes_size);
+  tsi_result (*process_bytes_from_peer)(tsi_handshaker *self,
+                                        const unsigned char *bytes,
+                                        size_t *bytes_size);
+  tsi_result (*get_result)(tsi_handshaker *self);
+  tsi_result (*extract_peer)(tsi_handshaker *self, tsi_peer *peer);
+  tsi_result (*create_frame_protector)(tsi_handshaker *self,
+                                       size_t *max_protected_frame_size,
+                                       tsi_frame_protector **protector);
+  void (*destroy)(tsi_handshaker *self);
+} tsi_handshaker_vtable;
+
+struct tsi_handshaker {
+  const tsi_handshaker_vtable *vtable;
+  int frame_protector_created;
+};
+
+/* Peer and property construction/destruction functions. */
+tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer);
+tsi_peer_property tsi_init_peer_property(void);
+void tsi_peer_property_destruct(tsi_peer_property *property);
+tsi_result tsi_construct_string_peer_property(const char *name,
+                                              const char *value,
+                                              size_t value_length,
+                                              tsi_peer_property *property);
+tsi_result tsi_construct_allocated_string_peer_property(
+    const char *name, size_t value_length, tsi_peer_property *property);
+tsi_result tsi_construct_string_peer_property_from_cstring(
+    const char *name, const char *value, tsi_peer_property *property);
+
+/* Utils. */
+char *tsi_strdup(const char *src); /* Sadly, no strdup in C89. */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_H */
diff --git a/src/core/lib/tsi/transport_security_interface.h b/src/core/lib/tsi/transport_security_interface.h
new file mode 100644
index 0000000..f88f151
--- /dev/null
+++ b/src/core/lib/tsi/transport_security_interface.h
@@ -0,0 +1,344 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_INTERFACE_H
+#define GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_INTERFACE_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* --- tsi result ---  */
+
+typedef enum {
+  TSI_OK = 0,
+  TSI_UNKNOWN_ERROR = 1,
+  TSI_INVALID_ARGUMENT = 2,
+  TSI_PERMISSION_DENIED = 3,
+  TSI_INCOMPLETE_DATA = 4,
+  TSI_FAILED_PRECONDITION = 5,
+  TSI_UNIMPLEMENTED = 6,
+  TSI_INTERNAL_ERROR = 7,
+  TSI_DATA_CORRUPTED = 8,
+  TSI_NOT_FOUND = 9,
+  TSI_PROTOCOL_FAILURE = 10,
+  TSI_HANDSHAKE_IN_PROGRESS = 11,
+  TSI_OUT_OF_RESOURCES = 12
+} tsi_result;
+
+const char *tsi_result_to_string(tsi_result result);
+
+/* --- tsi tracing --- */
+
+/* Set this early to avoid races */
+extern int tsi_tracing_enabled;
+
+/* --- tsi_frame_protector object ---
+
+  This object protects and unprotects buffers once the handshake is done.
+  Implementations of this object must be thread compatible.  */
+
+typedef struct tsi_frame_protector tsi_frame_protector;
+
+/* Outputs protected frames.
+   - unprotected_bytes is an input only parameter and points to the data
+     to be protected.
+   - unprotected_bytes_size is an input/output parameter used by the caller to
+     specify how many bytes are available in unprotected_bytes. The output
+     value is the number of bytes consumed during the call.
+   - protected_output_frames points to a buffer allocated by the caller that
+     will be written.
+   - protected_output_frames_size is an input/output parameter used by the
+     caller to specify how many bytes are available in protected_output_frames.
+     As an output, this value indicates the number of bytes written.
+   - This method returns TSI_OK in case of success or a specific error code in
+     case of failure. Note that even if all the input unprotected bytes are
+     consumed, they may not have been processed into the returned protected
+     output frames. The caller should call the protect_flush method
+     to make sure that there are no more protected bytes buffered in the
+     protector.
+
+   A typical way to call this method would be:
+
+   ------------------------------------------------------------------------
+   unsigned char protected_buffer[4096];
+   size_t protected_buffer_size = sizeof(protected_buffer);
+   tsi_result result = TSI_OK;
+   while (message_size > 0) {
+     size_t protected_buffer_size_to_send = protected_buffer_size;
+     size_t processed_message_size = message_size;
+     result = tsi_frame_protector_protect(protector,
+                                          message_bytes,
+                                          &processed_message_size,
+                                          protected_buffer,
+                                          &protected_buffer_size_to_send);
+     if (result != TSI_OK) break;
+     send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send);
+     message_bytes += processed_message_size;
+     message_size -= processed_message_size;
+
+     // Don't forget to flush.
+     if (message_size == 0) {
+       size_t still_pending_size;
+       do {
+         protected_buffer_size_to_send = protected_buffer_size;
+         result = tsi_frame_protector_protect_flush(
+             protector, protected_buffer,
+             &protected_buffer_size_to_send, &still_pending_size);
+         if (result != TSI_OK) break;
+         send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send);
+       } while (still_pending_size > 0);
+     }
+   }
+
+   if (result != TSI_OK) HandleError(result);
+   ------------------------------------------------------------------------  */
+tsi_result tsi_frame_protector_protect(tsi_frame_protector *self,
+                                       const unsigned char *unprotected_bytes,
+                                       size_t *unprotected_bytes_size,
+                                       unsigned char *protected_output_frames,
+                                       size_t *protected_output_frames_size);
+
+/* Indicates that we need to flush the bytes buffered in the protector and get
+   the resulting frame.
+   - protected_output_frames points to a buffer allocated by the caller that
+     will be written.
+   - protected_output_frames_size is an input/output parameter used by the
+     caller to specify how many bytes are available in protected_output_frames.
+   - still_pending_bytes is an output parameter indicating the number of bytes
+     that still need to be flushed from the protector.*/
+tsi_result tsi_frame_protector_protect_flush(
+    tsi_frame_protector *self, unsigned char *protected_output_frames,
+    size_t *protected_output_frames_size, size_t *still_pending_size);
+
+/* Outputs unprotected bytes.
+   - protected_frames_bytes is an input only parameter and points to the
+     protected frames to be unprotected.
+   - protected_frames_bytes_size is an input/output only parameter used by the
+     caller to specify how many bytes are available in protected_bytes. The
+     output value is the number of bytes consumed during the call.
+     Implementations will buffer up to a frame of protected data.
+   - unprotected_bytes points to a buffer allocated by the caller that will be
+     written.
+   - unprotected_bytes_size is an input/output parameter used by the caller to
+     specify how many bytes are available in unprotected_bytes. This
+     value is expected to be at most max_protected_frame_size minus overhead
+     which means that max_protected_frame_size is a safe bet. The output value
+     is the number of bytes actually written.
+     If *unprotected_bytes_size is unchanged, there may be more data remaining
+     to unprotect, and the caller should call this function again.
+
+   - This method returns TSI_OK in case of success. Success includes cases where
+     there is not enough data to output a frame in which case
+     unprotected_bytes_size will be set to 0 and cases where the internal buffer
+     needs to be read before new protected data can be processed in which case
+     protected_frames_size will be set to 0.  */
+tsi_result tsi_frame_protector_unprotect(
+    tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
+    size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
+    size_t *unprotected_bytes_size);
+
+/* Destroys the tsi_frame_protector object.  */
+void tsi_frame_protector_destroy(tsi_frame_protector *self);
+
+/* --- tsi_peer objects ---
+
+   tsi_peer objects are a set of properties. The peer owns the properties.  */
+
+/* This property is of type TSI_PEER_PROPERTY_STRING.  */
+#define TSI_CERTIFICATE_TYPE_PEER_PROPERTY "certificate_type"
+
+/* Property values may contain NULL characters just like C++ strings.
+   The length field gives the length of the string. */
+typedef struct tsi_peer_property {
+  char *name;
+  struct {
+    char *data;
+    size_t length;
+  } value;
+} tsi_peer_property;
+
+typedef struct {
+  tsi_peer_property *properties;
+  size_t property_count;
+} tsi_peer;
+
+/* Destructs the tsi_peer object. */
+void tsi_peer_destruct(tsi_peer *self);
+
+/* --- tsi_handshaker objects ----
+
+   Implementations of this object must be thread compatible.
+
+   A typical usage of this object would be:
+
+   ------------------------------------------------------------------------
+   tsi_result result = TSI_OK;
+   unsigned char buf[4096];
+   size_t buf_offset;
+   size_t buf_size;
+   while (1) {
+     // See if we need to send some bytes to the peer.
+     do {
+       size_t buf_size_to_send = sizeof(buf);
+       result = tsi_handshaker_get_bytes_to_send_to_peer(handshaker, buf,
+                                                         &buf_size_to_send);
+       if (buf_size_to_send > 0) send_bytes_to_peer(buf, buf_size_to_send);
+     } while (result == TSI_INCOMPLETE_DATA);
+     if (result != TSI_OK) return result;
+     if (!tsi_handshaker_is_in_progress(handshaker)) break;
+
+     do {
+       // Read bytes from the peer.
+       buf_size = sizeof(buf);
+       buf_offset = 0;
+       read_bytes_from_peer(buf, &buf_size);
+       if (buf_size == 0) break;
+
+       // Process the bytes from the peer. We have to be careful as these bytes
+       // may contain non-handshake data (protected data). If this is the case,
+       // we will exit from the loop with buf_size > 0.
+       size_t consumed_by_handshaker = buf_size;
+       result = tsi_handshaker_process_bytes_from_peer(
+           handshaker, buf, &consumed_by_handshaker);
+       buf_size -= consumed_by_handshaker;
+       buf_offset += consumed_by_handshaker;
+     } while (result == TSI_INCOMPLETE_DATA);
+
+     if (result != TSI_OK) return result;
+     if (!tsi_handshaker_is_in_progress(handshaker)) break;
+   }
+
+   // Check the Peer.
+   tsi_peer peer;
+   do {
+     result = tsi_handshaker_extract_peer(handshaker, &peer);
+     if (result != TSI_OK) break;
+     result = check_peer(&peer);
+   } while (0);
+   tsi_peer_destruct(&peer);
+   if (result != TSI_OK) return result;
+
+   // Create the protector.
+   tsi_frame_protector* protector = NULL;
+   result = tsi_handshaker_create_frame_protector(handshaker, NULL,
+                                                  &protector);
+   if (result != TSI_OK) return result;
+
+   // Do not forget to unprotect outstanding data if any.
+   if (buf_size > 0) {
+     result = tsi_frame_protector_unprotect(protector, buf + buf_offset,
+                                            buf_size, ..., ...);
+     ....
+   }
+   ...
+   ------------------------------------------------------------------------   */
+typedef struct tsi_handshaker tsi_handshaker;
+
+/* Gets bytes that need to be sent to the peer.
+   - bytes is the buffer that will be written with the data to be sent to the
+     peer.
+   - bytes_size is an input/output parameter specifying the capacity of the
+     bytes parameter as input and the number of bytes written as output.
+   Returns TSI_OK if all the data to send to the peer has been written or if
+   nothing has to be sent to the peer (in which base bytes_size outputs to 0),
+   otherwise returns TSI_INCOMPLETE_DATA which indicates that this method
+   needs to be called again to get all the bytes to send to the peer (there
+   was more data to write than the specified bytes_size). In case of a fatal
+   error in the handshake, another specific error code is returned.  */
+tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
+                                                    unsigned char *bytes,
+                                                    size_t *bytes_size);
+
+/* Processes bytes received from the peer.
+   - bytes is the buffer containing the data.
+   - bytes_size is an input/output parameter specifying the size of the data as
+     input and the number of bytes consumed as output.
+   Return TSI_OK if the handshake has all the data it needs to process,
+   otherwise return TSI_INCOMPLETE_DATA which indicates that this method
+   needs to be called again to complete the data needed for processing. In
+   case of a fatal error in the handshake, another specific error code is
+   returned.  */
+tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self,
+                                                  const unsigned char *bytes,
+                                                  size_t *bytes_size);
+
+/* Gets the result of the handshaker.
+   Returns TSI_OK if the hanshake completed successfully and there has been no
+   errors. Returns TSI_HANDSHAKE_IN_PROGRESS if the handshaker is not done yet
+   but no error has been encountered so far. Otherwise the handshaker failed
+   with the returned error.  */
+tsi_result tsi_handshaker_get_result(tsi_handshaker *self);
+
+/* Returns 1 if the handshake is in progress, 0 otherwise.  */
+#define tsi_handshaker_is_in_progress(h) \
+  (tsi_handshaker_get_result((h)) == TSI_HANDSHAKE_IN_PROGRESS)
+
+/* This method may return TSI_FAILED_PRECONDITION if
+   tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise
+   assuming the handshaker is not in a fatal error state.
+   The caller is responsible for destructing the peer.  */
+tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer);
+
+/* This method creates a tsi_frame_protector object after the handshake phase
+   is done. After this method has been called successfully, the only method
+   that can be called on this object is Destroy.
+   - max_output_protected_frame_size is an input/output parameter specifying the
+     desired max output protected frame size as input and outputing the actual
+     max output frame size as the output. Passing NULL is OK and will result in
+     the implementation choosing the default maximum protected frame size. Note
+     that this size only applies to outgoing frames (generated with
+     tsi_frame_protector_protect) and not incoming frames (input of
+     tsi_frame_protector_unprotect).
+   - protector is an output parameter pointing to the newly created
+     tsi_frame_protector object.
+   This method may return TSI_FAILED_PRECONDITION if
+   tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise assuming
+   the handshaker is not in a fatal error state.
+   The caller is responsible for destroying the protector.  */
+tsi_result tsi_handshaker_create_frame_protector(
+    tsi_handshaker *self, size_t *max_output_protected_frame_size,
+    tsi_frame_protector **protector);
+
+/* This method releases the tsi_handshaker object. After this method is called,
+   no other method can be called on the object.  */
+void tsi_handshaker_destroy(tsi_handshaker *self);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_INTERFACE_H */
diff --git a/src/core/profiling/basic_timers.c b/src/core/profiling/basic_timers.c
deleted file mode 100644
index df32472..0000000
--- a/src/core/profiling/basic_timers.c
+++ /dev/null
@@ -1,274 +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/support/port_platform.h>
-
-#ifdef GRPC_BASIC_PROFILER
-
-#include "src/core/profiling/timers.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <stdio.h>
-
-typedef enum { BEGIN = '{', END = '}', MARK = '.' } marker_type;
-
-typedef struct gpr_timer_entry {
-  gpr_timespec tm;
-  const char *tagstr;
-  const char *file;
-  short line;
-  char type;
-  uint8_t important;
-  int thd;
-} gpr_timer_entry;
-
-#define MAX_COUNT 1000000
-
-typedef struct gpr_timer_log {
-  size_t num_entries;
-  struct gpr_timer_log *next;
-  struct gpr_timer_log *prev;
-  gpr_timer_entry log[MAX_COUNT];
-} gpr_timer_log;
-
-typedef struct gpr_timer_log_list {
-  gpr_timer_log *head;
-  /* valid iff head!=NULL */
-  gpr_timer_log *tail;
-} gpr_timer_log_list;
-
-static __thread gpr_timer_log *g_thread_log;
-static gpr_once g_once_init = GPR_ONCE_INIT;
-static FILE *output_file;
-static const char *output_filename = "latency_trace.txt";
-static pthread_mutex_t g_mu;
-static pthread_cond_t g_cv;
-static gpr_timer_log_list g_in_progress_logs;
-static gpr_timer_log_list g_done_logs;
-static int g_shutdown;
-static gpr_thd_id g_writing_thread;
-static __thread int g_thread_id;
-static int g_next_thread_id;
-
-static int timer_log_push_back(gpr_timer_log_list *list, gpr_timer_log *log) {
-  if (list->head == NULL) {
-    list->head = list->tail = log;
-    log->next = log->prev = NULL;
-    return 1;
-  } else {
-    log->prev = list->tail;
-    log->next = NULL;
-    list->tail->next = log;
-    list->tail = log;
-    return 0;
-  }
-}
-
-static gpr_timer_log *timer_log_pop_front(gpr_timer_log_list *list) {
-  gpr_timer_log *out = list->head;
-  if (out != NULL) {
-    list->head = out->next;
-    if (list->head != NULL) {
-      list->head->prev = NULL;
-    } else {
-      list->tail = NULL;
-    }
-  }
-  return out;
-}
-
-static void timer_log_remove(gpr_timer_log_list *list, gpr_timer_log *log) {
-  if (log->prev == NULL) {
-    list->head = log->next;
-    if (list->head != NULL) {
-      list->head->prev = NULL;
-    }
-  } else {
-    log->prev->next = log->next;
-  }
-  if (log->next == NULL) {
-    list->tail = log->prev;
-    if (list->tail != NULL) {
-      list->tail->next = NULL;
-    }
-  } else {
-    log->next->prev = log->prev;
-  }
-}
-
-static void write_log(gpr_timer_log *log) {
-  size_t i;
-  if (output_file == NULL) {
-    output_file = fopen(output_filename, "w");
-  }
-  for (i = 0; i < log->num_entries; i++) {
-    gpr_timer_entry *entry = &(log->log[i]);
-    if (gpr_time_cmp(entry->tm, gpr_time_0(entry->tm.clock_type)) < 0) {
-      entry->tm = gpr_time_0(entry->tm.clock_type);
-    }
-    fprintf(output_file,
-            "{\"t\": %lld.%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": "
-            "\"%s\", \"file\": \"%s\", \"line\": %d, \"imp\": %d}\n",
-            (long long)entry->tm.tv_sec, (int)entry->tm.tv_nsec, entry->thd,
-            entry->type, entry->tagstr, entry->file, entry->line,
-            entry->important);
-  }
-}
-
-static void writing_thread(void *unused) {
-  gpr_timer_log *log;
-  pthread_mutex_lock(&g_mu);
-  for (;;) {
-    while ((log = timer_log_pop_front(&g_done_logs)) == NULL && !g_shutdown) {
-      pthread_cond_wait(&g_cv, &g_mu);
-    }
-    if (log != NULL) {
-      pthread_mutex_unlock(&g_mu);
-      write_log(log);
-      free(log);
-      pthread_mutex_lock(&g_mu);
-    }
-    if (g_shutdown) {
-      pthread_mutex_unlock(&g_mu);
-      return;
-    }
-  }
-}
-
-static void flush_logs(gpr_timer_log_list *list) {
-  gpr_timer_log *log;
-  while ((log = timer_log_pop_front(list)) != NULL) {
-    write_log(log);
-    free(log);
-  }
-}
-
-static void finish_writing() {
-  pthread_mutex_lock(&g_mu);
-  g_shutdown = 1;
-  pthread_cond_signal(&g_cv);
-  pthread_mutex_unlock(&g_mu);
-  gpr_thd_join(g_writing_thread);
-
-  gpr_log(GPR_INFO, "flushing logs");
-
-  pthread_mutex_lock(&g_mu);
-  flush_logs(&g_done_logs);
-  flush_logs(&g_in_progress_logs);
-  pthread_mutex_unlock(&g_mu);
-
-  if (output_file) {
-    fclose(output_file);
-  }
-}
-
-void gpr_timers_set_log_filename(const char *filename) {
-  output_filename = filename;
-}
-
-static void init_output() {
-  gpr_thd_options options = gpr_thd_options_default();
-  gpr_thd_options_set_joinable(&options);
-  gpr_thd_new(&g_writing_thread, writing_thread, NULL, &options);
-  atexit(finish_writing);
-}
-
-static void rotate_log() {
-  gpr_timer_log *new = malloc(sizeof(*new));
-  gpr_once_init(&g_once_init, init_output);
-  new->num_entries = 0;
-  pthread_mutex_lock(&g_mu);
-  if (g_thread_log != NULL) {
-    timer_log_remove(&g_in_progress_logs, g_thread_log);
-    if (timer_log_push_back(&g_done_logs, g_thread_log)) {
-      pthread_cond_signal(&g_cv);
-    }
-  } else {
-    g_thread_id = g_next_thread_id++;
-  }
-  timer_log_push_back(&g_in_progress_logs, new);
-  pthread_mutex_unlock(&g_mu);
-  g_thread_log = new;
-}
-
-static void gpr_timers_log_add(const char *tagstr, marker_type type,
-                               int important, const char *file, int line) {
-  gpr_timer_entry *entry;
-
-  if (g_thread_log == NULL || g_thread_log->num_entries == MAX_COUNT) {
-    rotate_log();
-  }
-
-  entry = &g_thread_log->log[g_thread_log->num_entries++];
-
-  entry->tm = gpr_now(GPR_CLOCK_PRECISE);
-  entry->tagstr = tagstr;
-  entry->type = type;
-  entry->file = file;
-  entry->line = (short)line;
-  entry->important = important != 0;
-  entry->thd = g_thread_id;
-}
-
-/* Latency profiler API implementation. */
-void gpr_timer_add_mark(const char *tagstr, int important, const char *file,
-                        int line) {
-  gpr_timers_log_add(tagstr, MARK, important, file, line);
-}
-
-void gpr_timer_begin(const char *tagstr, int important, const char *file,
-                     int line) {
-  gpr_timers_log_add(tagstr, BEGIN, important, file, line);
-}
-
-void gpr_timer_end(const char *tagstr, int important, const char *file,
-                   int line) {
-  gpr_timers_log_add(tagstr, END, important, file, line);
-}
-
-/* Basic profiler specific API functions. */
-void gpr_timers_global_init(void) {}
-
-void gpr_timers_global_destroy(void) {}
-
-#else  /* !GRPC_BASIC_PROFILER */
-void gpr_timers_global_init(void) {}
-
-void gpr_timers_global_destroy(void) {}
-
-void gpr_timers_set_log_filename(const char *filename) {}
-#endif /* GRPC_BASIC_PROFILER */
diff --git a/src/core/profiling/stap_timers.c b/src/core/profiling/stap_timers.c
deleted file mode 100644
index efcd1af..0000000
--- a/src/core/profiling/stap_timers.c
+++ /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.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GRPC_STAP_PROFILER
-
-#include "src/core/profiling/timers.h"
-
-#include <sys/sdt.h>
-/* Generated from src/core/profiling/stap_probes.d */
-#include "src/core/profiling/stap_probes.h"
-
-/* Latency profiler API implementation. */
-void gpr_timer_add_mark(int tag, const char *tagstr, void *id, const char *file,
-                        int line) {
-  _STAP_ADD_MARK(tag);
-}
-
-void gpr_timer_add_important_mark(int tag, const char *tagstr, void *id,
-                                  const char *file, int line) {
-  _STAP_ADD_IMPORTANT_MARK(tag);
-}
-
-void gpr_timer_begin(int tag, const char *tagstr, void *id, const char *file,
-                     int line) {
-  _STAP_TIMING_NS_BEGIN(tag);
-}
-
-void gpr_timer_end(int tag, const char *tagstr, void *id, const char *file,
-                   int line) {
-  _STAP_TIMING_NS_END(tag);
-}
-
-#endif /* GRPC_STAP_PROFILER */
diff --git a/src/core/profiling/timers.h b/src/core/profiling/timers.h
deleted file mode 100644
index 6a188dc..0000000
--- a/src/core/profiling/timers.h
+++ /dev/null
@@ -1,119 +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_CORE_PROFILING_TIMERS_H
-#define GRPC_CORE_PROFILING_TIMERS_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void gpr_timers_global_init(void);
-void gpr_timers_global_destroy(void);
-
-void gpr_timer_add_mark(const char *tagstr, int important, const char *file,
-                        int line);
-void gpr_timer_begin(const char *tagstr, int important, const char *file,
-                     int line);
-void gpr_timer_end(const char *tagstr, int important, const char *file,
-                   int line);
-
-void gpr_timers_set_log_filename(const char *filename);
-
-#if !(defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER))
-/* No profiling. No-op all the things. */
-#define GPR_TIMER_MARK(tag, important) \
-  do {                                 \
-  } while (0)
-
-#define GPR_TIMER_BEGIN(tag, important) \
-  do {                                  \
-  } while (0)
-
-#define GPR_TIMER_END(tag, important) \
-  do {                                \
-  } while (0)
-
-#else /* at least one profiler requested... */
-/* ... hopefully only one. */
-#if defined(GRPC_STAP_PROFILER) && defined(GRPC_BASIC_PROFILER)
-#error "GRPC_STAP_PROFILER and GRPC_BASIC_PROFILER are mutually exclusive."
-#endif
-
-/* Generic profiling interface. */
-#define GPR_TIMER_MARK(tag, important) \
-  gpr_timer_add_mark(tag, important, __FILE__, __LINE__);
-
-#define GPR_TIMER_BEGIN(tag, important) \
-  gpr_timer_begin(tag, important, __FILE__, __LINE__);
-
-#define GPR_TIMER_END(tag, important) \
-  gpr_timer_end(tag, important, __FILE__, __LINE__);
-
-#ifdef GRPC_STAP_PROFILER
-/* Empty placeholder for now. */
-#endif /* GRPC_STAP_PROFILER */
-
-#ifdef GRPC_BASIC_PROFILER
-/* Empty placeholder for now. */
-#endif /* GRPC_BASIC_PROFILER */
-
-#endif /* at least one profiler requested. */
-
-#ifdef __cplusplus
-}
-
-#if (defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER))
-namespace grpc {
-class ProfileScope {
- public:
-  ProfileScope(const char *desc, bool important) : desc_(desc) {
-    GPR_TIMER_BEGIN(desc_, important ? 1 : 0);
-  }
-  ~ProfileScope() { GPR_TIMER_END(desc_, 0); }
-
- private:
-  const char *const desc_;
-};
-}
-
-#define GPR_TIMER_SCOPE(tag, important) \
-  ::grpc::ProfileScope _profile_scope_##__LINE__((tag), (important))
-#else
-#define GPR_TIMER_SCOPE(tag, important) \
-  do {                                  \
-  } while (false)
-#endif
-#endif
-
-#endif /* GRPC_CORE_PROFILING_TIMERS_H */
diff --git a/src/core/proto/grpc/lb/v0/load_balancer.pb.c b/src/core/proto/grpc/lb/v0/load_balancer.pb.c
deleted file mode 100644
index 59aae30..0000000
--- a/src/core/proto/grpc/lb/v0/load_balancer.pb.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- *
- * Copyright 2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-/* Automatically generated nanopb constant definitions */
-/* Generated by nanopb-0.3.5-dev */
-
-#include "src/core/proto/grpc/lb/v0/load_balancer.pb.h"
-
-#if PB_PROTO_HEADER_VERSION != 30
-#error Regenerate this file with the current version of nanopb generator.
-#endif
-
-
-
-const pb_field_t grpc_lb_v0_Duration_fields[3] = {
-    PB_FIELD(  1, INT64   , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_Duration, seconds, seconds, 0),
-    PB_FIELD(  2, INT32   , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_Duration, nanos, seconds, 0),
-    PB_LAST_FIELD
-};
-
-const pb_field_t grpc_lb_v0_LoadBalanceRequest_fields[3] = {
-    PB_FIELD(  1, MESSAGE , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_LoadBalanceRequest, initial_request, initial_request, &grpc_lb_v0_InitialLoadBalanceRequest_fields),
-    PB_FIELD(  2, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_LoadBalanceRequest, client_stats, initial_request, &grpc_lb_v0_ClientStats_fields),
-    PB_LAST_FIELD
-};
-
-const pb_field_t grpc_lb_v0_InitialLoadBalanceRequest_fields[2] = {
-    PB_FIELD(  1, STRING  , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_InitialLoadBalanceRequest, name, name, 0),
-    PB_LAST_FIELD
-};
-
-const pb_field_t grpc_lb_v0_ClientStats_fields[4] = {
-    PB_FIELD(  1, INT64   , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_ClientStats, total_requests, total_requests, 0),
-    PB_FIELD(  2, INT64   , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_ClientStats, client_rpc_errors, total_requests, 0),
-    PB_FIELD(  3, INT64   , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_ClientStats, dropped_requests, client_rpc_errors, 0),
-    PB_LAST_FIELD
-};
-
-const pb_field_t grpc_lb_v0_LoadBalanceResponse_fields[3] = {
-    PB_FIELD(  1, MESSAGE , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_LoadBalanceResponse, initial_response, initial_response, &grpc_lb_v0_InitialLoadBalanceResponse_fields),
-    PB_FIELD(  2, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_LoadBalanceResponse, server_list, initial_response, &grpc_lb_v0_ServerList_fields),
-    PB_LAST_FIELD
-};
-
-const pb_field_t grpc_lb_v0_InitialLoadBalanceResponse_fields[4] = {
-    PB_FIELD(  1, STRING  , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_InitialLoadBalanceResponse, client_config, client_config, 0),
-    PB_FIELD(  2, STRING  , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_InitialLoadBalanceResponse, load_balancer_delegate, client_config, 0),
-    PB_FIELD(  3, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval, load_balancer_delegate, &grpc_lb_v0_Duration_fields),
-    PB_LAST_FIELD
-};
-
-const pb_field_t grpc_lb_v0_ServerList_fields[3] = {
-    PB_FIELD(  1, MESSAGE , REPEATED, CALLBACK, FIRST, grpc_lb_v0_ServerList, servers, servers, &grpc_lb_v0_Server_fields),
-    PB_FIELD(  3, MESSAGE , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_ServerList, expiration_interval, servers, &grpc_lb_v0_Duration_fields),
-    PB_LAST_FIELD
-};
-
-const pb_field_t grpc_lb_v0_Server_fields[5] = {
-    PB_FIELD(  1, STRING  , OPTIONAL, STATIC  , FIRST, grpc_lb_v0_Server, ip_address, ip_address, 0),
-    PB_FIELD(  2, INT32   , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_Server, port, ip_address, 0),
-    PB_FIELD(  3, BYTES   , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_Server, load_balance_token, port, 0),
-    PB_FIELD(  4, BOOL    , OPTIONAL, STATIC  , OTHER, grpc_lb_v0_Server, drop_request, load_balance_token, 0),
-    PB_LAST_FIELD
-};
-
-
-/* Check that field information fits in pb_field_t */
-#if !defined(PB_FIELD_32BIT)
-/* If you get an error here, it means that you need to define PB_FIELD_32BIT
- * compile-time option. You can do that in pb.h or on compiler command line.
- * 
- * The reason you need to do this is that some of your messages contain tag
- * numbers or field sizes that are larger than what can fit in 8 or 16 bit
- * field descriptors.
- */
-PB_STATIC_ASSERT((pb_membersize(grpc_lb_v0_LoadBalanceRequest, initial_request) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceRequest, client_stats) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, initial_response) < 65536 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, server_list) < 65536 && pb_membersize(grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval) < 65536 && pb_membersize(grpc_lb_v0_ServerList, servers) < 65536 && pb_membersize(grpc_lb_v0_ServerList, expiration_interval) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_grpc_lb_v0_Duration_grpc_lb_v0_LoadBalanceRequest_grpc_lb_v0_InitialLoadBalanceRequest_grpc_lb_v0_ClientStats_grpc_lb_v0_LoadBalanceResponse_grpc_lb_v0_InitialLoadBalanceResponse_grpc_lb_v0_ServerList_grpc_lb_v0_Server)
-#endif
-
-#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
-/* If you get an error here, it means that you need to define PB_FIELD_16BIT
- * compile-time option. You can do that in pb.h or on compiler command line.
- * 
- * The reason you need to do this is that some of your messages contain tag
- * numbers or field sizes that are larger than what can fit in the default
- * 8 bit descriptors.
- */
-PB_STATIC_ASSERT((pb_membersize(grpc_lb_v0_LoadBalanceRequest, initial_request) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceRequest, client_stats) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, initial_response) < 256 && pb_membersize(grpc_lb_v0_LoadBalanceResponse, server_list) < 256 && pb_membersize(grpc_lb_v0_InitialLoadBalanceResponse, client_stats_report_interval) < 256 && pb_membersize(grpc_lb_v0_ServerList, servers) < 256 && pb_membersize(grpc_lb_v0_ServerList, expiration_interval) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_grpc_lb_v0_Duration_grpc_lb_v0_LoadBalanceRequest_grpc_lb_v0_InitialLoadBalanceRequest_grpc_lb_v0_ClientStats_grpc_lb_v0_LoadBalanceResponse_grpc_lb_v0_InitialLoadBalanceResponse_grpc_lb_v0_ServerList_grpc_lb_v0_Server)
-#endif
-
-
diff --git a/src/core/security/auth_filters.h b/src/core/security/auth_filters.h
deleted file mode 100644
index c179b54..0000000
--- a/src/core/security/auth_filters.h
+++ /dev/null
@@ -1,42 +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_SECURITY_AUTH_FILTERS_H
-#define GRPC_INTERNAL_CORE_SECURITY_AUTH_FILTERS_H
-
-#include "src/core/channel/channel_stack.h"
-
-extern const grpc_channel_filter grpc_client_auth_filter;
-extern const grpc_channel_filter grpc_server_auth_filter;
-
-#endif /* GRPC_INTERNAL_CORE_SECURITY_AUTH_FILTERS_H */
diff --git a/src/core/security/b64.c b/src/core/security/b64.c
deleted file mode 100644
index c40b528..0000000
--- a/src/core/security/b64.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/security/b64.h"
-
-#include <stdint.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-/* --- Constants. --- */
-
-static const int8_t base64_bytes[] = {
-    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-    -1,   -1,   -1,   -1,   -1,   -1,   -1,   0x3E, -1,   -1,   -1,   0x3F,
-    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, -1,   -1,
-    -1,   0x7F, -1,   -1,   -1,   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
-    0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
-    0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, -1,   -1,   -1,   -1,   -1,
-    -1,   0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
-    0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
-    0x31, 0x32, 0x33, -1,   -1,   -1,   -1,   -1};
-
-static const char base64_url_unsafe_chars[] =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const char base64_url_safe_chars[] =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-
-#define GRPC_BASE64_PAD_CHAR '='
-#define GRPC_BASE64_PAD_BYTE 0x7F
-#define GRPC_BASE64_MULTILINE_LINE_LEN 76
-#define GRPC_BASE64_MULTILINE_NUM_BLOCKS (GRPC_BASE64_MULTILINE_LINE_LEN / 4)
-
-/* --- base64 functions. --- */
-
-char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe,
-                         int multiline) {
-  const unsigned char *data = vdata;
-  const char *base64_chars =
-      url_safe ? base64_url_safe_chars : base64_url_unsafe_chars;
-  size_t result_projected_size =
-      4 * ((data_size + 3) / 3) +
-      2 * (multiline ? (data_size / (3 * GRPC_BASE64_MULTILINE_NUM_BLOCKS))
-                     : 0) +
-      1;
-  char *result = gpr_malloc(result_projected_size);
-  char *current = result;
-  size_t num_blocks = 0;
-  size_t i = 0;
-
-  /* Encode each block. */
-  while (data_size >= 3) {
-    *current++ = base64_chars[(data[i] >> 2) & 0x3F];
-    *current++ =
-        base64_chars[((data[i] & 0x03) << 4) | ((data[i + 1] >> 4) & 0x0F)];
-    *current++ =
-        base64_chars[((data[i + 1] & 0x0F) << 2) | ((data[i + 2] >> 6) & 0x03)];
-    *current++ = base64_chars[data[i + 2] & 0x3F];
-
-    data_size -= 3;
-    i += 3;
-    if (multiline && (++num_blocks == GRPC_BASE64_MULTILINE_NUM_BLOCKS)) {
-      *current++ = '\r';
-      *current++ = '\n';
-      num_blocks = 0;
-    }
-  }
-
-  /* Take care of the tail. */
-  if (data_size == 2) {
-    *current++ = base64_chars[(data[i] >> 2) & 0x3F];
-    *current++ =
-        base64_chars[((data[i] & 0x03) << 4) | ((data[i + 1] >> 4) & 0x0F)];
-    *current++ = base64_chars[(data[i + 1] & 0x0F) << 2];
-    *current++ = GRPC_BASE64_PAD_CHAR;
-  } else if (data_size == 1) {
-    *current++ = base64_chars[(data[i] >> 2) & 0x3F];
-    *current++ = base64_chars[(data[i] & 0x03) << 4];
-    *current++ = GRPC_BASE64_PAD_CHAR;
-    *current++ = GRPC_BASE64_PAD_CHAR;
-  }
-
-  GPR_ASSERT(current >= result);
-  GPR_ASSERT((uintptr_t)(current - result) < result_projected_size);
-  result[current - result] = '\0';
-  return result;
-}
-
-gpr_slice grpc_base64_decode(const char *b64, int url_safe) {
-  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) {
-  uint32_t packed = ((uint32_t)codes[0] << 2) | ((uint32_t)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) {
-  uint32_t packed = ((uint32_t)codes[0] << 10) | ((uint32_t)codes[1] << 4) |
-                    ((uint32_t)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. */
-    uint32_t packed = ((uint32_t)codes[0] << 18) | ((uint32_t)codes[1] << 12) |
-                      ((uint32_t)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;
-  unsigned char codes[4];
-  size_t num_codes = 0;
-
-  while (b64_len--) {
-    unsigned char c = (unsigned char)(*b64++);
-    signed char code;
-    if (c >= GPR_ARRAY_SIZE(base64_bytes)) continue;
-    if (url_safe) {
-      if (c == '+' || c == '/') {
-        gpr_log(GPR_ERROR, "Invalid character for url safe base64 %c", c);
-        goto fail;
-      }
-      if (c == '-') {
-        c = '+';
-      } else if (c == '_') {
-        c = '/';
-      }
-    }
-    code = base64_bytes[c];
-    if (code == -1) {
-      if (c != '\r' && c != '\n') {
-        gpr_log(GPR_ERROR, "Invalid character %c", c);
-        goto fail;
-      }
-    } else {
-      codes[num_codes++] = (unsigned char)code;
-      if (num_codes == 4) {
-        if (!decode_group(codes, num_codes, current, &result_size)) goto fail;
-        num_codes = 0;
-      }
-    }
-  }
-
-  if (num_codes != 0 &&
-      !decode_group(codes, num_codes, current, &result_size)) {
-    goto fail;
-  }
-  GPR_SLICE_SET_LENGTH(result, result_size);
-  return result;
-
-fail:
-  gpr_slice_unref(result);
-  return gpr_empty_slice();
-}
diff --git a/src/core/security/b64.h b/src/core/security/b64.h
deleted file mode 100644
index 3e3b521..0000000
--- a/src/core/security/b64.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_SECURITY_BASE64_H
-#define GRPC_INTERNAL_CORE_SECURITY_BASE64_H
-
-#include <grpc/support/slice.h>
-
-/* Encodes data using base64. It is the caller's responsability to free
-   the returned char * using gpr_free. Returns NULL on NULL input. */
-char *grpc_base64_encode(const void *data, size_t data_size, int url_safe,
-                         int multiline);
-
-/* Decodes data according to the base64 specification. Returns an empty
-   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
deleted file mode 100644
index 332d425..0000000
--- a/src/core/security/client_auth_filter.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/security/auth_filters.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/channel/channel_stack.h"
-#include "src/core/security/credentials.h"
-#include "src/core/security/security_connector.h"
-#include "src/core/security/security_context.h"
-#include "src/core/support/string.h"
-#include "src/core/surface/call.h"
-#include "src/core/transport/static_metadata.h"
-
-#define MAX_CREDENTIALS_METADATA_COUNT 4
-
-/* We can have a per-call credentials. */
-typedef struct {
-  grpc_call_credentials *creds;
-  grpc_mdstr *host;
-  grpc_mdstr *method;
-  /* 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;
-  uint8_t security_context_set;
-  grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
-  grpc_auth_metadata_context auth_md_context;
-} call_data;
-
-/* We can have a per-channel credentials. */
-typedef struct {
-  grpc_channel_security_connector *security_connector;
-  grpc_auth_context *auth_context;
-} channel_data;
-
-static void reset_auth_metadata_context(
-    grpc_auth_metadata_context *auth_md_context) {
-  if (auth_md_context->service_url != NULL) {
-    gpr_free((char *)auth_md_context->service_url);
-    auth_md_context->service_url = NULL;
-  }
-  if (auth_md_context->method_name != NULL) {
-    gpr_free((char *)auth_md_context->method_name);
-    auth_md_context->method_name = NULL;
-  }
-  GRPC_AUTH_CONTEXT_UNREF(
-      (grpc_auth_context *)auth_md_context->channel_auth_context,
-      "grpc_auth_metadata_context");
-  auth_md_context->channel_auth_context = NULL;
-}
-
-static void bubble_up_error(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                            grpc_status_code status, const char *error_msg) {
-  call_data *calld = elem->call_data;
-  gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg);
-  grpc_transport_stream_op_add_cancellation(&calld->op, status);
-  grpc_call_next_op(exec_ctx, elem, &calld->op);
-}
-
-static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
-                                    grpc_credentials_md *md_elems,
-                                    size_t num_md,
-                                    grpc_credentials_status status) {
-  grpc_call_element *elem = (grpc_call_element *)user_data;
-  call_data *calld = elem->call_data;
-  grpc_transport_stream_op *op = &calld->op;
-  grpc_metadata_batch *mdb;
-  size_t i;
-  reset_auth_metadata_context(&calld->auth_md_context);
-  if (status != GRPC_CREDENTIALS_OK) {
-    bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED,
-                    "Credentials failed to get metadata.");
-    return;
-  }
-  GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT);
-  GPR_ASSERT(op->send_initial_metadata != NULL);
-  mdb = op->send_initial_metadata;
-  for (i = 0; i < num_md; i++) {
-    grpc_metadata_batch_add_tail(
-        mdb, &calld->md_links[i],
-        grpc_mdelem_from_slices(gpr_slice_ref(md_elems[i].key),
-                                gpr_slice_ref(md_elems[i].value)));
-  }
-  grpc_call_next_op(exec_ctx, elem, op);
-}
-
-void build_auth_metadata_context(grpc_security_connector *sc,
-                                 grpc_auth_context *auth_context,
-                                 call_data *calld) {
-  char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method));
-  char *last_slash = strrchr(service, '/');
-  char *method_name = NULL;
-  char *service_url = NULL;
-  reset_auth_metadata_context(&calld->auth_md_context);
-  if (last_slash == NULL) {
-    gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
-    service[0] = '\0';
-  } else if (last_slash == service) {
-    /* No service part in fully qualified method name: will just be "/". */
-    service[1] = '\0';
-  } else {
-    *last_slash = '\0';
-    method_name = gpr_strdup(last_slash + 1);
-  }
-  if (method_name == NULL) method_name = gpr_strdup("");
-  gpr_asprintf(&service_url, "%s://%s%s",
-               sc->url_scheme == NULL ? "" : sc->url_scheme,
-               grpc_mdstr_as_c_string(calld->host), service);
-  calld->auth_md_context.service_url = service_url;
-  calld->auth_md_context.method_name = method_name;
-  calld->auth_md_context.channel_auth_context =
-      GRPC_AUTH_CONTEXT_REF(auth_context, "grpc_auth_metadata_context");
-  gpr_free(service);
-}
-
-static void send_security_metadata(grpc_exec_ctx *exec_ctx,
-                                   grpc_call_element *elem,
-                                   grpc_transport_stream_op *op) {
-  call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
-  grpc_client_security_context *ctx =
-      (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value;
-  grpc_call_credentials *channel_call_creds =
-      chand->security_connector->request_metadata_creds;
-  int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL);
-
-  if (channel_call_creds == NULL && !call_creds_has_md) {
-    /* Skip sending metadata altogether. */
-    grpc_call_next_op(exec_ctx, elem, op);
-    return;
-  }
-
-  if (channel_call_creds != NULL && call_creds_has_md) {
-    calld->creds = grpc_composite_call_credentials_create(channel_call_creds,
-                                                          ctx->creds, NULL);
-    if (calld->creds == NULL) {
-      bubble_up_error(exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT,
-                      "Incompatible credentials set on channel and call.");
-      return;
-    }
-  } else {
-    calld->creds = grpc_call_credentials_ref(
-        call_creds_has_md ? ctx->creds : channel_call_creds);
-  }
-
-  build_auth_metadata_context(&chand->security_connector->base,
-                              chand->auth_context, calld);
-  calld->op = *op; /* Copy op (originates from the caller's stack). */
-  GPR_ASSERT(calld->pollset);
-  grpc_call_credentials_get_request_metadata(
-      exec_ctx, calld->creds, calld->pollset, calld->auth_md_context,
-      on_credentials_metadata, elem);
-}
-
-static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data,
-                            grpc_security_status status) {
-  grpc_call_element *elem = (grpc_call_element *)user_data;
-  call_data *calld = elem->call_data;
-
-  if (status == GRPC_SECURITY_OK) {
-    send_security_metadata(exec_ctx, elem, &calld->op);
-  } else {
-    char *error_msg;
-    gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.",
-                 grpc_mdstr_as_c_string(calld->host));
-    bubble_up_error(exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, error_msg);
-    gpr_free(error_msg);
-  }
-}
-
-/* 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 auth_start_transport_op(grpc_exec_ctx *exec_ctx,
-                                    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 *chand = elem->channel_data;
-  grpc_linked_mdelem *l;
-  grpc_client_security_context *sec_ctx = NULL;
-
-  if (calld->security_context_set == 0 &&
-      op->cancel_with_status == GRPC_STATUS_OK) {
-    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->auth_context, "client_auth_filter");
-  }
-
-  if (op->send_initial_metadata != NULL) {
-    for (l = op->send_initial_metadata->list.head; l != NULL; l = l->next) {
-      grpc_mdelem *md = l->md;
-      /* Pointer comparison is OK for md_elems created from the same context.
-       */
-      if (md->key == GRPC_MDSTR_AUTHORITY) {
-        if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host);
-        calld->host = GRPC_MDSTR_REF(md->value);
-      } else if (md->key == GRPC_MDSTR_PATH) {
-        if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method);
-        calld->method = GRPC_MDSTR_REF(md->value);
-      }
-    }
-    if (calld->host != NULL) {
-      const char *call_host = grpc_mdstr_as_c_string(calld->host);
-      calld->op = *op; /* Copy op (originates from the caller's stack). */
-      grpc_channel_security_connector_check_call_host(
-          exec_ctx, chand->security_connector, call_host, chand->auth_context,
-          on_host_checked, elem);
-      return; /* early exit */
-    }
-  }
-
-  /* pass control down the stack */
-  grpc_call_next_op(exec_ctx, elem, op);
-}
-
-/* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
-  call_data *calld = elem->call_data;
-  memset(calld, 0, sizeof(*calld));
-}
-
-static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                        grpc_pollset *pollset) {
-  call_data *calld = elem->call_data;
-  calld->pollset = pollset;
-}
-
-/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {
-  call_data *calld = elem->call_data;
-  grpc_call_credentials_unref(calld->creds);
-  if (calld->host != NULL) {
-    GRPC_MDSTR_UNREF(calld->host);
-  }
-  if (calld->method != NULL) {
-    GRPC_MDSTR_UNREF(calld->method);
-  }
-  reset_auth_metadata_context(&calld->auth_md_context);
-}
-
-/* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
-  grpc_security_connector *sc =
-      grpc_find_security_connector_in_args(args->channel_args);
-  grpc_auth_context *auth_context =
-      grpc_find_auth_context_in_args(args->channel_args);
-
-  /* grab pointers to our data from the channel element */
-  channel_data *chand = elem->channel_data;
-
-  /* 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(!args->is_last);
-  GPR_ASSERT(sc != NULL);
-  GPR_ASSERT(auth_context != NULL);
-
-  /* initialize members */
-  chand->security_connector =
-      (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF(
-          sc, "client_auth_filter");
-  chand->auth_context =
-      GRPC_AUTH_CONTEXT_REF(auth_context, "client_auth_filter");
-}
-
-/* Destructor for channel data */
-static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem) {
-  /* grab pointers to our data from the channel element */
-  channel_data *chand = elem->channel_data;
-  grpc_channel_security_connector *sc = chand->security_connector;
-  if (sc != NULL) {
-    GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "client_auth_filter");
-  }
-  GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "client_auth_filter");
-}
-
-const grpc_channel_filter grpc_client_auth_filter = {
-    auth_start_transport_op, grpc_channel_next_op, sizeof(call_data),
-    init_call_elem, set_pollset, destroy_call_elem, sizeof(channel_data),
-    init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer,
-    "client-auth"};
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
deleted file mode 100644
index b4fa616..0000000
--- a/src/core/security/credentials.c
+++ /dev/null
@@ -1,1280 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/security/credentials.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/http_client_filter.h"
-#include "src/core/httpcli/httpcli.h"
-#include "src/core/iomgr/executor.h"
-#include "src/core/json/json.h"
-#include "src/core/support/string.h"
-#include "src/core/surface/api_trace.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/time.h>
-
-/* -- Common. -- */
-
-struct grpc_credentials_metadata_request {
-  grpc_call_credentials *creds;
-  grpc_credentials_metadata_cb cb;
-  void *user_data;
-};
-
-static grpc_credentials_metadata_request *
-grpc_credentials_metadata_request_create(grpc_call_credentials *creds,
-                                         grpc_credentials_metadata_cb cb,
-                                         void *user_data) {
-  grpc_credentials_metadata_request *r =
-      gpr_malloc(sizeof(grpc_credentials_metadata_request));
-  r->creds = grpc_call_credentials_ref(creds);
-  r->cb = cb;
-  r->user_data = user_data;
-  return r;
-}
-
-static void grpc_credentials_metadata_request_destroy(
-    grpc_credentials_metadata_request *r) {
-  grpc_call_credentials_unref(r->creds);
-  gpr_free(r);
-}
-
-grpc_channel_credentials *grpc_channel_credentials_ref(
-    grpc_channel_credentials *creds) {
-  if (creds == NULL) return NULL;
-  gpr_ref(&creds->refcount);
-  return creds;
-}
-
-void grpc_channel_credentials_unref(grpc_channel_credentials *creds) {
-  if (creds == NULL) return;
-  if (gpr_unref(&creds->refcount)) {
-    if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds);
-    gpr_free(creds);
-  }
-}
-
-void grpc_channel_credentials_release(grpc_channel_credentials *creds) {
-  GRPC_API_TRACE("grpc_channel_credentials_release(creds=%p)", 1, (creds));
-  grpc_channel_credentials_unref(creds);
-}
-
-grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds) {
-  if (creds == NULL) return NULL;
-  gpr_ref(&creds->refcount);
-  return creds;
-}
-
-void grpc_call_credentials_unref(grpc_call_credentials *creds) {
-  if (creds == NULL) return;
-  if (gpr_unref(&creds->refcount)) {
-    if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds);
-    gpr_free(creds);
-  }
-}
-
-void grpc_call_credentials_release(grpc_call_credentials *creds) {
-  GRPC_API_TRACE("grpc_call_credentials_release(creds=%p)", 1, (creds));
-  grpc_call_credentials_unref(creds);
-}
-
-void grpc_call_credentials_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
-    grpc_pollset *pollset, grpc_auth_metadata_context context,
-    grpc_credentials_metadata_cb cb, void *user_data) {
-  if (creds == NULL || creds->vtable->get_request_metadata == NULL) {
-    if (cb != NULL) {
-      cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
-    }
-    return;
-  }
-  creds->vtable->get_request_metadata(exec_ctx, creds, pollset, context, cb,
-                                      user_data);
-}
-
-grpc_security_status grpc_channel_credentials_create_security_connector(
-    grpc_channel_credentials *channel_creds, const char *target,
-    const grpc_channel_args *args, grpc_channel_security_connector **sc,
-    grpc_channel_args **new_args) {
-  *new_args = NULL;
-  if (channel_creds == NULL) {
-    return GRPC_SECURITY_ERROR;
-  }
-  GPR_ASSERT(channel_creds->vtable->create_security_connector != NULL);
-  return channel_creds->vtable->create_security_connector(
-      channel_creds, NULL, target, args, sc, new_args);
-}
-
-grpc_server_credentials *grpc_server_credentials_ref(
-    grpc_server_credentials *creds) {
-  if (creds == NULL) return NULL;
-  gpr_ref(&creds->refcount);
-  return creds;
-}
-
-void grpc_server_credentials_unref(grpc_server_credentials *creds) {
-  if (creds == NULL) return;
-  if (gpr_unref(&creds->refcount)) {
-    if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds);
-    if (creds->processor.destroy != NULL && creds->processor.state != NULL) {
-      creds->processor.destroy(creds->processor.state);
-    }
-    gpr_free(creds);
-  }
-}
-
-void grpc_server_credentials_release(grpc_server_credentials *creds) {
-  GRPC_API_TRACE("grpc_server_credentials_release(creds=%p)", 1, (creds));
-  grpc_server_credentials_unref(creds);
-}
-
-grpc_security_status grpc_server_credentials_create_security_connector(
-    grpc_server_credentials *creds, grpc_server_security_connector **sc) {
-  if (creds == NULL || creds->vtable->create_security_connector == NULL) {
-    gpr_log(GPR_ERROR, "Server credentials cannot create security context.");
-    return GRPC_SECURITY_ERROR;
-  }
-  return creds->vtable->create_security_connector(creds, sc);
-}
-
-void grpc_server_credentials_set_auth_metadata_processor(
-    grpc_server_credentials *creds, grpc_auth_metadata_processor processor) {
-  GRPC_API_TRACE(
-      "grpc_server_credentials_set_auth_metadata_processor("
-      "creds=%p, "
-      "processor=grpc_auth_metadata_processor { process: %p, state: %p })",
-      3, (creds, (void *)(intptr_t)processor.process, processor.state));
-  if (creds == NULL) return;
-  if (creds->processor.destroy != NULL && creds->processor.state != NULL) {
-    creds->processor.destroy(creds->processor.state);
-  }
-  creds->processor = processor;
-}
-
-static void server_credentials_pointer_arg_destroy(void *p) {
-  grpc_server_credentials_unref(p);
-}
-
-static void *server_credentials_pointer_arg_copy(void *p) {
-  return grpc_server_credentials_ref(p);
-}
-
-static int server_credentials_pointer_cmp(void *a, void *b) {
-  return GPR_ICMP(a, b);
-}
-
-static const grpc_arg_pointer_vtable cred_ptr_vtable = {
-    server_credentials_pointer_arg_copy, server_credentials_pointer_arg_destroy,
-    server_credentials_pointer_cmp};
-
-grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *p) {
-  grpc_arg arg;
-  memset(&arg, 0, sizeof(grpc_arg));
-  arg.type = GRPC_ARG_POINTER;
-  arg.key = GRPC_SERVER_CREDENTIALS_ARG;
-  arg.value.pointer.p = p;
-  arg.value.pointer.vtable = &cred_ptr_vtable;
-  return arg;
-}
-
-grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg) {
-  if (strcmp(arg->key, GRPC_SERVER_CREDENTIALS_ARG) != 0) return NULL;
-  if (arg->type != GRPC_ARG_POINTER) {
-    gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
-            GRPC_SERVER_CREDENTIALS_ARG);
-    return NULL;
-  }
-  return arg->value.pointer.p;
-}
-
-grpc_server_credentials *grpc_find_server_credentials_in_args(
-    const grpc_channel_args *args) {
-  size_t i;
-  if (args == NULL) return NULL;
-  for (i = 0; i < args->num_args; i++) {
-    grpc_server_credentials *p =
-        grpc_server_credentials_from_arg(&args->args[i]);
-    if (p != NULL) return p;
-  }
-  return NULL;
-}
-
-/* -- Ssl credentials. -- */
-
-static void ssl_destruct(grpc_channel_credentials *creds) {
-  grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
-  if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
-  if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
-  if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
-}
-
-static void ssl_server_destruct(grpc_server_credentials *creds) {
-  grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
-  size_t i;
-  for (i = 0; i < c->config.num_key_cert_pairs; i++) {
-    if (c->config.pem_private_keys[i] != NULL) {
-      gpr_free(c->config.pem_private_keys[i]);
-    }
-    if (c->config.pem_cert_chains[i] != NULL) {
-      gpr_free(c->config.pem_cert_chains[i]);
-    }
-  }
-  if (c->config.pem_private_keys != NULL) gpr_free(c->config.pem_private_keys);
-  if (c->config.pem_private_keys_sizes != NULL) {
-    gpr_free(c->config.pem_private_keys_sizes);
-  }
-  if (c->config.pem_cert_chains != NULL) gpr_free(c->config.pem_cert_chains);
-  if (c->config.pem_cert_chains_sizes != NULL) {
-    gpr_free(c->config.pem_cert_chains_sizes);
-  }
-  if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
-}
-
-static grpc_security_status ssl_create_security_connector(
-    grpc_channel_credentials *creds, grpc_call_credentials *call_creds,
-    const char *target, const grpc_channel_args *args,
-    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
-  grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
-  grpc_security_status status = GRPC_SECURITY_OK;
-  size_t i = 0;
-  const char *overridden_target_name = NULL;
-  grpc_arg new_arg;
-
-  for (i = 0; args && i < args->num_args; i++) {
-    grpc_arg *arg = &args->args[i];
-    if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 &&
-        arg->type == GRPC_ARG_STRING) {
-      overridden_target_name = arg->value.string;
-      break;
-    }
-  }
-  status = grpc_ssl_channel_security_connector_create(
-      call_creds, &c->config, target, overridden_target_name, sc);
-  if (status != GRPC_SECURITY_OK) {
-    return status;
-  }
-  new_arg.type = GRPC_ARG_STRING;
-  new_arg.key = GRPC_ARG_HTTP2_SCHEME;
-  new_arg.value.string = "https";
-  *new_args = grpc_channel_args_copy_and_add(args, &new_arg, 1);
-  return status;
-}
-
-static grpc_security_status ssl_server_create_security_connector(
-    grpc_server_credentials *creds, grpc_server_security_connector **sc) {
-  grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
-  return grpc_ssl_server_security_connector_create(&c->config, sc);
-}
-
-static grpc_channel_credentials_vtable ssl_vtable = {
-    ssl_destruct, ssl_create_security_connector};
-
-static grpc_server_credentials_vtable ssl_server_vtable = {
-    ssl_server_destruct, ssl_server_create_security_connector};
-
-static void ssl_copy_key_material(const char *input, unsigned char **output,
-                                  size_t *output_size) {
-  *output_size = strlen(input);
-  *output = gpr_malloc(*output_size);
-  memcpy(*output, input, *output_size);
-}
-
-static void ssl_build_config(const char *pem_root_certs,
-                             grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
-                             grpc_ssl_config *config) {
-  if (pem_root_certs != NULL) {
-    ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
-                          &config->pem_root_certs_size);
-  }
-  if (pem_key_cert_pair != NULL) {
-    GPR_ASSERT(pem_key_cert_pair->private_key != NULL);
-    GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL);
-    ssl_copy_key_material(pem_key_cert_pair->private_key,
-                          &config->pem_private_key,
-                          &config->pem_private_key_size);
-    ssl_copy_key_material(pem_key_cert_pair->cert_chain,
-                          &config->pem_cert_chain,
-                          &config->pem_cert_chain_size);
-  }
-}
-
-static void ssl_build_server_config(
-    const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
-    size_t num_key_cert_pairs, int force_client_auth,
-    grpc_ssl_server_config *config) {
-  size_t i;
-  config->force_client_auth = force_client_auth;
-  if (pem_root_certs != NULL) {
-    ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
-                          &config->pem_root_certs_size);
-  }
-  if (num_key_cert_pairs > 0) {
-    GPR_ASSERT(pem_key_cert_pairs != NULL);
-    config->pem_private_keys =
-        gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *));
-    config->pem_cert_chains =
-        gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *));
-    config->pem_private_keys_sizes =
-        gpr_malloc(num_key_cert_pairs * sizeof(size_t));
-    config->pem_cert_chains_sizes =
-        gpr_malloc(num_key_cert_pairs * sizeof(size_t));
-  }
-  config->num_key_cert_pairs = num_key_cert_pairs;
-  for (i = 0; i < num_key_cert_pairs; i++) {
-    GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL);
-    GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL);
-    ssl_copy_key_material(pem_key_cert_pairs[i].private_key,
-                          &config->pem_private_keys[i],
-                          &config->pem_private_keys_sizes[i]);
-    ssl_copy_key_material(pem_key_cert_pairs[i].cert_chain,
-                          &config->pem_cert_chains[i],
-                          &config->pem_cert_chains_sizes[i]);
-  }
-}
-
-grpc_channel_credentials *grpc_ssl_credentials_create(
-    const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
-    void *reserved) {
-  grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials));
-  GRPC_API_TRACE(
-      "grpc_ssl_credentials_create(pem_root_certs=%s, "
-      "pem_key_cert_pair=%p, "
-      "reserved=%p)",
-      3, (pem_root_certs, pem_key_cert_pair, reserved));
-  GPR_ASSERT(reserved == NULL);
-  memset(c, 0, sizeof(grpc_ssl_credentials));
-  c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL;
-  c->base.vtable = &ssl_vtable;
-  gpr_ref_init(&c->base.refcount, 1);
-  ssl_build_config(pem_root_certs, pem_key_cert_pair, &c->config);
-  return &c->base;
-}
-
-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, int force_client_auth, void *reserved) {
-  grpc_ssl_server_credentials *c =
-      gpr_malloc(sizeof(grpc_ssl_server_credentials));
-  GRPC_API_TRACE(
-      "grpc_ssl_server_credentials_create("
-      "pem_root_certs=%s, pem_key_cert_pairs=%p, num_key_cert_pairs=%lu, "
-      "force_client_auth=%d, reserved=%p)",
-      5, (pem_root_certs, pem_key_cert_pairs, (unsigned long)num_key_cert_pairs,
-          force_client_auth, reserved));
-  GPR_ASSERT(reserved == NULL);
-  memset(c, 0, sizeof(grpc_ssl_server_credentials));
-  c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL;
-  gpr_ref_init(&c->base.refcount, 1);
-  c->base.vtable = &ssl_server_vtable;
-  ssl_build_server_config(pem_root_certs, pem_key_cert_pairs,
-                          num_key_cert_pairs, force_client_auth, &c->config);
-  return &c->base;
-}
-
-/* -- Jwt credentials -- */
-
-static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) {
-  if (c->cached.jwt_md != NULL) {
-    grpc_credentials_md_store_unref(c->cached.jwt_md);
-    c->cached.jwt_md = NULL;
-  }
-  if (c->cached.service_url != NULL) {
-    gpr_free(c->cached.service_url);
-    c->cached.service_url = NULL;
-  }
-  c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
-}
-
-static void jwt_destruct(grpc_call_credentials *creds) {
-  grpc_service_account_jwt_access_credentials *c =
-      (grpc_service_account_jwt_access_credentials *)creds;
-  grpc_auth_json_key_destruct(&c->key);
-  jwt_reset_cache(c);
-  gpr_mu_destroy(&c->cache_mu);
-}
-
-static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx,
-                                     grpc_call_credentials *creds,
-                                     grpc_pollset *pollset,
-                                     grpc_auth_metadata_context context,
-                                     grpc_credentials_metadata_cb cb,
-                                     void *user_data) {
-  grpc_service_account_jwt_access_credentials *c =
-      (grpc_service_account_jwt_access_credentials *)creds;
-  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;
-  {
-    gpr_mu_lock(&c->cache_mu);
-    if (c->cached.service_url != NULL &&
-        strcmp(c->cached.service_url, context.service_url) == 0 &&
-        c->cached.jwt_md != NULL &&
-        (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);
-    }
-    gpr_mu_unlock(&c->cache_mu);
-  }
-
-  if (jwt_md == NULL) {
-    char *jwt = NULL;
-    /* Generate a new jwt. */
-    gpr_mu_lock(&c->cache_mu);
-    jwt_reset_cache(c);
-    jwt = grpc_jwt_encode_and_sign(&c->key, context.service_url,
-                                   c->jwt_lifetime, NULL);
-    if (jwt != NULL) {
-      char *md_value;
-      gpr_asprintf(&md_value, "Bearer %s", jwt);
-      gpr_free(jwt);
-      c->cached.jwt_expiration =
-          gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime);
-      c->cached.service_url = gpr_strdup(context.service_url);
-      c->cached.jwt_md = grpc_credentials_md_store_create(1);
-      grpc_credentials_md_store_add_cstrings(
-          c->cached.jwt_md, GRPC_AUTHORIZATION_METADATA_KEY, md_value);
-      gpr_free(md_value);
-      jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md);
-    }
-    gpr_mu_unlock(&c->cache_mu);
-  }
-
-  if (jwt_md != NULL) {
-    cb(exec_ctx, user_data, jwt_md->entries, jwt_md->num_entries,
-       GRPC_CREDENTIALS_OK);
-    grpc_credentials_md_store_unref(jwt_md);
-  } else {
-    cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_ERROR);
-  }
-}
-
-static grpc_call_credentials_vtable jwt_vtable = {jwt_destruct,
-                                                  jwt_get_request_metadata};
-
-grpc_call_credentials *
-grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
-    grpc_auth_json_key key, gpr_timespec token_lifetime) {
-  grpc_service_account_jwt_access_credentials *c;
-  if (!grpc_auth_json_key_is_valid(&key)) {
-    gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
-    return NULL;
-  }
-  c = gpr_malloc(sizeof(grpc_service_account_jwt_access_credentials));
-  memset(c, 0, sizeof(grpc_service_account_jwt_access_credentials));
-  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_JWT;
-  gpr_ref_init(&c->base.refcount, 1);
-  c->base.vtable = &jwt_vtable;
-  c->key = key;
-  c->jwt_lifetime = token_lifetime;
-  gpr_mu_init(&c->cache_mu);
-  jwt_reset_cache(c);
-  return &c->base;
-}
-
-grpc_call_credentials *grpc_service_account_jwt_access_credentials_create(
-    const char *json_key, gpr_timespec token_lifetime, void *reserved) {
-  GRPC_API_TRACE(
-      "grpc_service_account_jwt_access_credentials_create("
-      "json_key=%s, "
-      "token_lifetime="
-      "gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
-      "reserved=%p)",
-      5,
-      (json_key, (long long)token_lifetime.tv_sec, (int)token_lifetime.tv_nsec,
-       (int)token_lifetime.clock_type, reserved));
-  GPR_ASSERT(reserved == NULL);
-  return grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
-      grpc_auth_json_key_create_from_string(json_key), token_lifetime);
-}
-
-/* -- Oauth2TokenFetcher credentials -- */
-
-static void oauth2_token_fetcher_destruct(grpc_call_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);
-}
-
-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) {
-  char *null_terminated_body = NULL;
-  char *new_access_token = NULL;
-  grpc_credentials_status status = GRPC_CREDENTIALS_OK;
-  grpc_json *json = NULL;
-
-  if (response == NULL) {
-    gpr_log(GPR_ERROR, "Received NULL response.");
-    status = GRPC_CREDENTIALS_ERROR;
-    goto end;
-  }
-
-  if (response->body_length > 0) {
-    null_terminated_body = gpr_malloc(response->body_length + 1);
-    null_terminated_body[response->body_length] = '\0';
-    memcpy(null_terminated_body, response->body, response->body_length);
-  }
-
-  if (response->status != 200) {
-    gpr_log(GPR_ERROR, "Call to http server ended with error %d [%s].",
-            response->status,
-            null_terminated_body != NULL ? null_terminated_body : "");
-    status = GRPC_CREDENTIALS_ERROR;
-    goto end;
-  } else {
-    grpc_json *access_token = NULL;
-    grpc_json *token_type = NULL;
-    grpc_json *expires_in = NULL;
-    grpc_json *ptr;
-    json = grpc_json_parse_string(null_terminated_body);
-    if (json == NULL) {
-      gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body);
-      status = GRPC_CREDENTIALS_ERROR;
-      goto end;
-    }
-    if (json->type != GRPC_JSON_OBJECT) {
-      gpr_log(GPR_ERROR, "Response should be a JSON object");
-      status = GRPC_CREDENTIALS_ERROR;
-      goto end;
-    }
-    for (ptr = json->child; ptr; ptr = ptr->next) {
-      if (strcmp(ptr->key, "access_token") == 0) {
-        access_token = ptr;
-      } else if (strcmp(ptr->key, "token_type") == 0) {
-        token_type = ptr;
-      } else if (strcmp(ptr->key, "expires_in") == 0) {
-        expires_in = ptr;
-      }
-    }
-    if (access_token == NULL || access_token->type != GRPC_JSON_STRING) {
-      gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON.");
-      status = GRPC_CREDENTIALS_ERROR;
-      goto end;
-    }
-    if (token_type == NULL || token_type->type != GRPC_JSON_STRING) {
-      gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON.");
-      status = GRPC_CREDENTIALS_ERROR;
-      goto end;
-    }
-    if (expires_in == NULL || expires_in->type != GRPC_JSON_NUMBER) {
-      gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON.");
-      status = GRPC_CREDENTIALS_ERROR;
-      goto end;
-    }
-    gpr_asprintf(&new_access_token, "%s %s", token_type->value,
-                 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(
-        *token_md, GRPC_AUTHORIZATION_METADATA_KEY, new_access_token);
-    status = GRPC_CREDENTIALS_OK;
-  }
-
-end:
-  if (status != GRPC_CREDENTIALS_OK && (*token_md != NULL)) {
-    grpc_credentials_md_store_unref(*token_md);
-    *token_md = NULL;
-  }
-  if (null_terminated_body != NULL) gpr_free(null_terminated_body);
-  if (new_access_token != NULL) gpr_free(new_access_token);
-  if (json != NULL) grpc_json_destroy(json);
-  return status;
-}
-
-static void on_oauth2_token_fetcher_http_response(
-    grpc_exec_ctx *exec_ctx, void *user_data,
-    const grpc_httpcli_response *response) {
-  grpc_credentials_metadata_request *r =
-      (grpc_credentials_metadata_request *)user_data;
-  grpc_oauth2_token_fetcher_credentials *c =
-      (grpc_oauth2_token_fetcher_credentials *)r->creds;
-  gpr_timespec token_lifetime;
-  grpc_credentials_status status;
-
-  gpr_mu_lock(&c->mu);
-  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(GPR_CLOCK_REALTIME), token_lifetime);
-    r->cb(exec_ctx, r->user_data, c->access_token_md->entries,
-          c->access_token_md->num_entries, status);
-  } else {
-    c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
-    r->cb(exec_ctx, r->user_data, NULL, 0, status);
-  }
-  gpr_mu_unlock(&c->mu);
-  grpc_credentials_metadata_request_destroy(r);
-}
-
-static void oauth2_token_fetcher_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
-    grpc_pollset *pollset, grpc_auth_metadata_context context,
-    grpc_credentials_metadata_cb cb, void *user_data) {
-  grpc_oauth2_token_fetcher_credentials *c =
-      (grpc_oauth2_token_fetcher_credentials *)creds;
-  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(GPR_CLOCK_REALTIME)),
-             refresh_threshold) > 0)) {
-      cached_access_token_md =
-          grpc_credentials_md_store_ref(c->access_token_md);
-    }
-    gpr_mu_unlock(&c->mu);
-  }
-  if (cached_access_token_md != NULL) {
-    cb(exec_ctx, user_data, cached_access_token_md->entries,
-       cached_access_token_md->num_entries, GRPC_CREDENTIALS_OK);
-    grpc_credentials_md_store_unref(cached_access_token_md);
-  } else {
-    c->fetch_func(
-        exec_ctx,
-        grpc_credentials_metadata_request_create(creds, cb, user_data),
-        &c->httpcli_context, pollset, on_oauth2_token_fetcher_http_response,
-        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold));
-  }
-}
-
-static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c,
-                                      grpc_fetch_oauth2_func fetch_func) {
-  memset(c, 0, sizeof(grpc_oauth2_token_fetcher_credentials));
-  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
-  gpr_ref_init(&c->base.refcount, 1);
-  gpr_mu_init(&c->mu);
-  c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
-  c->fetch_func = fetch_func;
-  grpc_httpcli_context_init(&c->httpcli_context);
-}
-
-/* -- GoogleComputeEngine credentials. -- */
-
-static grpc_call_credentials_vtable compute_engine_vtable = {
-    oauth2_token_fetcher_destruct, oauth2_token_fetcher_get_request_metadata};
-
-static void compute_engine_fetch_oauth2(
-    grpc_exec_ctx *exec_ctx, 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;
-  memset(&request, 0, sizeof(grpc_httpcli_request));
-  request.host = GRPC_COMPUTE_ENGINE_METADATA_HOST;
-  request.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
-  request.hdr_count = 1;
-  request.hdrs = &header;
-  grpc_httpcli_get(exec_ctx, httpcli_context, pollset, &request, deadline,
-                   response_cb, metadata_req);
-}
-
-grpc_call_credentials *grpc_google_compute_engine_credentials_create(
-    void *reserved) {
-  grpc_oauth2_token_fetcher_credentials *c =
-      gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials));
-  GRPC_API_TRACE("grpc_compute_engine_credentials_create(reserved=%p)", 1,
-                 (reserved));
-  GPR_ASSERT(reserved == NULL);
-  init_oauth2_token_fetcher(c, compute_engine_fetch_oauth2);
-  c->base.vtable = &compute_engine_vtable;
-  return &c->base;
-}
-
-/* -- GoogleRefreshToken credentials. -- */
-
-static void refresh_token_destruct(grpc_call_credentials *creds) {
-  grpc_google_refresh_token_credentials *c =
-      (grpc_google_refresh_token_credentials *)creds;
-  grpc_auth_refresh_token_destruct(&c->refresh_token);
-  oauth2_token_fetcher_destruct(&c->base.base);
-}
-
-static grpc_call_credentials_vtable refresh_token_vtable = {
-    refresh_token_destruct, oauth2_token_fetcher_get_request_metadata};
-
-static void refresh_token_fetch_oauth2(
-    grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req,
-    grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
-    grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
-  grpc_google_refresh_token_credentials *c =
-      (grpc_google_refresh_token_credentials *)metadata_req->creds;
-  grpc_httpcli_header header = {"Content-Type",
-                                "application/x-www-form-urlencoded"};
-  grpc_httpcli_request request;
-  char *body = NULL;
-  gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING,
-               c->refresh_token.client_id, c->refresh_token.client_secret,
-               c->refresh_token.refresh_token);
-  memset(&request, 0, sizeof(grpc_httpcli_request));
-  request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST;
-  request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH;
-  request.hdr_count = 1;
-  request.hdrs = &header;
-  request.handshaker = &grpc_httpcli_ssl;
-  grpc_httpcli_post(exec_ctx, httpcli_context, pollset, &request, body,
-                    strlen(body), deadline, response_cb, metadata_req);
-  gpr_free(body);
-}
-
-grpc_call_credentials *
-grpc_refresh_token_credentials_create_from_auth_refresh_token(
-    grpc_auth_refresh_token refresh_token) {
-  grpc_google_refresh_token_credentials *c;
-  if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
-    gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation");
-    return NULL;
-  }
-  c = gpr_malloc(sizeof(grpc_google_refresh_token_credentials));
-  memset(c, 0, sizeof(grpc_google_refresh_token_credentials));
-  init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2);
-  c->base.base.vtable = &refresh_token_vtable;
-  c->refresh_token = refresh_token;
-  return &c->base.base;
-}
-
-grpc_call_credentials *grpc_google_refresh_token_credentials_create(
-    const char *json_refresh_token, void *reserved) {
-  GRPC_API_TRACE(
-      "grpc_refresh_token_credentials_create(json_refresh_token=%s, "
-      "reserved=%p)",
-      2, (json_refresh_token, reserved));
-  GPR_ASSERT(reserved == NULL);
-  return grpc_refresh_token_credentials_create_from_auth_refresh_token(
-      grpc_auth_refresh_token_create_from_string(json_refresh_token));
-}
-
-/* -- Metadata-only credentials. -- */
-
-static void md_only_test_destruct(grpc_call_credentials *creds) {
-  grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
-  grpc_credentials_md_store_unref(c->md_store);
-}
-
-static void on_simulated_token_fetch_done(grpc_exec_ctx *exec_ctx,
-                                          void *user_data, bool success) {
-  grpc_credentials_metadata_request *r =
-      (grpc_credentials_metadata_request *)user_data;
-  grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds;
-  r->cb(exec_ctx, r->user_data, c->md_store->entries, c->md_store->num_entries,
-        GRPC_CREDENTIALS_OK);
-  grpc_credentials_metadata_request_destroy(r);
-}
-
-static void md_only_test_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
-    grpc_pollset *pollset, grpc_auth_metadata_context context,
-    grpc_credentials_metadata_cb cb, void *user_data) {
-  grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
-
-  if (c->is_async) {
-    grpc_credentials_metadata_request *cb_arg =
-        grpc_credentials_metadata_request_create(creds, cb, user_data);
-    grpc_executor_enqueue(
-        grpc_closure_create(on_simulated_token_fetch_done, cb_arg), true);
-  } else {
-    cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK);
-  }
-}
-
-static grpc_call_credentials_vtable md_only_test_vtable = {
-    md_only_test_destruct, md_only_test_get_request_metadata};
-
-grpc_call_credentials *grpc_md_only_test_credentials_create(
-    const char *md_key, const char *md_value, int is_async) {
-  grpc_md_only_test_credentials *c =
-      gpr_malloc(sizeof(grpc_md_only_test_credentials));
-  memset(c, 0, sizeof(grpc_md_only_test_credentials));
-  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
-  c->base.vtable = &md_only_test_vtable;
-  gpr_ref_init(&c->base.refcount, 1);
-  c->md_store = grpc_credentials_md_store_create(1);
-  grpc_credentials_md_store_add_cstrings(c->md_store, md_key, md_value);
-  c->is_async = is_async;
-  return &c->base;
-}
-
-/* -- Oauth2 Access Token credentials. -- */
-
-static void access_token_destruct(grpc_call_credentials *creds) {
-  grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
-  grpc_credentials_md_store_unref(c->access_token_md);
-}
-
-static void access_token_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
-    grpc_pollset *pollset, grpc_auth_metadata_context context,
-    grpc_credentials_metadata_cb cb, void *user_data) {
-  grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
-  cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK);
-}
-
-static grpc_call_credentials_vtable access_token_vtable = {
-    access_token_destruct, access_token_get_request_metadata};
-
-grpc_call_credentials *grpc_access_token_credentials_create(
-    const char *access_token, void *reserved) {
-  grpc_access_token_credentials *c =
-      gpr_malloc(sizeof(grpc_access_token_credentials));
-  char *token_md_value;
-  GRPC_API_TRACE(
-      "grpc_access_token_credentials_create(access_token=%s, "
-      "reserved=%p)",
-      2, (access_token, reserved));
-  GPR_ASSERT(reserved == NULL);
-  memset(c, 0, sizeof(grpc_access_token_credentials));
-  c->base.type = GRPC_CALL_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 grpc_security_status fake_transport_security_create_security_connector(
-    grpc_channel_credentials *c, grpc_call_credentials *call_creds,
-    const char *target, const grpc_channel_args *args,
-    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
-  *sc = grpc_fake_channel_security_connector_create(call_creds);
-  return GRPC_SECURITY_OK;
-}
-
-static grpc_security_status
-fake_transport_security_server_create_security_connector(
-    grpc_server_credentials *c, grpc_server_security_connector **sc) {
-  *sc = grpc_fake_server_security_connector_create();
-  return GRPC_SECURITY_OK;
-}
-
-static grpc_channel_credentials_vtable
-    fake_transport_security_credentials_vtable = {
-        NULL, fake_transport_security_create_security_connector};
-
-static grpc_server_credentials_vtable
-    fake_transport_security_server_credentials_vtable = {
-        NULL, fake_transport_security_server_create_security_connector};
-
-grpc_channel_credentials *grpc_fake_transport_security_credentials_create(
-    void) {
-  grpc_channel_credentials *c = gpr_malloc(sizeof(grpc_channel_credentials));
-  memset(c, 0, sizeof(grpc_channel_credentials));
-  c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
-  c->vtable = &fake_transport_security_credentials_vtable;
-  gpr_ref_init(&c->refcount, 1);
-  return c;
-}
-
-grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
-    void) {
-  grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials));
-  memset(c, 0, sizeof(grpc_server_credentials));
-  c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
-  gpr_ref_init(&c->refcount, 1);
-  c->vtable = &fake_transport_security_server_credentials_vtable;
-  return c;
-}
-
-/* -- Composite call credentials. -- */
-
-typedef struct {
-  grpc_composite_call_credentials *composite_creds;
-  size_t creds_index;
-  grpc_credentials_md_store *md_elems;
-  grpc_auth_metadata_context auth_md_context;
-  void *user_data;
-  grpc_pollset *pollset;
-  grpc_credentials_metadata_cb cb;
-} grpc_composite_call_credentials_metadata_context;
-
-static void composite_call_destruct(grpc_call_credentials *creds) {
-  grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
-  size_t i;
-  for (i = 0; i < c->inner.num_creds; i++) {
-    grpc_call_credentials_unref(c->inner.creds_array[i]);
-  }
-  gpr_free(c->inner.creds_array);
-}
-
-static void composite_call_md_context_destroy(
-    grpc_composite_call_credentials_metadata_context *ctx) {
-  grpc_credentials_md_store_unref(ctx->md_elems);
-  gpr_free(ctx);
-}
-
-static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
-                                       grpc_credentials_md *md_elems,
-                                       size_t num_md,
-                                       grpc_credentials_status status) {
-  grpc_composite_call_credentials_metadata_context *ctx =
-      (grpc_composite_call_credentials_metadata_context *)user_data;
-  if (status != GRPC_CREDENTIALS_OK) {
-    ctx->cb(exec_ctx, ctx->user_data, NULL, 0, status);
-    return;
-  }
-
-  /* Copy the metadata in the context. */
-  if (num_md > 0) {
-    size_t i;
-    for (i = 0; i < num_md; i++) {
-      grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key,
-                                    md_elems[i].value);
-    }
-  }
-
-  /* See if we need to get some more metadata. */
-  if (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
-    grpc_call_credentials *inner_creds =
-        ctx->composite_creds->inner.creds_array[ctx->creds_index++];
-    grpc_call_credentials_get_request_metadata(
-        exec_ctx, inner_creds, ctx->pollset, ctx->auth_md_context,
-        composite_call_metadata_cb, ctx);
-    return;
-  }
-
-  /* We're done!. */
-  ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries,
-          ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK);
-  composite_call_md_context_destroy(ctx);
-}
-
-static void composite_call_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
-    grpc_pollset *pollset, grpc_auth_metadata_context auth_md_context,
-    grpc_credentials_metadata_cb cb, void *user_data) {
-  grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
-  grpc_composite_call_credentials_metadata_context *ctx;
-
-  ctx = gpr_malloc(sizeof(grpc_composite_call_credentials_metadata_context));
-  memset(ctx, 0, sizeof(grpc_composite_call_credentials_metadata_context));
-  ctx->auth_md_context = auth_md_context;
-  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);
-  grpc_call_credentials_get_request_metadata(
-      exec_ctx, c->inner.creds_array[ctx->creds_index++], pollset,
-      auth_md_context, composite_call_metadata_cb, ctx);
-}
-
-static grpc_call_credentials_vtable composite_call_credentials_vtable = {
-    composite_call_destruct, composite_call_get_request_metadata};
-
-static grpc_call_credentials_array get_creds_array(
-    grpc_call_credentials **creds_addr) {
-  grpc_call_credentials_array result;
-  grpc_call_credentials *creds = *creds_addr;
-  result.creds_array = creds_addr;
-  result.num_creds = 1;
-  if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
-    result = *grpc_composite_call_credentials_get_credentials(creds);
-  }
-  return result;
-}
-
-grpc_call_credentials *grpc_composite_call_credentials_create(
-    grpc_call_credentials *creds1, grpc_call_credentials *creds2,
-    void *reserved) {
-  size_t i;
-  size_t creds_array_byte_size;
-  grpc_call_credentials_array creds1_array;
-  grpc_call_credentials_array creds2_array;
-  grpc_composite_call_credentials *c;
-  GRPC_API_TRACE(
-      "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, "
-      "reserved=%p)",
-      3, (creds1, creds2, reserved));
-  GPR_ASSERT(reserved == NULL);
-  GPR_ASSERT(creds1 != NULL);
-  GPR_ASSERT(creds2 != NULL);
-  c = gpr_malloc(sizeof(grpc_composite_call_credentials));
-  memset(c, 0, sizeof(grpc_composite_call_credentials));
-  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE;
-  c->base.vtable = &composite_call_credentials_vtable;
-  gpr_ref_init(&c->base.refcount, 1);
-  creds1_array = get_creds_array(&creds1);
-  creds2_array = get_creds_array(&creds2);
-  c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
-  creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials *);
-  c->inner.creds_array = gpr_malloc(creds_array_byte_size);
-  memset(c->inner.creds_array, 0, creds_array_byte_size);
-  for (i = 0; i < creds1_array.num_creds; i++) {
-    grpc_call_credentials *cur_creds = creds1_array.creds_array[i];
-    c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds);
-  }
-  for (i = 0; i < creds2_array.num_creds; i++) {
-    grpc_call_credentials *cur_creds = creds2_array.creds_array[i];
-    c->inner.creds_array[i + creds1_array.num_creds] =
-        grpc_call_credentials_ref(cur_creds);
-  }
-  return &c->base;
-}
-
-const grpc_call_credentials_array *
-grpc_composite_call_credentials_get_credentials(grpc_call_credentials *creds) {
-  const grpc_composite_call_credentials *c =
-      (const grpc_composite_call_credentials *)creds;
-  GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
-  return &c->inner;
-}
-
-grpc_call_credentials *grpc_credentials_contains_type(
-    grpc_call_credentials *creds, const char *type,
-    grpc_call_credentials **composite_creds) {
-  size_t i;
-  if (strcmp(creds->type, type) == 0) {
-    if (composite_creds != NULL) *composite_creds = NULL;
-    return creds;
-  } else if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
-    const grpc_call_credentials_array *inner_creds_array =
-        grpc_composite_call_credentials_get_credentials(creds);
-    for (i = 0; i < inner_creds_array->num_creds; i++) {
-      if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) {
-        if (composite_creds != NULL) *composite_creds = creds;
-        return inner_creds_array->creds_array[i];
-      }
-    }
-  }
-  return NULL;
-}
-
-/* -- IAM credentials. -- */
-
-static void iam_destruct(grpc_call_credentials *creds) {
-  grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
-  grpc_credentials_md_store_unref(c->iam_md);
-}
-
-static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx,
-                                     grpc_call_credentials *creds,
-                                     grpc_pollset *pollset,
-                                     grpc_auth_metadata_context context,
-                                     grpc_credentials_metadata_cb cb,
-                                     void *user_data) {
-  grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
-  cb(exec_ctx, user_data, c->iam_md->entries, c->iam_md->num_entries,
-     GRPC_CREDENTIALS_OK);
-}
-
-static grpc_call_credentials_vtable iam_vtable = {iam_destruct,
-                                                  iam_get_request_metadata};
-
-grpc_call_credentials *grpc_google_iam_credentials_create(
-    const char *token, const char *authority_selector, void *reserved) {
-  grpc_google_iam_credentials *c;
-  GRPC_API_TRACE(
-      "grpc_iam_credentials_create(token=%s, authority_selector=%s, "
-      "reserved=%p)",
-      3, (token, authority_selector, reserved));
-  GPR_ASSERT(reserved == NULL);
-  GPR_ASSERT(token != NULL);
-  GPR_ASSERT(authority_selector != NULL);
-  c = gpr_malloc(sizeof(grpc_google_iam_credentials));
-  memset(c, 0, sizeof(grpc_google_iam_credentials));
-  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_IAM;
-  c->base.vtable = &iam_vtable;
-  gpr_ref_init(&c->base.refcount, 1);
-  c->iam_md = grpc_credentials_md_store_create(2);
-  grpc_credentials_md_store_add_cstrings(
-      c->iam_md, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token);
-  grpc_credentials_md_store_add_cstrings(
-      c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector);
-  return &c->base;
-}
-
-/* -- Plugin credentials. -- */
-
-typedef struct {
-  void *user_data;
-  grpc_credentials_metadata_cb cb;
-} grpc_metadata_plugin_request;
-
-static void plugin_destruct(grpc_call_credentials *creds) {
-  grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
-  if (c->plugin.state != NULL && c->plugin.destroy != NULL) {
-    c->plugin.destroy(c->plugin.state);
-  }
-}
-
-static void plugin_md_request_metadata_ready(void *request,
-                                             const grpc_metadata *md,
-                                             size_t num_md,
-                                             grpc_status_code status,
-                                             const char *error_details) {
-  /* called from application code */
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_metadata_plugin_request *r = (grpc_metadata_plugin_request *)request;
-  if (status != GRPC_STATUS_OK) {
-    if (error_details != NULL) {
-      gpr_log(GPR_ERROR, "Getting metadata from plugin failed with error: %s",
-              error_details);
-    }
-    r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR);
-  } else {
-    size_t i;
-    grpc_credentials_md *md_array = NULL;
-    if (num_md > 0) {
-      md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md));
-      for (i = 0; i < num_md; i++) {
-        md_array[i].key = gpr_slice_from_copied_string(md[i].key);
-        md_array[i].value =
-            gpr_slice_from_copied_buffer(md[i].value, md[i].value_length);
-      }
-    }
-    r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK);
-    if (md_array != NULL) {
-      for (i = 0; i < num_md; i++) {
-        gpr_slice_unref(md_array[i].key);
-        gpr_slice_unref(md_array[i].value);
-      }
-      gpr_free(md_array);
-    }
-  }
-  gpr_free(r);
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx,
-                                        grpc_call_credentials *creds,
-                                        grpc_pollset *pollset,
-                                        grpc_auth_metadata_context context,
-                                        grpc_credentials_metadata_cb cb,
-                                        void *user_data) {
-  grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
-  if (c->plugin.get_metadata != NULL) {
-    grpc_metadata_plugin_request *request = gpr_malloc(sizeof(*request));
-    memset(request, 0, sizeof(*request));
-    request->user_data = user_data;
-    request->cb = cb;
-    c->plugin.get_metadata(c->plugin.state, context,
-                           plugin_md_request_metadata_ready, request);
-  } else {
-    cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
-  }
-}
-
-static grpc_call_credentials_vtable plugin_vtable = {
-    plugin_destruct, plugin_get_request_metadata};
-
-grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
-    grpc_metadata_credentials_plugin plugin, void *reserved) {
-  grpc_plugin_credentials *c = gpr_malloc(sizeof(*c));
-  GRPC_API_TRACE("grpc_metadata_credentials_create_from_plugin(reserved=%p)", 1,
-                 (reserved));
-  GPR_ASSERT(reserved == NULL);
-  memset(c, 0, sizeof(*c));
-  c->base.type = plugin.type;
-  c->base.vtable = &plugin_vtable;
-  gpr_ref_init(&c->base.refcount, 1);
-  c->plugin = plugin;
-  return &c->base;
-}
-
-/* -- Composite channel credentials. -- */
-
-static void composite_channel_destruct(grpc_channel_credentials *creds) {
-  grpc_composite_channel_credentials *c =
-      (grpc_composite_channel_credentials *)creds;
-  grpc_channel_credentials_unref(c->inner_creds);
-  grpc_call_credentials_unref(c->call_creds);
-}
-
-static grpc_security_status composite_channel_create_security_connector(
-    grpc_channel_credentials *creds, grpc_call_credentials *call_creds,
-    const char *target, const grpc_channel_args *args,
-    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
-  grpc_composite_channel_credentials *c =
-      (grpc_composite_channel_credentials *)creds;
-  grpc_security_status status = GRPC_SECURITY_ERROR;
-
-  GPR_ASSERT(c->inner_creds != NULL && c->call_creds != NULL &&
-             c->inner_creds->vtable != NULL &&
-             c->inner_creds->vtable->create_security_connector != NULL);
-  /* If we are passed a call_creds, create a call composite to pass it
-     downstream. */
-  if (call_creds != NULL) {
-    grpc_call_credentials *composite_call_creds =
-        grpc_composite_call_credentials_create(c->call_creds, call_creds, NULL);
-    status = c->inner_creds->vtable->create_security_connector(
-        c->inner_creds, composite_call_creds, target, args, sc, new_args);
-    grpc_call_credentials_unref(composite_call_creds);
-  } else {
-    status = c->inner_creds->vtable->create_security_connector(
-        c->inner_creds, c->call_creds, target, args, sc, new_args);
-  }
-  return status;
-}
-
-static grpc_channel_credentials_vtable composite_channel_credentials_vtable = {
-    composite_channel_destruct, composite_channel_create_security_connector};
-
-grpc_channel_credentials *grpc_composite_channel_credentials_create(
-    grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds,
-    void *reserved) {
-  grpc_composite_channel_credentials *c = gpr_malloc(sizeof(*c));
-  memset(c, 0, sizeof(*c));
-  GPR_ASSERT(channel_creds != NULL && call_creds != NULL && reserved == NULL);
-  GRPC_API_TRACE(
-      "grpc_composite_channel_credentials_create(channel_creds=%p, "
-      "call_creds=%p, reserved=%p)",
-      3, (channel_creds, call_creds, reserved));
-  c->base.type = channel_creds->type;
-  c->base.vtable = &composite_channel_credentials_vtable;
-  gpr_ref_init(&c->base.refcount, 1);
-  c->inner_creds = grpc_channel_credentials_ref(channel_creds);
-  c->call_creds = grpc_call_credentials_ref(call_creds);
-  return &c->base;
-}
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
deleted file mode 100644
index 0de4cd9..0000000
--- a/src/core/security/credentials.h
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H
-#define GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H
-
-#include "src/core/transport/metadata_batch.h"
-#include <grpc/grpc.h>
-#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;
-
-/* --- Constants. --- */
-
-typedef enum {
-  GRPC_CREDENTIALS_OK = 0,
-  GRPC_CREDENTIALS_ERROR
-} grpc_credentials_status;
-
-#define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake"
-
-#define GRPC_CHANNEL_CREDENTIALS_TYPE_SSL "Ssl"
-#define GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY \
-  "FakeTransportSecurity"
-
-#define GRPC_CALL_CREDENTIALS_TYPE_OAUTH2 "Oauth2"
-#define GRPC_CALL_CREDENTIALS_TYPE_JWT "Jwt"
-#define GRPC_CALL_CREDENTIALS_TYPE_IAM "Iam"
-#define GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE "Composite"
-
-#define GRPC_AUTHORIZATION_METADATA_KEY "authorization"
-#define GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY \
-  "x-goog-iam-authorization-token"
-#define GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY "x-goog-iam-authority-selector"
-
-#define GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY "gcloud"
-#define GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE \
-  "application_default_credentials.json"
-
-#define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60
-
-#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata"
-#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
-  "/computeMetadata/v1/instance/service-accounts/default/token"
-
-#define GRPC_GOOGLE_OAUTH2_SERVICE_HOST "www.googleapis.com"
-#define GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH "/oauth2/v3/token"
-
-#define GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX                         \
-  "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" \
-  "assertion="
-
-#define GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING \
-  "client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token"
-
-/* --- Google utils --- */
-
-/* It is the caller's responsibility to gpr_free the result if not NULL. */
-char *grpc_get_well_known_google_credentials_file_path(void);
-
-/* Implementation function for the different platforms. */
-char *grpc_get_well_known_google_credentials_file_path_impl(void);
-
-/* Override for testing only. Not thread-safe */
-typedef char *(*grpc_well_known_credentials_path_getter)(void);
-void grpc_override_well_known_credentials_path_getter(
-    grpc_well_known_credentials_path_getter getter);
-
-/* --- grpc_channel_credentials. --- */
-
-typedef struct {
-  void (*destruct)(grpc_channel_credentials *c);
-
-  grpc_security_status (*create_security_connector)(
-      grpc_channel_credentials *c, grpc_call_credentials *call_creds,
-      const char *target, const grpc_channel_args *args,
-      grpc_channel_security_connector **sc, grpc_channel_args **new_args);
-} grpc_channel_credentials_vtable;
-
-struct grpc_channel_credentials {
-  const grpc_channel_credentials_vtable *vtable;
-  const char *type;
-  gpr_refcount refcount;
-};
-
-grpc_channel_credentials *grpc_channel_credentials_ref(
-    grpc_channel_credentials *creds);
-void grpc_channel_credentials_unref(grpc_channel_credentials *creds);
-
-/* Creates a security connector for the channel. May also create new channel
-   args for the channel to be used in place of the passed in const args if
-   returned non NULL. In that case the caller is responsible for destroying
-   new_args after channel creation. */
-grpc_security_status grpc_channel_credentials_create_security_connector(
-    grpc_channel_credentials *creds, const char *target,
-    const grpc_channel_args *args, grpc_channel_security_connector **sc,
-    grpc_channel_args **new_args);
-
-/* --- grpc_credentials_md. --- */
-
-typedef struct {
-  gpr_slice key;
-  gpr_slice value;
-} grpc_credentials_md;
-
-typedef struct {
-  grpc_credentials_md *entries;
-  size_t num_entries;
-  size_t allocated;
-  gpr_refcount refcount;
-} grpc_credentials_md_store;
-
-grpc_credentials_md_store *grpc_credentials_md_store_create(
-    size_t initial_capacity);
-
-/* Will ref key and value. */
-void grpc_credentials_md_store_add(grpc_credentials_md_store *store,
-                                   gpr_slice key, gpr_slice value);
-void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store,
-                                            const char *key, const char *value);
-grpc_credentials_md_store *grpc_credentials_md_store_ref(
-    grpc_credentials_md_store *store);
-void grpc_credentials_md_store_unref(grpc_credentials_md_store *store);
-
-/* --- grpc_call_credentials. --- */
-
-typedef void (*grpc_credentials_metadata_cb)(grpc_exec_ctx *exec_ctx,
-                                             void *user_data,
-                                             grpc_credentials_md *md_elems,
-                                             size_t num_md,
-                                             grpc_credentials_status status);
-
-typedef struct {
-  void (*destruct)(grpc_call_credentials *c);
-  void (*get_request_metadata)(grpc_exec_ctx *exec_ctx,
-                               grpc_call_credentials *c, grpc_pollset *pollset,
-                               grpc_auth_metadata_context context,
-                               grpc_credentials_metadata_cb cb,
-                               void *user_data);
-} grpc_call_credentials_vtable;
-
-struct grpc_call_credentials {
-  const grpc_call_credentials_vtable *vtable;
-  const char *type;
-  gpr_refcount refcount;
-};
-
-grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds);
-void grpc_call_credentials_unref(grpc_call_credentials *creds);
-void grpc_call_credentials_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
-    grpc_pollset *pollset, grpc_auth_metadata_context context,
-    grpc_credentials_metadata_cb cb, void *user_data);
-
-typedef struct {
-  grpc_call_credentials **creds_array;
-  size_t num_creds;
-} grpc_call_credentials_array;
-
-const grpc_call_credentials_array *
-grpc_composite_call_credentials_get_credentials(
-    grpc_call_credentials *composite_creds);
-
-/* Returns creds if creds is of the specified type or the inner creds of the
-   specified type (if found), if the creds is of type COMPOSITE.
-   If composite_creds is not NULL, *composite_creds will point to creds if of
-   type COMPOSITE in case of success. */
-grpc_call_credentials *grpc_credentials_contains_type(
-    grpc_call_credentials *creds, const char *type,
-    grpc_call_credentials **composite_creds);
-
-/* 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);
-
-void grpc_flush_cached_google_default_credentials(void);
-
-/* Metadata-only credentials with the specified key and value where
-   asynchronicity can be simulated for testing. */
-grpc_call_credentials *grpc_md_only_test_credentials_create(
-    const char *md_key, const char *md_value, int is_async);
-
-/* Private constructor for jwt credentials from an already parsed json key.
-   Takes ownership of the key. */
-grpc_call_credentials *
-grpc_service_account_jwt_access_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_call_credentials *
-grpc_refresh_token_credentials_create_from_auth_refresh_token(
-    grpc_auth_refresh_token token);
-
-/* --- grpc_server_credentials. --- */
-
-typedef struct {
-  void (*destruct)(grpc_server_credentials *c);
-  grpc_security_status (*create_security_connector)(
-      grpc_server_credentials *c, grpc_server_security_connector **sc);
-} grpc_server_credentials_vtable;
-
-struct grpc_server_credentials {
-  const grpc_server_credentials_vtable *vtable;
-  const char *type;
-  gpr_refcount refcount;
-  grpc_auth_metadata_processor processor;
-};
-
-grpc_security_status grpc_server_credentials_create_security_connector(
-    grpc_server_credentials *creds, grpc_server_security_connector **sc);
-
-grpc_server_credentials *grpc_server_credentials_ref(
-    grpc_server_credentials *creds);
-
-void grpc_server_credentials_unref(grpc_server_credentials *creds);
-
-#define GRPC_SERVER_CREDENTIALS_ARG "grpc.server_credentials"
-
-grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *c);
-grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg);
-grpc_server_credentials *grpc_find_server_credentials_in_args(
-    const grpc_channel_args *args);
-
-/* -- Fake transport security credentials. -- */
-
-/* Creates a fake transport security credentials object for testing. */
-grpc_channel_credentials *grpc_fake_transport_security_credentials_create(void);
-/* Creates a fake server transport security credentials object for testing. */
-grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
-    void);
-
-/* -- Ssl credentials. -- */
-
-typedef struct {
-  grpc_channel_credentials base;
-  grpc_ssl_config config;
-} grpc_ssl_credentials;
-
-typedef struct {
-  grpc_server_credentials base;
-  grpc_ssl_server_config config;
-} grpc_ssl_server_credentials;
-
-/* -- Channel composite credentials. -- */
-
-typedef struct {
-  grpc_channel_credentials base;
-  grpc_channel_credentials *inner_creds;
-  grpc_call_credentials *call_creds;
-} grpc_composite_channel_credentials;
-
-/* -- Jwt credentials -- */
-
-typedef struct {
-  grpc_call_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_service_account_jwt_access_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_exec_ctx *exec_ctx,
-                                       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_call_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;
-
-/* -- GoogleRefreshToken credentials. -- */
-
-typedef struct {
-  grpc_oauth2_token_fetcher_credentials base;
-  grpc_auth_refresh_token refresh_token;
-} grpc_google_refresh_token_credentials;
-
-/* -- Oauth2 Access Token credentials. -- */
-
-typedef struct {
-  grpc_call_credentials base;
-  grpc_credentials_md_store *access_token_md;
-} grpc_access_token_credentials;
-
-/* --  Metadata-only Test credentials. -- */
-
-typedef struct {
-  grpc_call_credentials base;
-  grpc_credentials_md_store *md_store;
-  int is_async;
-} grpc_md_only_test_credentials;
-
-/* -- GoogleIAM credentials. -- */
-
-typedef struct {
-  grpc_call_credentials base;
-  grpc_credentials_md_store *iam_md;
-} grpc_google_iam_credentials;
-
-/* -- Composite credentials. -- */
-
-typedef struct {
-  grpc_call_credentials base;
-  grpc_call_credentials_array inner;
-} grpc_composite_call_credentials;
-
-/* -- Plugin credentials. -- */
-
-typedef struct {
-  grpc_call_credentials base;
-  grpc_metadata_credentials_plugin plugin;
-  grpc_credentials_md_store *plugin_md;
-} grpc_plugin_credentials;
-
-#endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */
diff --git a/src/core/security/credentials_metadata.c b/src/core/security/credentials_metadata.c
deleted file mode 100644
index b8a132f..0000000
--- a/src/core/security/credentials_metadata.c
+++ /dev/null
@@ -1,101 +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/security/credentials.h"
-
-#include <grpc/support/alloc.h>
-
-#include <string.h>
-
-static void store_ensure_capacity(grpc_credentials_md_store *store) {
-  if (store->num_entries == store->allocated) {
-    store->allocated = (store->allocated == 0) ? 1 : store->allocated * 2;
-    store->entries = gpr_realloc(
-        store->entries, store->allocated * sizeof(grpc_credentials_md));
-  }
-}
-
-grpc_credentials_md_store *grpc_credentials_md_store_create(
-    size_t initial_capacity) {
-  grpc_credentials_md_store *store =
-      gpr_malloc(sizeof(grpc_credentials_md_store));
-  memset(store, 0, sizeof(grpc_credentials_md_store));
-  if (initial_capacity > 0) {
-    store->entries = gpr_malloc(initial_capacity * sizeof(grpc_credentials_md));
-    store->allocated = initial_capacity;
-  }
-  gpr_ref_init(&store->refcount, 1);
-  return store;
-}
-
-void grpc_credentials_md_store_add(grpc_credentials_md_store *store,
-                                   gpr_slice key, gpr_slice value) {
-  if (store == NULL) return;
-  store_ensure_capacity(store);
-  store->entries[store->num_entries].key = gpr_slice_ref(key);
-  store->entries[store->num_entries].value = gpr_slice_ref(value);
-  store->num_entries++;
-}
-
-void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store,
-                                            const char *key,
-                                            const char *value) {
-  if (store == NULL) return;
-  store_ensure_capacity(store);
-  store->entries[store->num_entries].key = gpr_slice_from_copied_string(key);
-  store->entries[store->num_entries].value =
-      gpr_slice_from_copied_string(value);
-  store->num_entries++;
-}
-
-grpc_credentials_md_store *grpc_credentials_md_store_ref(
-    grpc_credentials_md_store *store) {
-  if (store == NULL) return NULL;
-  gpr_ref(&store->refcount);
-  return store;
-}
-
-void grpc_credentials_md_store_unref(grpc_credentials_md_store *store) {
-  if (store == NULL) return;
-  if (gpr_unref(&store->refcount)) {
-    if (store->entries != NULL) {
-      size_t i;
-      for (i = 0; i < store->num_entries; i++) {
-        gpr_slice_unref(store->entries[i].key);
-        gpr_slice_unref(store->entries[i].value);
-      }
-      gpr_free(store->entries);
-    }
-    gpr_free(store);
-  }
-}
diff --git a/src/core/security/credentials_posix.c b/src/core/security/credentials_posix.c
deleted file mode 100644
index 0c92bd4..0000000
--- a/src/core/security/credentials_posix.c
+++ /dev/null
@@ -1,61 +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/support/port_platform.h>
-
-#ifdef GPR_POSIX_FILE
-
-#include "src/core/security/credentials.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/support/env.h"
-#include "src/core/support/string.h"
-
-char *grpc_get_well_known_google_credentials_file_path_impl(void) {
-  char *result = NULL;
-  char *home = gpr_getenv("HOME");
-  if (home == NULL) {
-    gpr_log(GPR_ERROR, "Could not get HOME environment variable.");
-    return NULL;
-  }
-  gpr_asprintf(&result, "%s/.config/%s/%s", home,
-               GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY,
-               GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE);
-  gpr_free(home);
-  return result;
-}
-
-#endif /* GPR_POSIX_FILE */
diff --git a/src/core/security/credentials_win32.c b/src/core/security/credentials_win32.c
deleted file mode 100644
index 8ee9f70..0000000
--- a/src/core/security/credentials_win32.c
+++ /dev/null
@@ -1,61 +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/support/port_platform.h>
-
-#ifdef GPR_WIN32
-
-#include "src/core/security/credentials.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/support/env.h"
-#include "src/core/support/string.h"
-
-char *grpc_get_well_known_google_credentials_file_path_impl(void) {
-  char *result = NULL;
-  char *appdata_path = gpr_getenv("APPDATA");
-  if (appdata_path == NULL) {
-    gpr_log(GPR_ERROR, "Could not get APPDATA environment variable.");
-    return NULL;
-  }
-  gpr_asprintf(&result, "%s/%s/%s", appdata_path,
-               GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY,
-               GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE);
-  gpr_free(appdata_path);
-  return result;
-}
-
-#endif /* GPR_WIN32 */
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
deleted file mode 100644
index 1f4f3e4..0000000
--- a/src/core/security/google_default_credentials.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/security/credentials.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-
-#include "src/core/httpcli/httpcli.h"
-#include "src/core/support/env.h"
-#include "src/core/support/load_file.h"
-#include "src/core/surface/api_trace.h"
-
-/* -- Constants. -- */
-
-#define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal"
-
-/* -- Default credentials. -- */
-
-static grpc_channel_credentials *default_credentials = NULL;
-static int compute_engine_detection_done = 0;
-static gpr_mu g_state_mu;
-static gpr_mu *g_polling_mu;
-static gpr_once g_once = GPR_ONCE_INIT;
-
-static void init_default_credentials(void) { gpr_mu_init(&g_state_mu); }
-
-typedef struct {
-  grpc_pollset *pollset;
-  int is_done;
-  int success;
-} compute_engine_detector;
-
-static void on_compute_engine_detection_http_response(
-    grpc_exec_ctx *exec_ctx, void *user_data,
-    const grpc_httpcli_response *response) {
-  compute_engine_detector *detector = (compute_engine_detector *)user_data;
-  if (response != NULL && response->status == 200 && response->hdr_count > 0) {
-    /* Internet providers can return a generic response to all requests, so
-       it is necessary to check that metadata header is present also. */
-    size_t i;
-    for (i = 0; i < response->hdr_count; i++) {
-      grpc_httpcli_header *header = &response->hdrs[i];
-      if (strcmp(header->key, "Metadata-Flavor") == 0 &&
-          strcmp(header->value, "Google") == 0) {
-        detector->success = 1;
-        break;
-      }
-    }
-  }
-  gpr_mu_lock(g_polling_mu);
-  detector->is_done = 1;
-  grpc_pollset_kick(detector->pollset, NULL);
-  gpr_mu_unlock(g_polling_mu);
-}
-
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool s) {
-  grpc_pollset_destroy(p);
-}
-
-static int is_stack_running_on_compute_engine(void) {
-  compute_engine_detector detector;
-  grpc_httpcli_request request;
-  grpc_httpcli_context context;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_closure destroy_closure;
-
-  /* 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 = gpr_time_from_seconds(1, GPR_TIMESPAN);
-
-  detector.pollset = gpr_malloc(grpc_pollset_size());
-  grpc_pollset_init(detector.pollset, &g_polling_mu);
-  detector.is_done = 0;
-  detector.success = 0;
-
-  memset(&request, 0, sizeof(grpc_httpcli_request));
-  request.host = GRPC_COMPUTE_ENGINE_DETECTION_HOST;
-  request.path = "/";
-
-  grpc_httpcli_context_init(&context);
-
-  grpc_httpcli_get(
-      &exec_ctx, &context, detector.pollset, &request,
-      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay),
-      on_compute_engine_detection_http_response, &detector);
-
-  grpc_exec_ctx_finish(&exec_ctx);
-
-  /* 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(g_polling_mu);
-  while (!detector.is_done) {
-    grpc_pollset_worker *worker = NULL;
-    grpc_pollset_work(&exec_ctx, detector.pollset, &worker,
-                      gpr_now(GPR_CLOCK_MONOTONIC),
-                      gpr_inf_future(GPR_CLOCK_MONOTONIC));
-  }
-  gpr_mu_unlock(g_polling_mu);
-
-  grpc_httpcli_context_destroy(&context);
-  grpc_closure_init(&destroy_closure, destroy_pollset, detector.pollset);
-  grpc_pollset_shutdown(&exec_ctx, detector.pollset, &destroy_closure);
-  grpc_exec_ctx_finish(&exec_ctx);
-  g_polling_mu = NULL;
-
-  gpr_free(detector.pollset);
-
-  return detector.success;
-}
-
-/* Takes ownership of creds_path if not NULL. */
-static grpc_call_credentials *create_default_creds_from_path(char *creds_path) {
-  grpc_json *json = NULL;
-  grpc_auth_json_key key;
-  grpc_auth_refresh_token token;
-  grpc_call_credentials *result = NULL;
-  gpr_slice creds_data = gpr_empty_slice();
-  int file_ok = 0;
-  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;
-
-  /* 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_service_account_jwt_access_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;
-}
-
-grpc_channel_credentials *grpc_google_default_credentials_create(void) {
-  grpc_channel_credentials *result = NULL;
-  grpc_call_credentials *call_creds = NULL;
-
-  GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ());
-
-  gpr_once_init(&g_once, init_default_credentials);
-
-  gpr_mu_lock(&g_state_mu);
-
-  if (default_credentials != NULL) {
-    result = grpc_channel_credentials_ref(default_credentials);
-    goto end;
-  }
-
-  /* First, try the environment variable. */
-  call_creds = create_default_creds_from_path(
-      gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR));
-  if (call_creds != NULL) goto end;
-
-  /* Then the well-known file. */
-  call_creds = create_default_creds_from_path(
-      grpc_get_well_known_google_credentials_file_path());
-  if (call_creds != NULL) goto end;
-
-  /* At last try to see if we're on compute engine (do the detection only once
-     since it requires a network test). */
-  if (!compute_engine_detection_done) {
-    int need_compute_engine_creds = is_stack_running_on_compute_engine();
-    compute_engine_detection_done = 1;
-    if (need_compute_engine_creds) {
-      call_creds = grpc_google_compute_engine_credentials_create(NULL);
-    }
-  }
-
-end:
-  if (result == NULL) {
-    if (call_creds != NULL) {
-      /* Blend with default ssl credentials and add a global reference so that
-         it
-         can be cached and re-served. */
-      grpc_channel_credentials *ssl_creds =
-          grpc_ssl_credentials_create(NULL, NULL, NULL);
-      default_credentials = grpc_channel_credentials_ref(
-          grpc_composite_channel_credentials_create(ssl_creds, call_creds,
-                                                    NULL));
-      GPR_ASSERT(default_credentials != NULL);
-      grpc_channel_credentials_unref(ssl_creds);
-      grpc_call_credentials_unref(call_creds);
-      result = default_credentials;
-    } else {
-      gpr_log(GPR_ERROR, "Could not create google default credentials.");
-    }
-  }
-  gpr_mu_unlock(&g_state_mu);
-  return result;
-}
-
-void grpc_flush_cached_google_default_credentials(void) {
-  gpr_once_init(&g_once, init_default_credentials);
-  gpr_mu_lock(&g_state_mu);
-  if (default_credentials != NULL) {
-    grpc_channel_credentials_unref(default_credentials);
-    default_credentials = NULL;
-  }
-  compute_engine_detection_done = 0;
-  gpr_mu_unlock(&g_state_mu);
-}
-
-/* -- Well known credentials path. -- */
-
-static grpc_well_known_credentials_path_getter creds_path_getter = NULL;
-
-char *grpc_get_well_known_google_credentials_file_path(void) {
-  if (creds_path_getter != NULL) return creds_path_getter();
-  return grpc_get_well_known_google_credentials_file_path_impl();
-}
-
-void grpc_override_well_known_credentials_path_getter(
-    grpc_well_known_credentials_path_getter getter) {
-  creds_path_getter = getter;
-}
diff --git a/src/core/security/handshake.c b/src/core/security/handshake.c
deleted file mode 100644
index b5bb666..0000000
--- a/src/core/security/handshake.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/security/handshake.h"
-
-#include <stdbool.h>
-#include <string.h>
-
-#include "src/core/security/security_context.h"
-#include "src/core/security/secure_endpoint.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
-
-#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256
-
-typedef struct {
-  grpc_security_connector *connector;
-  tsi_handshaker *handshaker;
-  bool is_client_side;
-  unsigned char *handshake_buffer;
-  size_t handshake_buffer_size;
-  grpc_endpoint *wrapped_endpoint;
-  grpc_endpoint *secure_endpoint;
-  gpr_slice_buffer left_overs;
-  gpr_slice_buffer incoming;
-  gpr_slice_buffer outgoing;
-  grpc_security_handshake_done_cb cb;
-  void *user_data;
-  grpc_closure on_handshake_data_sent_to_peer;
-  grpc_closure on_handshake_data_received_from_peer;
-  grpc_auth_context *auth_context;
-} grpc_security_handshake;
-
-static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
-                                                 void *setup, bool success);
-
-static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup,
-                                           bool success);
-
-static void security_connector_remove_handshake(grpc_security_handshake *h) {
-  GPR_ASSERT(!h->is_client_side);
-  grpc_security_connector_handshake_list *node;
-  grpc_security_connector_handshake_list *tmp;
-  grpc_server_security_connector *sc =
-      (grpc_server_security_connector *)h->connector;
-  gpr_mu_lock(&sc->mu);
-  node = sc->handshaking_handshakes;
-  if (node && node->handshake == h) {
-    sc->handshaking_handshakes = node->next;
-    gpr_free(node);
-    gpr_mu_unlock(&sc->mu);
-    return;
-  }
-  while (node) {
-    if (node->next->handshake == h) {
-      tmp = node->next;
-      node->next = node->next->next;
-      gpr_free(tmp);
-      gpr_mu_unlock(&sc->mu);
-      return;
-    }
-    node = node->next;
-  }
-  gpr_mu_unlock(&sc->mu);
-}
-
-static void security_handshake_done(grpc_exec_ctx *exec_ctx,
-                                    grpc_security_handshake *h,
-                                    int is_success) {
-  if (!h->is_client_side) {
-    security_connector_remove_handshake(h);
-  }
-  if (is_success) {
-    h->cb(exec_ctx, h->user_data, GRPC_SECURITY_OK, h->secure_endpoint,
-          h->auth_context);
-  } else {
-    if (h->secure_endpoint != NULL) {
-      grpc_endpoint_shutdown(exec_ctx, h->secure_endpoint);
-      grpc_endpoint_destroy(exec_ctx, h->secure_endpoint);
-    } else {
-      grpc_endpoint_destroy(exec_ctx, h->wrapped_endpoint);
-    }
-    h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, NULL, NULL);
-  }
-  if (h->handshaker != NULL) tsi_handshaker_destroy(h->handshaker);
-  if (h->handshake_buffer != NULL) gpr_free(h->handshake_buffer);
-  gpr_slice_buffer_destroy(&h->left_overs);
-  gpr_slice_buffer_destroy(&h->outgoing);
-  gpr_slice_buffer_destroy(&h->incoming);
-  GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake");
-  GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake");
-  gpr_free(h);
-}
-
-static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
-                            grpc_security_status status,
-                            grpc_auth_context *auth_context) {
-  grpc_security_handshake *h = user_data;
-  tsi_frame_protector *protector;
-  tsi_result result;
-  if (status != GRPC_SECURITY_OK) {
-    gpr_log(GPR_ERROR, "Error checking peer.");
-    security_handshake_done(exec_ctx, h, 0);
-    return;
-  }
-  h->auth_context = GRPC_AUTH_CONTEXT_REF(auth_context, "handshake");
-  result =
-      tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector);
-  if (result != TSI_OK) {
-    gpr_log(GPR_ERROR, "Frame protector creation failed with error %s.",
-            tsi_result_to_string(result));
-    security_handshake_done(exec_ctx, h, 0);
-    return;
-  }
-  h->secure_endpoint =
-      grpc_secure_endpoint_create(protector, h->wrapped_endpoint,
-                                  h->left_overs.slices, h->left_overs.count);
-  h->left_overs.count = 0;
-  h->left_overs.length = 0;
-  security_handshake_done(exec_ctx, h, 1);
-  return;
-}
-
-static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) {
-  tsi_peer peer;
-  tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer);
-
-  if (result != TSI_OK) {
-    gpr_log(GPR_ERROR, "Peer extraction failed with error %s",
-            tsi_result_to_string(result));
-    security_handshake_done(exec_ctx, h, 0);
-    return;
-  }
-  grpc_security_connector_check_peer(exec_ctx, h->connector, peer,
-                                     on_peer_checked, h);
-}
-
-static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
-                                         grpc_security_handshake *h) {
-  size_t offset = 0;
-  tsi_result result = TSI_OK;
-  gpr_slice to_send;
-
-  do {
-    size_t to_send_size = h->handshake_buffer_size - offset;
-    result = tsi_handshaker_get_bytes_to_send_to_peer(
-        h->handshaker, h->handshake_buffer + offset, &to_send_size);
-    offset += to_send_size;
-    if (result == TSI_INCOMPLETE_DATA) {
-      h->handshake_buffer_size *= 2;
-      h->handshake_buffer =
-          gpr_realloc(h->handshake_buffer, h->handshake_buffer_size);
-    }
-  } while (result == TSI_INCOMPLETE_DATA);
-
-  if (result != TSI_OK) {
-    gpr_log(GPR_ERROR, "Handshake failed with error %s",
-            tsi_result_to_string(result));
-    security_handshake_done(exec_ctx, h, 0);
-    return;
-  }
-
-  to_send =
-      gpr_slice_from_copied_buffer((const char *)h->handshake_buffer, offset);
-  gpr_slice_buffer_reset_and_unref(&h->outgoing);
-  gpr_slice_buffer_add(&h->outgoing, to_send);
-  /* TODO(klempner,jboeuf): This should probably use the client setup
-     deadline */
-  grpc_endpoint_write(exec_ctx, h->wrapped_endpoint, &h->outgoing,
-                      &h->on_handshake_data_sent_to_peer);
-}
-
-static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
-                                                 void *handshake,
-                                                 bool success) {
-  grpc_security_handshake *h = handshake;
-  size_t consumed_slice_size = 0;
-  tsi_result result = TSI_OK;
-  size_t i;
-  size_t num_left_overs;
-  int has_left_overs_in_current_slice = 0;
-
-  if (!success) {
-    gpr_log(GPR_ERROR, "Read failed.");
-    security_handshake_done(exec_ctx, h, 0);
-    return;
-  }
-
-  for (i = 0; i < h->incoming.count; i++) {
-    consumed_slice_size = GPR_SLICE_LENGTH(h->incoming.slices[i]);
-    result = tsi_handshaker_process_bytes_from_peer(
-        h->handshaker, GPR_SLICE_START_PTR(h->incoming.slices[i]),
-        &consumed_slice_size);
-    if (!tsi_handshaker_is_in_progress(h->handshaker)) break;
-  }
-
-  if (tsi_handshaker_is_in_progress(h->handshaker)) {
-    /* We may need more data. */
-    if (result == TSI_INCOMPLETE_DATA) {
-      grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming,
-                         &h->on_handshake_data_received_from_peer);
-      return;
-    } else {
-      send_handshake_bytes_to_peer(exec_ctx, h);
-      return;
-    }
-  }
-
-  if (result != TSI_OK) {
-    gpr_log(GPR_ERROR, "Handshake failed with error %s",
-            tsi_result_to_string(result));
-    security_handshake_done(exec_ctx, h, 0);
-    return;
-  }
-
-  /* Handshake is done and successful this point. */
-  has_left_overs_in_current_slice =
-      (consumed_slice_size < GPR_SLICE_LENGTH(h->incoming.slices[i]));
-  num_left_overs =
-      (has_left_overs_in_current_slice ? 1 : 0) + h->incoming.count - i - 1;
-  if (num_left_overs == 0) {
-    check_peer(exec_ctx, h);
-    return;
-  }
-
-  /* Put the leftovers in our buffer (ownership transfered). */
-  if (has_left_overs_in_current_slice) {
-    gpr_slice_buffer_add(
-        &h->left_overs,
-        gpr_slice_split_tail(&h->incoming.slices[i], consumed_slice_size));
-    gpr_slice_unref(
-        h->incoming.slices[i]); /* split_tail above increments refcount. */
-  }
-  gpr_slice_buffer_addn(
-      &h->left_overs, &h->incoming.slices[i + 1],
-      num_left_overs - (size_t)has_left_overs_in_current_slice);
-  check_peer(exec_ctx, h);
-}
-
-/* If handshake is NULL, the handshake is done. */
-static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx,
-                                           void *handshake, bool success) {
-  grpc_security_handshake *h = handshake;
-
-  /* Make sure that write is OK. */
-  if (!success) {
-    gpr_log(GPR_ERROR, "Write failed.");
-    if (handshake != NULL) security_handshake_done(exec_ctx, h, 0);
-    return;
-  }
-
-  /* We may be done. */
-  if (tsi_handshaker_is_in_progress(h->handshaker)) {
-    /* TODO(klempner,jboeuf): This should probably use the client setup
-       deadline */
-    grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming,
-                       &h->on_handshake_data_received_from_peer);
-  } else {
-    check_peer(exec_ctx, h);
-  }
-}
-
-void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
-                                tsi_handshaker *handshaker,
-                                grpc_security_connector *connector,
-                                bool is_client_side,
-                                grpc_endpoint *nonsecure_endpoint,
-                                grpc_security_handshake_done_cb cb,
-                                void *user_data) {
-  grpc_security_connector_handshake_list *handshake_node;
-  grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake));
-  memset(h, 0, sizeof(grpc_security_handshake));
-  h->handshaker = handshaker;
-  h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake");
-  h->is_client_side = is_client_side;
-  h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
-  h->handshake_buffer = gpr_malloc(h->handshake_buffer_size);
-  h->wrapped_endpoint = nonsecure_endpoint;
-  h->user_data = user_data;
-  h->cb = cb;
-  grpc_closure_init(&h->on_handshake_data_sent_to_peer,
-                    on_handshake_data_sent_to_peer, h);
-  grpc_closure_init(&h->on_handshake_data_received_from_peer,
-                    on_handshake_data_received_from_peer, h);
-  gpr_slice_buffer_init(&h->left_overs);
-  gpr_slice_buffer_init(&h->outgoing);
-  gpr_slice_buffer_init(&h->incoming);
-  if (!is_client_side) {
-    grpc_server_security_connector *server_connector =
-        (grpc_server_security_connector *)connector;
-    handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list));
-    handshake_node->handshake = h;
-    gpr_mu_lock(&server_connector->mu);
-    handshake_node->next = server_connector->handshaking_handshakes;
-    server_connector->handshaking_handshakes = handshake_node;
-    gpr_mu_unlock(&server_connector->mu);
-  }
-  send_handshake_bytes_to_peer(exec_ctx, h);
-}
-
-void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx,
-                                      void *handshake) {
-  grpc_security_handshake *h = handshake;
-  grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint);
-}
diff --git a/src/core/security/handshake.h b/src/core/security/handshake.h
deleted file mode 100644
index db8b374..0000000
--- a/src/core/security/handshake.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_SECURITY_HANDSHAKE_H
-#define GRPC_INTERNAL_CORE_SECURITY_HANDSHAKE_H
-
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/security/security_connector.h"
-
-/* Calls the callback upon completion. Takes owership of handshaker. */
-void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
-                                tsi_handshaker *handshaker,
-                                grpc_security_connector *connector,
-                                bool is_client_side,
-                                grpc_endpoint *nonsecure_endpoint,
-                                grpc_security_handshake_done_cb cb,
-                                void *user_data);
-
-void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, void *handshake);
-
-#endif /* GRPC_INTERNAL_CORE_SECURITY_HANDSHAKE_H */
diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c
deleted file mode 100644
index 372e5bf..0000000
--- a/src/core/security/json_token.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/security/json_token.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/security/b64.h"
-#include "src/core/support/string.h"
-
-#include <openssl/bio.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-
-/* --- Constants. --- */
-
-/* 1 hour max. */
-gpr_timespec grpc_max_auth_token_lifetime() {
-  gpr_timespec out;
-  out.tv_sec = 3600;
-  out.tv_nsec = 0;
-  out.clock_type = GPR_TIMESPAN;
-  return out;
-}
-
-#define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
-#define GRPC_JWT_TYPE "JWT"
-
-/* --- Override for testing. --- */
-
-static grpc_jwt_encode_and_sign_override g_jwt_encode_and_sign_override = NULL;
-
-/* --- grpc_auth_json_key. --- */
-
-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) {
-    if (strcmp(child->key, prop_name) == 0) break;
-  }
-  if (child == NULL || child->type != GRPC_JSON_STRING) {
-    gpr_log(GPR_ERROR, "Invalid or missing %s property.", prop_name);
-    return NULL;
-  }
-  return child->value;
-}
-
-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;
-  *json_key_field = gpr_strdup(prop_value);
-  return 1;
-}
-
-int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key) {
-  return (json_key != NULL) &&
-         strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID);
-}
-
-grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json) {
-  grpc_auth_json_key result;
-  BIO *bio = NULL;
-  const char *prop_value;
-  int success = 0;
-
-  memset(&result, 0, sizeof(grpc_auth_json_key));
-  result.type = GRPC_AUTH_JSON_TYPE_INVALID;
-  if (json == NULL) {
-    gpr_log(GPR_ERROR, "Invalid json.");
-    goto end;
-  }
-
-  prop_value = json_get_string_property(json, "type");
-  if (prop_value == NULL ||
-      strcmp(prop_value, GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT)) {
-    goto end;
-  }
-  result.type = GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT;
-
-  if (!set_json_key_string_property(json, "private_key_id",
-                                    &result.private_key_id) ||
-      !set_json_key_string_property(json, "client_id", &result.client_id) ||
-      !set_json_key_string_property(json, "client_email",
-                                    &result.client_email)) {
-    goto end;
-  }
-
-  prop_value = json_get_string_property(json, "private_key");
-  if (prop_value == NULL) {
-    goto end;
-  }
-  bio = BIO_new(BIO_s_mem());
-  success = BIO_puts(bio, prop_value);
-  if ((success < 0) || ((size_t)success != strlen(prop_value))) {
-    gpr_log(GPR_ERROR, "Could not write into openssl BIO.");
-    goto end;
-  }
-  result.private_key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, "");
-  if (result.private_key == NULL) {
-    gpr_log(GPR_ERROR, "Could not deserialize private key.");
-    goto end;
-  }
-  success = 1;
-
-end:
-  if (bio != NULL) BIO_free(bio);
-  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;
-}
-
-void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) {
-  if (json_key == NULL) return;
-  json_key->type = GRPC_AUTH_JSON_TYPE_INVALID;
-  if (json_key->client_id != NULL) {
-    gpr_free(json_key->client_id);
-    json_key->client_id = NULL;
-  }
-  if (json_key->private_key_id != NULL) {
-    gpr_free(json_key->private_key_id);
-    json_key->private_key_id = NULL;
-  }
-  if (json_key->client_email != NULL) {
-    gpr_free(json_key->client_email);
-    json_key->client_email = NULL;
-  }
-  if (json_key->private_key != NULL) {
-    RSA_free(json_key->private_key);
-    json_key->private_key = NULL;
-  }
-}
-
-/* --- jwt encoding and signature. --- */
-
-static grpc_json *create_child(grpc_json *brother, grpc_json *parent,
-                               const char *key, const char *value,
-                               grpc_json_type type) {
-  grpc_json *child = grpc_json_create(type);
-  if (brother) brother->next = child;
-  if (!parent->child) parent->child = child;
-  child->parent = parent;
-  child->value = value;
-  child->key = key;
-  return child;
-}
-
-static char *encoded_jwt_header(const char *key_id, const char *algorithm) {
-  grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT);
-  grpc_json *child = NULL;
-  char *json_str = NULL;
-  char *result = NULL;
-
-  child = create_child(NULL, json, "alg", algorithm, GRPC_JSON_STRING);
-  child = create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING);
-  create_child(child, json, "kid", key_id, GRPC_JSON_STRING);
-
-  json_str = grpc_json_dump_to_string(json, 0);
-  result = grpc_base64_encode(json_str, strlen(json_str), 1, 0);
-  gpr_free(json_str);
-  grpc_json_destroy(json);
-  return result;
-}
-
-static char *encoded_jwt_claim(const grpc_auth_json_key *json_key,
-                               const char *audience,
-                               gpr_timespec token_lifetime, const char *scope) {
-  grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT);
-  grpc_json *child = NULL;
-  char *json_str = NULL;
-  char *result = NULL;
-  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];
-  if (gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime()) > 0) {
-    gpr_log(GPR_INFO, "Cropping token lifetime to maximum allowed value.");
-    expiration = gpr_time_add(now, grpc_max_auth_token_lifetime());
-  }
-  int64_ttoa(now.tv_sec, now_str);
-  int64_ttoa(expiration.tv_sec, expiration_str);
-
-  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 {
-    /* Unscoped JWTs need a sub field. */
-    child = create_child(child, json, "sub", json_key->client_email,
-                         GRPC_JSON_STRING);
-  }
-
-  child = create_child(child, json, "aud", audience, GRPC_JSON_STRING);
-  child = create_child(child, json, "iat", now_str, GRPC_JSON_NUMBER);
-  create_child(child, json, "exp", expiration_str, GRPC_JSON_NUMBER);
-
-  json_str = grpc_json_dump_to_string(json, 0);
-  result = grpc_base64_encode(json_str, strlen(json_str), 1, 0);
-  gpr_free(json_str);
-  grpc_json_destroy(json);
-  return result;
-}
-
-static char *dot_concat_and_free_strings(char *str1, char *str2) {
-  size_t str1_len = strlen(str1);
-  size_t str2_len = strlen(str2);
-  size_t result_len = str1_len + 1 /* dot */ + str2_len;
-  char *result = gpr_malloc(result_len + 1 /* NULL terminated */);
-  char *current = result;
-  memcpy(current, str1, str1_len);
-  current += str1_len;
-  *(current++) = '.';
-  memcpy(current, str2, str2_len);
-  current += str2_len;
-  GPR_ASSERT(current >= result);
-  GPR_ASSERT((uintptr_t)(current - result) == result_len);
-  *current = '\0';
-  gpr_free(str1);
-  gpr_free(str2);
-  return result;
-}
-
-const EVP_MD *openssl_digest_from_algorithm(const char *algorithm) {
-  if (strcmp(algorithm, GRPC_JWT_RSA_SHA256_ALGORITHM) == 0) {
-    return EVP_sha256();
-  } else {
-    gpr_log(GPR_ERROR, "Unknown algorithm %s.", algorithm);
-    return NULL;
-  }
-}
-
-char *compute_and_encode_signature(const grpc_auth_json_key *json_key,
-                                   const char *signature_algorithm,
-                                   const char *to_sign) {
-  const EVP_MD *md = openssl_digest_from_algorithm(signature_algorithm);
-  EVP_MD_CTX *md_ctx = NULL;
-  EVP_PKEY *key = EVP_PKEY_new();
-  size_t sig_len = 0;
-  unsigned char *sig = NULL;
-  char *result = NULL;
-  if (md == NULL) return NULL;
-  md_ctx = EVP_MD_CTX_create();
-  if (md_ctx == NULL) {
-    gpr_log(GPR_ERROR, "Could not create MD_CTX");
-    goto end;
-  }
-  EVP_PKEY_set1_RSA(key, json_key->private_key);
-  if (EVP_DigestSignInit(md_ctx, NULL, md, NULL, key) != 1) {
-    gpr_log(GPR_ERROR, "DigestInit failed.");
-    goto end;
-  }
-  if (EVP_DigestSignUpdate(md_ctx, to_sign, strlen(to_sign)) != 1) {
-    gpr_log(GPR_ERROR, "DigestUpdate failed.");
-    goto end;
-  }
-  if (EVP_DigestSignFinal(md_ctx, NULL, &sig_len) != 1) {
-    gpr_log(GPR_ERROR, "DigestFinal (get signature length) failed.");
-    goto end;
-  }
-  sig = gpr_malloc(sig_len);
-  if (EVP_DigestSignFinal(md_ctx, sig, &sig_len) != 1) {
-    gpr_log(GPR_ERROR, "DigestFinal (signature compute) failed.");
-    goto end;
-  }
-  result = grpc_base64_encode(sig, sig_len, 1, 0);
-
-end:
-  if (key != NULL) EVP_PKEY_free(key);
-  if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx);
-  if (sig != NULL) gpr_free(sig);
-  return result;
-}
-
-char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key,
-                               const char *audience,
-                               gpr_timespec token_lifetime, const char *scope) {
-  if (g_jwt_encode_and_sign_override != NULL) {
-    return g_jwt_encode_and_sign_override(json_key, audience, token_lifetime,
-                                          scope);
-  } else {
-    const char *sig_algo = GRPC_JWT_RSA_SHA256_ALGORITHM;
-    char *to_sign = dot_concat_and_free_strings(
-        encoded_jwt_header(json_key->private_key_id, sig_algo),
-        encoded_jwt_claim(json_key, audience, token_lifetime, scope));
-    char *sig = compute_and_encode_signature(json_key, sig_algo, to_sign);
-    if (sig == NULL) {
-      gpr_free(to_sign);
-      return NULL;
-    }
-    return dot_concat_and_free_strings(to_sign, sig);
-  }
-}
-
-void grpc_jwt_encode_and_sign_set_override(
-    grpc_jwt_encode_and_sign_override func) {
-  g_jwt_encode_and_sign_override = func;
-}
-
-/* --- grpc_auth_refresh_token --- */
-
-int grpc_auth_refresh_token_is_valid(
-    const grpc_auth_refresh_token *refresh_token) {
-  return (refresh_token != NULL) &&
-         strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID);
-}
-
-grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
-    const grpc_json *json) {
-  grpc_auth_refresh_token result;
-  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.");
-    goto end;
-  }
-
-  prop_value = json_get_string_property(json, "type");
-  if (prop_value == NULL ||
-      strcmp(prop_value, GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER)) {
-    goto end;
-  }
-  result.type = GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER;
-
-  if (!set_json_key_string_property(json, "client_secret",
-                                    &result.client_secret) ||
-      !set_json_key_string_property(json, "client_id", &result.client_id) ||
-      !set_json_key_string_property(json, "refresh_token",
-                                    &result.refresh_token)) {
-    goto end;
-  }
-  success = 1;
-
-end:
-  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;
-}
-
-void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token) {
-  if (refresh_token == NULL) return;
-  refresh_token->type = GRPC_AUTH_JSON_TYPE_INVALID;
-  if (refresh_token->client_id != NULL) {
-    gpr_free(refresh_token->client_id);
-    refresh_token->client_id = NULL;
-  }
-  if (refresh_token->client_secret != NULL) {
-    gpr_free(refresh_token->client_secret);
-    refresh_token->client_secret = NULL;
-  }
-  if (refresh_token->refresh_token != NULL) {
-    gpr_free(refresh_token->refresh_token);
-    refresh_token->refresh_token = NULL;
-  }
-}
diff --git a/src/core/security/json_token.h b/src/core/security/json_token.h
deleted file mode 100644
index 7e06864..0000000
--- a/src/core/security/json_token.h
+++ /dev/null
@@ -1,118 +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_SECURITY_JSON_TOKEN_H
-#define GRPC_INTERNAL_CORE_SECURITY_JSON_TOKEN_H
-
-#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 {
-  const char *type;
-  char *private_key_id;
-  char *client_id;
-  char *client_email;
-  RSA *private_key;
-} grpc_auth_json_key;
-
-/* Returns 1 if the object is valid, 0 otherwise. */
-int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key);
-
-/* Creates a json_key object from string. Returns an invalid object if a parsing
-   error has been encountered. */
-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);
-
-/* --- json token encoding and signing. --- */
-
-/* Caller is responsible for calling gpr_free on the returned value. May return
-   NULL on invalid input. The scope parameter may be NULL. */
-char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key,
-                               const char *audience,
-                               gpr_timespec token_lifetime, const char *scope);
-
-/* Override encode_and_sign function for testing. */
-typedef char *(*grpc_jwt_encode_and_sign_override)(
-    const grpc_auth_json_key *json_key, const char *audience,
-    gpr_timespec token_lifetime, const char *scope);
-
-/* Set a custom encode_and_sign override for testing. */
-void grpc_jwt_encode_and_sign_set_override(
-    grpc_jwt_encode_and_sign_override func);
-
-/* --- auth_refresh_token parsing. --- */
-
-typedef struct {
-  const char *type;
-  char *client_id;
-  char *client_secret;
-  char *refresh_token;
-} grpc_auth_refresh_token;
-
-/* Returns 1 if the object is valid, 0 otherwise. */
-int grpc_auth_refresh_token_is_valid(
-    const grpc_auth_refresh_token *refresh_token);
-
-/* Creates a refresh token object from string. Returns an invalid object if a
-   parsing error has been encountered. */
-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);
-
-#endif /* GRPC_INTERNAL_CORE_SECURITY_JSON_TOKEN_H */
diff --git a/src/core/security/jwt_verifier.c b/src/core/security/jwt_verifier.c
deleted file mode 100644
index 928c6c1..0000000
--- a/src/core/security/jwt_verifier.c
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/security/jwt_verifier.h"
-
-#include <limits.h>
-#include <string.h>
-
-#include "src/core/httpcli/httpcli.h"
-#include "src/core/security/b64.h"
-#include "src/core/tsi/ssl_types.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());
-  size_t len = strlen(x509_str);
-  GPR_ASSERT(len < INT_MAX);
-  BIO_write(bio, x509_str, (int)len);
-  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),
-                     TSI_SIZE_AS_SIZE(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(grpc_exec_ctx *exec_ctx, 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(grpc_exec_ctx *exec_ctx, 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.handshaker = &grpc_httpcli_ssl;
-  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(
-      exec_ctx, &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(grpc_exec_ctx *exec_ctx,
-                                    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.handshaker = &grpc_httpcli_ssl;
-
-  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(
-      exec_ctx, &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_exec_ctx *exec_ctx,
-                              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, (size_t)(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, (size_t)(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(
-      exec_ctx,
-      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
deleted file mode 100644
index 25613f0..0000000
--- a/src/core/security/jwt_verifier.h
+++ /dev/null
@@ -1,136 +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_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_exec_ctx *exec_ctx,
-                              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
deleted file mode 100644
index d11c43b..0000000
--- a/src/core/security/secure_endpoint.c
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/security/secure_endpoint.h"
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/sync.h>
-#include "src/core/tsi/transport_security_interface.h"
-#include "src/core/debug/trace.h"
-
-#define STAGING_BUFFER_SIZE 8192
-
-typedef struct {
-  grpc_endpoint base;
-  grpc_endpoint *wrapped_ep;
-  struct tsi_frame_protector *protector;
-  gpr_mu protector_mu;
-  /* saved upper level callbacks and user_data. */
-  grpc_closure *read_cb;
-  grpc_closure *write_cb;
-  grpc_closure on_read;
-  gpr_slice_buffer *read_buffer;
-  gpr_slice_buffer source_buffer;
-  /* saved handshaker leftover data to unprotect. */
-  gpr_slice_buffer leftover_bytes;
-  /* buffers for read and write */
-  gpr_slice read_staging_buffer;
-
-  gpr_slice write_staging_buffer;
-  gpr_slice_buffer output_buffer;
-
-  gpr_refcount ref;
-} secure_endpoint;
-
-int grpc_trace_secure_endpoint = 0;
-
-static void destroy(grpc_exec_ctx *exec_ctx, secure_endpoint *secure_ep) {
-  secure_endpoint *ep = secure_ep;
-  grpc_endpoint_destroy(exec_ctx, ep->wrapped_ep);
-  tsi_frame_protector_destroy(ep->protector);
-  gpr_slice_buffer_destroy(&ep->leftover_bytes);
-  gpr_slice_unref(ep->read_staging_buffer);
-  gpr_slice_unref(ep->write_staging_buffer);
-  gpr_slice_buffer_destroy(&ep->output_buffer);
-  gpr_slice_buffer_destroy(&ep->source_buffer);
-  gpr_mu_destroy(&ep->protector_mu);
-  gpr_free(ep);
-}
-
-/*#define GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG*/
-#ifdef GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG
-#define SECURE_ENDPOINT_UNREF(exec_ctx, ep, reason) \
-  secure_endpoint_unref((exec_ctx), (ep), (reason), __FILE__, __LINE__)
-#define SECURE_ENDPOINT_REF(ep, reason) \
-  secure_endpoint_ref((ep), (reason), __FILE__, __LINE__)
-static void secure_endpoint_unref(secure_endpoint *ep,
-                                  grpc_closure_list *closure_list,
-                                  const char *reason, const char *file,
-                                  int line) {
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP unref %p : %s %d -> %d",
-          ep, reason, ep->ref.count, ep->ref.count - 1);
-  if (gpr_unref(&ep->ref)) {
-    destroy(exec_ctx, ep);
-  }
-}
-
-static void secure_endpoint_ref(secure_endpoint *ep, const char *reason,
-                                const char *file, int line) {
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP   ref %p : %s %d -> %d",
-          ep, reason, ep->ref.count, ep->ref.count + 1);
-  gpr_ref(&ep->ref);
-}
-#else
-#define SECURE_ENDPOINT_UNREF(exec_ctx, ep, reason) \
-  secure_endpoint_unref((exec_ctx), (ep))
-#define SECURE_ENDPOINT_REF(ep, reason) secure_endpoint_ref((ep))
-static void secure_endpoint_unref(grpc_exec_ctx *exec_ctx,
-                                  secure_endpoint *ep) {
-  if (gpr_unref(&ep->ref)) {
-    destroy(exec_ctx, ep);
-  }
-}
-
-static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); }
-#endif
-
-static void flush_read_staging_buffer(secure_endpoint *ep, uint8_t **cur,
-                                      uint8_t **end) {
-  gpr_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer);
-  ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
-  *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
-  *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
-}
-
-static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep,
-                         bool success) {
-  if (grpc_trace_secure_endpoint) {
-    size_t i;
-    for (i = 0; i < ep->read_buffer->count; i++) {
-      char *data = gpr_dump_slice(ep->read_buffer->slices[i],
-                                  GPR_DUMP_HEX | GPR_DUMP_ASCII);
-      gpr_log(GPR_DEBUG, "READ %p: %s", ep, data);
-      gpr_free(data);
-    }
-  }
-  ep->read_buffer = NULL;
-  grpc_exec_ctx_enqueue(exec_ctx, ep->read_cb, success, NULL);
-  SECURE_ENDPOINT_UNREF(exec_ctx, ep, "read");
-}
-
-static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
-  unsigned i;
-  uint8_t keep_looping = 0;
-  tsi_result result = TSI_OK;
-  secure_endpoint *ep = (secure_endpoint *)user_data;
-  uint8_t *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
-  uint8_t *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
-
-  if (!success) {
-    gpr_slice_buffer_reset_and_unref(ep->read_buffer);
-    call_read_cb(exec_ctx, ep, 0);
-    return;
-  }
-
-  /* TODO(yangg) check error, maybe bail out early */
-  for (i = 0; i < ep->source_buffer.count; i++) {
-    gpr_slice encrypted = ep->source_buffer.slices[i];
-    uint8_t *message_bytes = GPR_SLICE_START_PTR(encrypted);
-    size_t message_size = GPR_SLICE_LENGTH(encrypted);
-
-    while (message_size > 0 || keep_looping) {
-      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,
-                                             &processed_message_size, cur,
-                                             &unprotected_buffer_size_written);
-      gpr_mu_unlock(&ep->protector_mu);
-      if (result != TSI_OK) {
-        gpr_log(GPR_ERROR, "Decryption error: %s",
-                tsi_result_to_string(result));
-        break;
-      }
-      message_bytes += processed_message_size;
-      message_size -= processed_message_size;
-      cur += unprotected_buffer_size_written;
-
-      if (cur == end) {
-        flush_read_staging_buffer(ep, &cur, &end);
-        /* Force to enter the loop again to extract buffered bytes in protector.
-           The bytes could be buffered because of running out of staging_buffer.
-           If this happens at the end of all slices, doing another unprotect
-           avoids leaving data in the protector. */
-        keep_looping = 1;
-      } else if (unprotected_buffer_size_written > 0) {
-        keep_looping = 1;
-      } else {
-        keep_looping = 0;
-      }
-    }
-    if (result != TSI_OK) break;
-  }
-
-  if (cur != GPR_SLICE_START_PTR(ep->read_staging_buffer)) {
-    gpr_slice_buffer_add(
-        ep->read_buffer,
-        gpr_slice_split_head(
-            &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
-     helps latency */
-  gpr_slice_buffer_reset_and_unref(&ep->source_buffer);
-
-  if (result != TSI_OK) {
-    gpr_slice_buffer_reset_and_unref(ep->read_buffer);
-    call_read_cb(exec_ctx, ep, 0);
-    return;
-  }
-
-  call_read_cb(exec_ctx, ep, 1);
-}
-
-static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
-                          gpr_slice_buffer *slices, grpc_closure *cb) {
-  secure_endpoint *ep = (secure_endpoint *)secure_ep;
-  ep->read_cb = cb;
-  ep->read_buffer = slices;
-  gpr_slice_buffer_reset_and_unref(ep->read_buffer);
-
-  SECURE_ENDPOINT_REF(ep, "read");
-  if (ep->leftover_bytes.count) {
-    gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer);
-    GPR_ASSERT(ep->leftover_bytes.count == 0);
-    on_read(exec_ctx, ep, 1);
-    return;
-  }
-
-  grpc_endpoint_read(exec_ctx, ep->wrapped_ep, &ep->source_buffer,
-                     &ep->on_read);
-}
-
-static void flush_write_staging_buffer(secure_endpoint *ep, uint8_t **cur,
-                                       uint8_t **end) {
-  gpr_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer);
-  ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
-  *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
-  *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
-}
-
-static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
-                           gpr_slice_buffer *slices, grpc_closure *cb) {
-  unsigned i;
-  tsi_result result = TSI_OK;
-  secure_endpoint *ep = (secure_endpoint *)secure_ep;
-  uint8_t *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
-  uint8_t *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
-
-  gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
-
-  if (grpc_trace_secure_endpoint) {
-    for (i = 0; i < slices->count; i++) {
-      char *data =
-          gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
-      gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data);
-      gpr_free(data);
-    }
-  }
-
-  for (i = 0; i < slices->count; i++) {
-    gpr_slice plain = slices->slices[i];
-    uint8_t *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 = (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,
-                                           &processed_message_size, cur,
-                                           &protected_buffer_size_to_send);
-      gpr_mu_unlock(&ep->protector_mu);
-      if (result != TSI_OK) {
-        gpr_log(GPR_ERROR, "Encryption error: %s",
-                tsi_result_to_string(result));
-        break;
-      }
-      message_bytes += processed_message_size;
-      message_size -= processed_message_size;
-      cur += protected_buffer_size_to_send;
-
-      if (cur == end) {
-        flush_write_staging_buffer(ep, &cur, &end);
-      }
-    }
-    if (result != TSI_OK) break;
-  }
-  if (result == TSI_OK) {
-    size_t still_pending_size;
-    do {
-      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,
-                                                 &still_pending_size);
-      gpr_mu_unlock(&ep->protector_mu);
-      if (result != TSI_OK) break;
-      cur += protected_buffer_size_to_send;
-      if (cur == end) {
-        flush_write_staging_buffer(ep, &cur, &end);
-      }
-    } while (still_pending_size > 0);
-    if (cur != GPR_SLICE_START_PTR(ep->write_staging_buffer)) {
-      gpr_slice_buffer_add(
-          &ep->output_buffer,
-          gpr_slice_split_head(
-              &ep->write_staging_buffer,
-              (size_t)(cur - GPR_SLICE_START_PTR(ep->write_staging_buffer))));
-    }
-  }
-
-  if (result != TSI_OK) {
-    /* TODO(yangg) do different things according to the error type? */
-    gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
-    grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
-    return;
-  }
-
-  grpc_endpoint_write(exec_ctx, ep->wrapped_ep, &ep->output_buffer, cb);
-}
-
-static void endpoint_shutdown(grpc_exec_ctx *exec_ctx,
-                              grpc_endpoint *secure_ep) {
-  secure_endpoint *ep = (secure_endpoint *)secure_ep;
-  grpc_endpoint_shutdown(exec_ctx, ep->wrapped_ep);
-}
-
-static void endpoint_destroy(grpc_exec_ctx *exec_ctx,
-                             grpc_endpoint *secure_ep) {
-  secure_endpoint *ep = (secure_endpoint *)secure_ep;
-  SECURE_ENDPOINT_UNREF(exec_ctx, ep, "destroy");
-}
-
-static void endpoint_add_to_pollset(grpc_exec_ctx *exec_ctx,
-                                    grpc_endpoint *secure_ep,
-                                    grpc_pollset *pollset) {
-  secure_endpoint *ep = (secure_endpoint *)secure_ep;
-  grpc_endpoint_add_to_pollset(exec_ctx, ep->wrapped_ep, pollset);
-}
-
-static void endpoint_add_to_pollset_set(grpc_exec_ctx *exec_ctx,
-                                        grpc_endpoint *secure_ep,
-                                        grpc_pollset_set *pollset_set) {
-  secure_endpoint *ep = (secure_endpoint *)secure_ep;
-  grpc_endpoint_add_to_pollset_set(exec_ctx, ep->wrapped_ep, pollset_set);
-}
-
-static char *endpoint_get_peer(grpc_endpoint *secure_ep) {
-  secure_endpoint *ep = (secure_endpoint *)secure_ep;
-  return grpc_endpoint_get_peer(ep->wrapped_ep);
-}
-
-static const grpc_endpoint_vtable vtable = {
-    endpoint_read, endpoint_write, endpoint_add_to_pollset,
-    endpoint_add_to_pollset_set, endpoint_shutdown, endpoint_destroy,
-    endpoint_get_peer};
-
-grpc_endpoint *grpc_secure_endpoint_create(
-    struct tsi_frame_protector *protector, grpc_endpoint *transport,
-    gpr_slice *leftover_slices, size_t leftover_nslices) {
-  size_t i;
-  secure_endpoint *ep = (secure_endpoint *)gpr_malloc(sizeof(secure_endpoint));
-  ep->base.vtable = &vtable;
-  ep->wrapped_ep = transport;
-  ep->protector = protector;
-  gpr_slice_buffer_init(&ep->leftover_bytes);
-  for (i = 0; i < leftover_nslices; i++) {
-    gpr_slice_buffer_add(&ep->leftover_bytes,
-                         gpr_slice_ref(leftover_slices[i]));
-  }
-  ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
-  ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
-  gpr_slice_buffer_init(&ep->output_buffer);
-  gpr_slice_buffer_init(&ep->source_buffer);
-  ep->read_buffer = NULL;
-  grpc_closure_init(&ep->on_read, on_read, ep);
-  gpr_mu_init(&ep->protector_mu);
-  gpr_ref_init(&ep->ref, 1);
-  return &ep->base;
-}
diff --git a/src/core/security/secure_endpoint.h b/src/core/security/secure_endpoint.h
deleted file mode 100644
index c563bdd..0000000
--- a/src/core/security/secure_endpoint.h
+++ /dev/null
@@ -1,49 +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_SECURITY_SECURE_ENDPOINT_H
-#define GRPC_INTERNAL_CORE_SECURITY_SECURE_ENDPOINT_H
-
-#include "src/core/iomgr/endpoint.h"
-#include <grpc/support/slice.h>
-
-struct tsi_frame_protector;
-
-extern int grpc_trace_secure_endpoint;
-
-/* Takes ownership of protector and to_wrap, and refs leftover_slices. */
-grpc_endpoint *grpc_secure_endpoint_create(
-    struct tsi_frame_protector *protector, grpc_endpoint *to_wrap,
-    gpr_slice *leftover_slices, size_t leftover_nslices);
-
-#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURE_ENDPOINT_H */
diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c
deleted file mode 100644
index 33c62a2..0000000
--- a/src/core/security/security_connector.c
+++ /dev/null
@@ -1,806 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/security/security_connector.h"
-
-#include <stdbool.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/security/credentials.h"
-#include "src/core/security/handshake.h"
-#include "src/core/security/secure_endpoint.h"
-#include "src/core/security/security_context.h"
-#include "src/core/support/env.h"
-#include "src/core/support/load_file.h"
-#include "src/core/support/string.h"
-#include "src/core/transport/chttp2/alpn.h"
-#include "src/core/tsi/fake_transport_security.h"
-#include "src/core/tsi/ssl_transport_security.h"
-
-/* -- Constants. -- */
-
-#ifndef INSTALL_PREFIX
-static const char *installed_roots_path = "/usr/share/grpc/roots.pem";
-#else
-static const char *installed_roots_path =
-    INSTALL_PREFIX "/share/grpc/roots.pem";
-#endif
-
-/* -- Overridden default roots. -- */
-
-static grpc_ssl_roots_override_callback ssl_roots_override_cb = NULL;
-
-void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb) {
-  ssl_roots_override_cb = cb;
-}
-
-/* -- Cipher suites. -- */
-
-/* Defines the cipher suites that we accept by default. All these cipher suites
-   are compliant with HTTP2. */
-#define GRPC_SSL_CIPHER_SUITES                                            \
-  "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-" \
-  "SHA384:ECDHE-RSA-AES256-GCM-SHA384"
-
-static gpr_once cipher_suites_once = GPR_ONCE_INIT;
-static const char *cipher_suites = NULL;
-
-static void init_cipher_suites(void) {
-  char *overridden = gpr_getenv("GRPC_SSL_CIPHER_SUITES");
-  cipher_suites = overridden != NULL ? overridden : GRPC_SSL_CIPHER_SUITES;
-}
-
-static const char *ssl_cipher_suites(void) {
-  gpr_once_init(&cipher_suites_once, init_cipher_suites);
-  return cipher_suites;
-}
-
-/* -- 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) {
-  size_t i;
-  if (peer == NULL) return NULL;
-  for (i = 0; i < peer->property_count; i++) {
-    const tsi_peer_property *property = &peer->properties[i];
-    if (name == NULL && property->name == NULL) {
-      return property;
-    }
-    if (name != NULL && property->name != NULL &&
-        strcmp(property->name, name) == 0) {
-      return property;
-    }
-  }
-  return NULL;
-}
-
-void grpc_server_security_connector_shutdown(
-    grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector) {
-  grpc_security_connector_handshake_list *tmp;
-  gpr_mu_lock(&connector->mu);
-  while (connector->handshaking_handshakes) {
-    tmp = connector->handshaking_handshakes;
-    grpc_security_handshake_shutdown(
-        exec_ctx, connector->handshaking_handshakes->handshake);
-    connector->handshaking_handshakes = tmp->next;
-    gpr_free(tmp);
-  }
-  gpr_mu_unlock(&connector->mu);
-}
-
-void grpc_channel_security_connector_do_handshake(
-    grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
-    grpc_endpoint *nonsecure_endpoint, grpc_security_handshake_done_cb cb,
-    void *user_data) {
-  if (sc == NULL || nonsecure_endpoint == NULL) {
-    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
-  } else {
-    sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, cb, user_data);
-  }
-}
-
-void grpc_server_security_connector_do_handshake(
-    grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
-    grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
-    grpc_security_handshake_done_cb cb, void *user_data) {
-  if (sc == NULL || nonsecure_endpoint == NULL) {
-    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
-  } else {
-    sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, cb, user_data);
-  }
-}
-
-void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
-                                        grpc_security_connector *sc,
-                                        tsi_peer peer,
-                                        grpc_security_peer_check_cb cb,
-                                        void *user_data) {
-  if (sc == NULL) {
-    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL);
-    tsi_peer_destruct(&peer);
-  } else {
-    sc->vtable->check_peer(exec_ctx, sc, peer, cb, user_data);
-  }
-}
-
-void grpc_channel_security_connector_check_call_host(
-    grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
-    const char *host, grpc_auth_context *auth_context,
-    grpc_security_call_host_check_cb cb, void *user_data) {
-  if (sc == NULL || sc->check_call_host == NULL) {
-    cb(exec_ctx, user_data, GRPC_SECURITY_ERROR);
-  } else {
-    sc->check_call_host(exec_ctx, sc, host, auth_context, cb, user_data);
-  }
-}
-
-#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, "connector_pointer_arg");
-}
-
-static void *connector_pointer_arg_copy(void *p) {
-  return GRPC_SECURITY_CONNECTOR_REF(p, "connector_pointer_arg");
-}
-
-static int connector_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); }
-
-static const grpc_arg_pointer_vtable connector_pointer_vtable = {
-    connector_pointer_arg_copy, connector_pointer_arg_destroy,
-    connector_pointer_cmp};
-
-grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) {
-  grpc_arg result;
-  result.type = GRPC_ARG_POINTER;
-  result.key = GRPC_SECURITY_CONNECTOR_ARG;
-  result.value.pointer.vtable = &connector_pointer_vtable;
-  result.value.pointer.p = sc;
-  return result;
-}
-
-grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) {
-  if (strcmp(arg->key, GRPC_SECURITY_CONNECTOR_ARG)) return NULL;
-  if (arg->type != GRPC_ARG_POINTER) {
-    gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
-            GRPC_SECURITY_CONNECTOR_ARG);
-    return NULL;
-  }
-  return arg->value.pointer.p;
-}
-
-grpc_security_connector *grpc_find_security_connector_in_args(
-    const grpc_channel_args *args) {
-  size_t i;
-  if (args == NULL) return NULL;
-  for (i = 0; i < args->num_args; i++) {
-    grpc_security_connector *sc =
-        grpc_security_connector_from_arg(&args->args[i]);
-    if (sc != NULL) return sc;
-  }
-  return NULL;
-}
-
-/* -- Fake implementation. -- */
-
-static void fake_channel_destroy(grpc_security_connector *sc) {
-  grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
-  grpc_call_credentials_unref(c->request_metadata_creds);
-  gpr_free(sc);
-}
-
-static void fake_server_destroy(grpc_security_connector *sc) {
-  grpc_server_security_connector *c = (grpc_server_security_connector *)sc;
-  gpr_mu_destroy(&c->mu);
-  gpr_free(sc);
-}
-
-static void fake_check_peer(grpc_exec_ctx *exec_ctx,
-                            grpc_security_connector *sc, tsi_peer peer,
-                            grpc_security_peer_check_cb cb, void *user_data) {
-  const char *prop_name;
-  grpc_security_status status = GRPC_SECURITY_OK;
-  grpc_auth_context *auth_context = NULL;
-  if (peer.property_count != 1) {
-    gpr_log(GPR_ERROR, "Fake peers should only have 1 property.");
-    status = GRPC_SECURITY_ERROR;
-    goto end;
-  }
-  prop_name = peer.properties[0].name;
-  if (prop_name == NULL ||
-      strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) {
-    gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.",
-            prop_name == NULL ? "<EMPTY>" : prop_name);
-    status = GRPC_SECURITY_ERROR;
-    goto end;
-  }
-  if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE,
-              peer.properties[0].value.length)) {
-    gpr_log(GPR_ERROR, "Invalid value for cert type property.");
-    status = GRPC_SECURITY_ERROR;
-    goto end;
-  }
-  auth_context = grpc_auth_context_create(NULL);
-  grpc_auth_context_add_cstring_property(
-      auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
-      GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
-
-end:
-  cb(exec_ctx, user_data, status, auth_context);
-  grpc_auth_context_unref(auth_context);
-  tsi_peer_destruct(&peer);
-}
-
-static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx,
-                                         grpc_channel_security_connector *sc,
-                                         const char *host,
-                                         grpc_auth_context *auth_context,
-                                         grpc_security_call_host_check_cb cb,
-                                         void *user_data) {
-  cb(exec_ctx, user_data, GRPC_SECURITY_OK);
-}
-
-static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx,
-                                      grpc_channel_security_connector *sc,
-                                      grpc_endpoint *nonsecure_endpoint,
-                                      grpc_security_handshake_done_cb cb,
-                                      void *user_data) {
-  grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(1), &sc->base,
-                             true, nonsecure_endpoint, cb, user_data);
-}
-
-static void fake_server_do_handshake(grpc_exec_ctx *exec_ctx,
-                                     grpc_server_security_connector *sc,
-                                     grpc_tcp_server_acceptor *acceptor,
-                                     grpc_endpoint *nonsecure_endpoint,
-                                     grpc_security_handshake_done_cb cb,
-                                     void *user_data) {
-  grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), &sc->base,
-                             false, nonsecure_endpoint, cb, user_data);
-}
-
-static grpc_security_connector_vtable fake_channel_vtable = {
-    fake_channel_destroy, fake_check_peer};
-
-static grpc_security_connector_vtable fake_server_vtable = {fake_server_destroy,
-                                                            fake_check_peer};
-
-grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
-    grpc_call_credentials *request_metadata_creds) {
-  grpc_channel_security_connector *c = gpr_malloc(sizeof(*c));
-  memset(c, 0, sizeof(*c));
-  gpr_ref_init(&c->base.refcount, 1);
-  c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
-  c->base.vtable = &fake_channel_vtable;
-  c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds);
-  c->check_call_host = fake_channel_check_call_host;
-  c->do_handshake = fake_channel_do_handshake;
-  return c;
-}
-
-grpc_server_security_connector *grpc_fake_server_security_connector_create(
-    void) {
-  grpc_server_security_connector *c =
-      gpr_malloc(sizeof(grpc_server_security_connector));
-  memset(c, 0, sizeof(*c));
-  gpr_ref_init(&c->base.refcount, 1);
-  c->base.vtable = &fake_server_vtable;
-  c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
-  c->do_handshake = fake_server_do_handshake;
-  gpr_mu_init(&c->mu);
-  return c;
-}
-
-/* --- Ssl implementation. --- */
-
-typedef struct {
-  grpc_channel_security_connector base;
-  tsi_ssl_handshaker_factory *handshaker_factory;
-  char *target_name;
-  char *overridden_target_name;
-} grpc_ssl_channel_security_connector;
-
-typedef struct {
-  grpc_server_security_connector base;
-  tsi_ssl_handshaker_factory *handshaker_factory;
-} grpc_ssl_server_security_connector;
-
-static void ssl_channel_destroy(grpc_security_connector *sc) {
-  grpc_ssl_channel_security_connector *c =
-      (grpc_ssl_channel_security_connector *)sc;
-  grpc_call_credentials_unref(c->base.request_metadata_creds);
-  if (c->handshaker_factory != NULL) {
-    tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
-  }
-  if (c->target_name != NULL) gpr_free(c->target_name);
-  if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name);
-  gpr_free(sc);
-}
-
-static void ssl_server_destroy(grpc_security_connector *sc) {
-  grpc_ssl_server_security_connector *c =
-      (grpc_ssl_server_security_connector *)sc;
-
-  if (c->handshaker_factory != NULL) {
-    tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
-  }
-  gpr_mu_destroy(&c->base.mu);
-  gpr_free(sc);
-}
-
-static grpc_security_status ssl_create_handshaker(
-    tsi_ssl_handshaker_factory *handshaker_factory, bool is_client,
-    const char *peer_name, tsi_handshaker **handshaker) {
-  tsi_result result = TSI_OK;
-  if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
-  result = tsi_ssl_handshaker_factory_create_handshaker(
-      handshaker_factory, is_client ? peer_name : NULL, handshaker);
-  if (result != TSI_OK) {
-    gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
-            tsi_result_to_string(result));
-    return GRPC_SECURITY_ERROR;
-  }
-  return GRPC_SECURITY_OK;
-}
-
-static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx,
-                                     grpc_channel_security_connector *sc,
-                                     grpc_endpoint *nonsecure_endpoint,
-                                     grpc_security_handshake_done_cb cb,
-                                     void *user_data) {
-  grpc_ssl_channel_security_connector *c =
-      (grpc_ssl_channel_security_connector *)sc;
-  tsi_handshaker *handshaker;
-  grpc_security_status status = ssl_create_handshaker(
-      c->handshaker_factory, true,
-      c->overridden_target_name != NULL ? c->overridden_target_name
-                                        : c->target_name,
-      &handshaker);
-  if (status != GRPC_SECURITY_OK) {
-    cb(exec_ctx, user_data, status, NULL, NULL);
-  } else {
-    grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
-                               nonsecure_endpoint, cb, user_data);
-  }
-}
-
-static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx,
-                                    grpc_server_security_connector *sc,
-                                    grpc_tcp_server_acceptor *acceptor,
-                                    grpc_endpoint *nonsecure_endpoint,
-                                    grpc_security_handshake_done_cb cb,
-                                    void *user_data) {
-  grpc_ssl_server_security_connector *c =
-      (grpc_ssl_server_security_connector *)sc;
-  tsi_handshaker *handshaker;
-  grpc_security_status status =
-      ssl_create_handshaker(c->handshaker_factory, false, NULL, &handshaker);
-  if (status != GRPC_SECURITY_OK) {
-    cb(exec_ctx, user_data, status, NULL, NULL);
-  } else {
-    grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, false,
-                               nonsecure_endpoint, cb, user_data);
-  }
-}
-
-static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
-  char *allocated_name = NULL;
-  int r;
-
-  if (strchr(peer_name, ':') != NULL) {
-    char *ignored_port;
-    gpr_split_host_port(peer_name, &allocated_name, &ignored_port);
-    gpr_free(ignored_port);
-    peer_name = allocated_name;
-    if (!peer_name) return 0;
-  }
-  r = tsi_ssl_peer_matches_name(peer, peer_name);
-  gpr_free(allocated_name);
-  return r;
-}
-
-grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
-  size_t i;
-  grpc_auth_context *ctx = NULL;
-  const char *peer_identity_property_name = NULL;
-
-  /* The caller has checked the certificate type property. */
-  GPR_ASSERT(peer->property_count >= 1);
-  ctx = grpc_auth_context_create(NULL);
-  grpc_auth_context_add_cstring_property(
-      ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
-      GRPC_SSL_TRANSPORT_SECURITY_TYPE);
-  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) {
-      /* If there is no subject alt name, have the CN as the identity. */
-      if (peer_identity_property_name == NULL) {
-        peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME;
-      }
-      grpc_auth_context_add_property(ctx, GRPC_X509_CN_PROPERTY_NAME,
-                                     prop->value.data, prop->value.length);
-    } else if (strcmp(prop->name,
-                      TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
-      peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME;
-      grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME,
-                                     prop->value.data, prop->value.length);
-    }
-  }
-  if (peer_identity_property_name != NULL) {
-    GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
-                   ctx, peer_identity_property_name) == 1);
-  }
-  return ctx;
-}
-
-static grpc_security_status ssl_check_peer(grpc_security_connector *sc,
-                                           const char *peer_name,
-                                           const tsi_peer *peer,
-                                           grpc_auth_context **auth_context) {
-  /* Check the ALPN. */
-  const tsi_peer_property *p =
-      tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
-  if (p == NULL) {
-    gpr_log(GPR_ERROR, "Missing selected ALPN property.");
-    return GRPC_SECURITY_ERROR;
-  }
-  if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) {
-    gpr_log(GPR_ERROR, "Invalid ALPN value.");
-    return GRPC_SECURITY_ERROR;
-  }
-
-  /* Check the peer name if specified. */
-  if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) {
-    gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
-    return GRPC_SECURITY_ERROR;
-  }
-  *auth_context = tsi_ssl_peer_to_auth_context(peer);
-  return GRPC_SECURITY_OK;
-}
-
-static void ssl_channel_check_peer(grpc_exec_ctx *exec_ctx,
-                                   grpc_security_connector *sc, tsi_peer peer,
-                                   grpc_security_peer_check_cb cb,
-                                   void *user_data) {
-  grpc_ssl_channel_security_connector *c =
-      (grpc_ssl_channel_security_connector *)sc;
-  grpc_security_status status;
-  grpc_auth_context *auth_context = NULL;
-  status = ssl_check_peer(sc, c->overridden_target_name != NULL
-                                  ? c->overridden_target_name
-                                  : c->target_name,
-                          &peer, &auth_context);
-  cb(exec_ctx, user_data, status, auth_context);
-  grpc_auth_context_unref(auth_context);
-  tsi_peer_destruct(&peer);
-}
-
-static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx,
-                                  grpc_security_connector *sc, tsi_peer peer,
-                                  grpc_security_peer_check_cb cb,
-                                  void *user_data) {
-  grpc_auth_context *auth_context = NULL;
-  grpc_security_status status = ssl_check_peer(sc, NULL, &peer, &auth_context);
-  tsi_peer_destruct(&peer);
-  cb(exec_ctx, user_data, status, auth_context);
-  grpc_auth_context_unref(auth_context);
-}
-
-static void add_shalow_auth_property_to_peer(tsi_peer *peer,
-                                             const grpc_auth_property *prop,
-                                             const char *tsi_prop_name) {
-  tsi_peer_property *tsi_prop = &peer->properties[peer->property_count++];
-  tsi_prop->name = (char *)tsi_prop_name;
-  tsi_prop->value.data = prop->value;
-  tsi_prop->value.length = prop->value_length;
-}
-
-tsi_peer tsi_shallow_peer_from_ssl_auth_context(
-    const grpc_auth_context *auth_context) {
-  size_t max_num_props = 0;
-  grpc_auth_property_iterator it;
-  const grpc_auth_property *prop;
-  tsi_peer peer;
-  memset(&peer, 0, sizeof(peer));
-
-  it = grpc_auth_context_property_iterator(auth_context);
-  while (grpc_auth_property_iterator_next(&it) != NULL) max_num_props++;
-
-  if (max_num_props > 0) {
-    peer.properties = gpr_malloc(max_num_props * sizeof(tsi_peer_property));
-    it = grpc_auth_context_property_iterator(auth_context);
-    while ((prop = grpc_auth_property_iterator_next(&it)) != NULL) {
-      if (strcmp(prop->name, GRPC_X509_SAN_PROPERTY_NAME) == 0) {
-        add_shalow_auth_property_to_peer(
-            &peer, prop, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY);
-      } else if (strcmp(prop->name, GRPC_X509_CN_PROPERTY_NAME) == 0) {
-        add_shalow_auth_property_to_peer(
-            &peer, prop, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY);
-      }
-    }
-  }
-  return peer;
-}
-
-void tsi_shallow_peer_destruct(tsi_peer *peer) {
-  if (peer->properties != NULL) gpr_free(peer->properties);
-}
-
-static void ssl_channel_check_call_host(grpc_exec_ctx *exec_ctx,
-                                        grpc_channel_security_connector *sc,
-                                        const char *host,
-                                        grpc_auth_context *auth_context,
-                                        grpc_security_call_host_check_cb cb,
-                                        void *user_data) {
-  grpc_ssl_channel_security_connector *c =
-      (grpc_ssl_channel_security_connector *)sc;
-  grpc_security_status status = GRPC_SECURITY_ERROR;
-  tsi_peer peer = tsi_shallow_peer_from_ssl_auth_context(auth_context);
-  if (ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK;
-
-  /* If the target name was overridden, then the original target_name was
-     'checked' transitively during the previous peer check at the end of the
-     handshake. */
-  if (c->overridden_target_name != NULL && strcmp(host, c->target_name) == 0) {
-    status = GRPC_SECURITY_OK;
-  }
-  cb(exec_ctx, user_data, status);
-  tsi_shallow_peer_destruct(&peer);
-}
-
-static grpc_security_connector_vtable ssl_channel_vtable = {
-    ssl_channel_destroy, ssl_channel_check_peer};
-
-static grpc_security_connector_vtable ssl_server_vtable = {
-    ssl_server_destroy, ssl_server_check_peer};
-
-static gpr_slice compute_default_pem_root_certs_once(void) {
-  gpr_slice result = gpr_empty_slice();
-
-  /* First try to load the roots from the environment. */
-  char *default_root_certs_path =
-      gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
-  if (default_root_certs_path != NULL) {
-    result = gpr_load_file(default_root_certs_path, 0, NULL);
-    gpr_free(default_root_certs_path);
-  }
-
-  /* Try overridden roots if needed. */
-  grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL;
-  if (GPR_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != NULL) {
-    char *pem_root_certs = NULL;
-    ovrd_res = ssl_roots_override_cb(&pem_root_certs);
-    if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) {
-      GPR_ASSERT(pem_root_certs != NULL);
-      result = gpr_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free);
-    }
-  }
-
-  /* Fall back to installed certs if needed. */
-  if (GPR_SLICE_IS_EMPTY(result) &&
-      ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
-    result = gpr_load_file(installed_roots_path, 0, NULL);
-  }
-  return result;
-}
-
-static gpr_slice default_pem_root_certs;
-
-static void init_default_pem_root_certs(void) {
-  default_pem_root_certs = compute_default_pem_root_certs_once();
-}
-
-gpr_slice grpc_get_default_ssl_roots_for_testing(void) {
-  return compute_default_pem_root_certs_once();
-}
-
-size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
-  /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in
-     loading all the roots once for the lifetime of the process. */
-  static gpr_once once = GPR_ONCE_INIT;
-  gpr_once_init(&once, init_default_pem_root_certs);
-  *pem_root_certs = GPR_SLICE_START_PTR(default_pem_root_certs);
-  return GPR_SLICE_LENGTH(default_pem_root_certs);
-}
-
-grpc_security_status grpc_ssl_channel_security_connector_create(
-    grpc_call_credentials *request_metadata_creds,
-    const grpc_ssl_config *config, const char *target_name,
-    const char *overridden_target_name, grpc_channel_security_connector **sc) {
-  size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
-  const unsigned char **alpn_protocol_strings =
-      gpr_malloc(sizeof(const char *) * num_alpn_protocols);
-  unsigned char *alpn_protocol_string_lengths =
-      gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
-  tsi_result result = TSI_OK;
-  grpc_ssl_channel_security_connector *c;
-  size_t i;
-  const unsigned char *pem_root_certs;
-  size_t pem_root_certs_size;
-  char *port;
-
-  for (i = 0; i < num_alpn_protocols; i++) {
-    alpn_protocol_strings[i] =
-        (const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
-    alpn_protocol_string_lengths[i] =
-        (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i));
-  }
-
-  if (config == NULL || target_name == NULL) {
-    gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name.");
-    goto error;
-  }
-  if (config->pem_root_certs == NULL) {
-    pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
-    if (pem_root_certs == NULL || pem_root_certs_size == 0) {
-      gpr_log(GPR_ERROR, "Could not get default pem root certs.");
-      goto error;
-    }
-  } else {
-    pem_root_certs = config->pem_root_certs;
-    pem_root_certs_size = config->pem_root_certs_size;
-  }
-
-  c = gpr_malloc(sizeof(grpc_ssl_channel_security_connector));
-  memset(c, 0, sizeof(grpc_ssl_channel_security_connector));
-
-  gpr_ref_init(&c->base.base.refcount, 1);
-  c->base.base.vtable = &ssl_channel_vtable;
-  c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
-  c->base.request_metadata_creds =
-      grpc_call_credentials_ref(request_metadata_creds);
-  c->base.check_call_host = ssl_channel_check_call_host;
-  c->base.do_handshake = ssl_channel_do_handshake;
-  gpr_split_host_port(target_name, &c->target_name, &port);
-  gpr_free(port);
-  if (overridden_target_name != NULL) {
-    c->overridden_target_name = gpr_strdup(overridden_target_name);
-  }
-  result = tsi_create_ssl_client_handshaker_factory(
-      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, (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));
-    ssl_channel_destroy(&c->base.base);
-    *sc = NULL;
-    goto error;
-  }
-  *sc = &c->base;
-  gpr_free((void *)alpn_protocol_strings);
-  gpr_free(alpn_protocol_string_lengths);
-  return GRPC_SECURITY_OK;
-
-error:
-  gpr_free((void *)alpn_protocol_strings);
-  gpr_free(alpn_protocol_string_lengths);
-  return GRPC_SECURITY_ERROR;
-}
-
-grpc_security_status grpc_ssl_server_security_connector_create(
-    const grpc_ssl_server_config *config, grpc_server_security_connector **sc) {
-  size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
-  const unsigned char **alpn_protocol_strings =
-      gpr_malloc(sizeof(const char *) * num_alpn_protocols);
-  unsigned char *alpn_protocol_string_lengths =
-      gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
-  tsi_result result = TSI_OK;
-  grpc_ssl_server_security_connector *c;
-  size_t i;
-
-  for (i = 0; i < num_alpn_protocols; i++) {
-    alpn_protocol_strings[i] =
-        (const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
-    alpn_protocol_string_lengths[i] =
-        (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i));
-  }
-
-  if (config == NULL || config->num_key_cert_pairs == 0) {
-    gpr_log(GPR_ERROR, "An SSL server needs a key and a cert.");
-    goto error;
-  }
-  c = gpr_malloc(sizeof(grpc_ssl_server_security_connector));
-  memset(c, 0, sizeof(grpc_ssl_server_security_connector));
-
-  gpr_ref_init(&c->base.base.refcount, 1);
-  c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
-  c->base.base.vtable = &ssl_server_vtable;
-  result = tsi_create_ssl_server_handshaker_factory(
-      (const unsigned char **)config->pem_private_keys,
-      config->pem_private_keys_sizes,
-      (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,
-      config->force_client_auth, ssl_cipher_suites(), 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));
-    ssl_server_destroy(&c->base.base);
-    *sc = NULL;
-    goto error;
-  }
-  gpr_mu_init(&c->base.mu);
-  c->base.do_handshake = ssl_server_do_handshake;
-  *sc = &c->base;
-  gpr_free((void *)alpn_protocol_strings);
-  gpr_free(alpn_protocol_string_lengths);
-  return GRPC_SECURITY_OK;
-
-error:
-  gpr_free((void *)alpn_protocol_strings);
-  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
deleted file mode 100644
index 1e35d3f..0000000
--- a/src/core/security/security_connector.h
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H
-#define GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H
-
-#include <grpc/grpc_security.h>
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/iomgr/tcp_server.h"
-#include "src/core/tsi/transport_security_interface.h"
-
-/* --- status enum. --- */
-
-typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_ERROR } grpc_security_status;
-
-/* --- URL schemes. --- */
-
-#define GRPC_SSL_URL_SCHEME "https"
-#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security"
-
-/* --- security_connector object. ---
-
-    A security connector object represents away to configure the underlying
-    transport security mechanism and check the resulting trusted peer.  */
-
-typedef struct grpc_security_connector grpc_security_connector;
-
-#define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector"
-
-typedef void (*grpc_security_peer_check_cb)(grpc_exec_ctx *exec_ctx,
-                                            void *user_data,
-                                            grpc_security_status status,
-                                            grpc_auth_context *auth_context);
-
-/* Ownership of the secure_endpoint is transfered. */
-typedef void (*grpc_security_handshake_done_cb)(
-    grpc_exec_ctx *exec_ctx, void *user_data, grpc_security_status status,
-    grpc_endpoint *secure_endpoint, grpc_auth_context *auth_context);
-
-typedef struct {
-  void (*destroy)(grpc_security_connector *sc);
-  void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc,
-                     tsi_peer peer, grpc_security_peer_check_cb cb,
-                     void *user_data);
-} grpc_security_connector_vtable;
-
-typedef struct grpc_security_connector_handshake_list {
-  void *handshake;
-  struct grpc_security_connector_handshake_list *next;
-} grpc_security_connector_handshake_list;
-
-struct grpc_security_connector {
-  const grpc_security_connector_vtable *vtable;
-  gpr_refcount refcount;
-  const char *url_scheme;
-};
-
-/* 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 *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
-
-/* Check the peer. Callee takes ownership of the peer object.
-   The callback will include the resulting auth_context. */
-void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
-                                        grpc_security_connector *sc,
-                                        tsi_peer peer,
-                                        grpc_security_peer_check_cb cb,
-                                        void *user_data);
-
-/* Util to encapsulate the connector in a channel arg. */
-grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc);
-
-/* Util to get the connector from a channel arg. */
-grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg);
-
-/* Util to find the connector from channel args. */
-grpc_security_connector *grpc_find_security_connector_in_args(
-    const grpc_channel_args *args);
-
-/* --- channel_security_connector object. ---
-
-    A channel security connector object represents away to configure the
-    underlying transport security mechanism on the client side.  */
-
-typedef struct grpc_channel_security_connector grpc_channel_security_connector;
-
-typedef void (*grpc_security_call_host_check_cb)(grpc_exec_ctx *exec_ctx,
-                                                 void *user_data,
-                                                 grpc_security_status status);
-
-struct grpc_channel_security_connector {
-  grpc_security_connector base;
-  grpc_call_credentials *request_metadata_creds;
-  void (*check_call_host)(grpc_exec_ctx *exec_ctx,
-                          grpc_channel_security_connector *sc, const char *host,
-                          grpc_auth_context *auth_context,
-                          grpc_security_call_host_check_cb cb, void *user_data);
-  void (*do_handshake)(grpc_exec_ctx *exec_ctx,
-                       grpc_channel_security_connector *sc,
-                       grpc_endpoint *nonsecure_endpoint,
-                       grpc_security_handshake_done_cb cb, void *user_data);
-};
-
-/* Checks that the host that will be set for a call is acceptable. */
-void grpc_channel_security_connector_check_call_host(
-    grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
-    const char *host, grpc_auth_context *auth_context,
-    grpc_security_call_host_check_cb cb, void *user_data);
-
-/* Handshake. */
-void grpc_channel_security_connector_do_handshake(
-    grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector,
-    grpc_endpoint *nonsecure_endpoint, grpc_security_handshake_done_cb cb,
-    void *user_data);
-
-/* --- server_security_connector object. ---
-
-    A server security connector object represents away to configure the
-    underlying transport security mechanism on the server side.  */
-
-typedef struct grpc_server_security_connector grpc_server_security_connector;
-
-struct grpc_server_security_connector {
-  grpc_security_connector base;
-  gpr_mu mu;
-  grpc_security_connector_handshake_list *handshaking_handshakes;
-  const grpc_channel_args *channel_args;
-  void (*do_handshake)(grpc_exec_ctx *exec_ctx,
-                       grpc_server_security_connector *sc,
-                       grpc_tcp_server_acceptor *acceptor,
-                       grpc_endpoint *nonsecure_endpoint,
-                       grpc_security_handshake_done_cb cb, void *user_data);
-};
-
-void grpc_server_security_connector_do_handshake(
-    grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
-    grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
-    grpc_security_handshake_done_cb cb, void *user_data);
-
-void grpc_server_security_connector_shutdown(
-    grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector);
-
-/* --- Creation security connectors. --- */
-
-/* For TESTING ONLY!
-   Creates a fake connector that emulates real channel security.  */
-grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
-    grpc_call_credentials *request_metadata_creds);
-
-/* For TESTING ONLY!
-   Creates a fake connector that emulates real server security.  */
-grpc_server_security_connector *grpc_fake_server_security_connector_create(
-    void);
-
-/* Config for ssl clients. */
-typedef struct {
-  unsigned char *pem_private_key;
-  size_t pem_private_key_size;
-  unsigned char *pem_cert_chain;
-  size_t pem_cert_chain_size;
-  unsigned char *pem_root_certs;
-  size_t pem_root_certs_size;
-} grpc_ssl_config;
-
-/* Creates an SSL channel_security_connector.
-   - request_metadata_creds is the credentials object which metadata
-     will be sent with each request. This parameter can be NULL.
-   - config is the SSL config to be used for the SSL channel establishment.
-   - is_client should be 0 for a server or a non-0 value for a client.
-   - secure_peer_name is the secure peer name that should be checked in
-     grpc_channel_security_connector_check_peer. This parameter may be NULL in
-     which case the peer name will not be checked. Note that if this parameter
-     is not NULL, then, pem_root_certs should not be NULL either.
-   - sc is a pointer on the connector to be created.
-  This function returns GRPC_SECURITY_OK in case of success or a
-  specific error code otherwise.
-*/
-grpc_security_status grpc_ssl_channel_security_connector_create(
-    grpc_call_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);
-
-/* Exposed for TESTING ONLY!. */
-gpr_slice grpc_get_default_ssl_roots_for_testing(void);
-
-/* Config for ssl servers. */
-typedef struct {
-  unsigned char **pem_private_keys;
-  size_t *pem_private_keys_sizes;
-  unsigned char **pem_cert_chains;
-  size_t *pem_cert_chains_sizes;
-  size_t num_key_cert_pairs;
-  unsigned char *pem_root_certs;
-  size_t pem_root_certs_size;
-  int force_client_auth;
-} grpc_ssl_server_config;
-
-/* Creates an SSL server_security_connector.
-   - config is the SSL config to be used for the SSL channel establishment.
-   - sc is a pointer on the connector to be created.
-  This function returns GRPC_SECURITY_OK in case of success or a
-  specific error code otherwise.
-*/
-grpc_security_status grpc_ssl_server_security_connector_create(
-    const grpc_ssl_server_config *config, grpc_server_security_connector **sc);
-
-/* Util. */
-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);
-tsi_peer tsi_shallow_peer_from_ssl_auth_context(
-    const grpc_auth_context *auth_context);
-void tsi_shallow_peer_destruct(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
deleted file mode 100644
index a71b3bc..0000000
--- a/src/core/security/security_context.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <string.h>
-
-#include "src/core/security/security_context.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/call.h"
-#include "src/core/support/string.h"
-
-#include <grpc/grpc_security.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-/* --- grpc_call --- */
-
-grpc_call_error grpc_call_set_credentials(grpc_call *call,
-                                          grpc_call_credentials *creds) {
-  grpc_client_security_context *ctx = NULL;
-  GRPC_API_TRACE("grpc_call_set_credentials(call=%p, creds=%p)", 2,
-                 (call, creds));
-  if (!grpc_call_is_client(call)) {
-    gpr_log(GPR_ERROR, "Method is client-side only.");
-    return GRPC_CALL_ERROR_NOT_ON_SERVER;
-  }
-  ctx = (grpc_client_security_context *)grpc_call_context_get(
-      call, GRPC_CONTEXT_SECURITY);
-  if (ctx == NULL) {
-    ctx = grpc_client_security_context_create();
-    ctx->creds = grpc_call_credentials_ref(creds);
-    grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx,
-                          grpc_client_security_context_destroy);
-  } else {
-    grpc_call_credentials_unref(ctx->creds);
-    ctx->creds = grpc_call_credentials_ref(creds);
-  }
-  return GRPC_CALL_OK;
-}
-
-grpc_auth_context *grpc_call_auth_context(grpc_call *call) {
-  void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY);
-  GRPC_API_TRACE("grpc_call_auth_context(call=%p)", 1, (call));
-  if (sec_ctx == NULL) return NULL;
-  return grpc_call_is_client(call)
-             ? 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_API_TRACE("grpc_auth_context_release(context=%p)", 1, (context));
-  GRPC_AUTH_CONTEXT_UNREF(context, "grpc_auth_context_unref");
-}
-
-/* --- grpc_client_security_context --- */
-
-grpc_client_security_context *grpc_client_security_context_create(void) {
-  grpc_client_security_context *ctx =
-      gpr_malloc(sizeof(grpc_client_security_context));
-  memset(ctx, 0, sizeof(grpc_client_security_context));
-  return ctx;
-}
-
-void grpc_client_security_context_destroy(void *ctx) {
-  grpc_client_security_context *c = (grpc_client_security_context *)ctx;
-  grpc_call_credentials_unref(c->creds);
-  GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context");
-  gpr_free(ctx);
-}
-
-/* --- grpc_server_security_context --- */
-
-grpc_server_security_context *grpc_server_security_context_create(void) {
-  grpc_server_security_context *ctx =
-      gpr_malloc(sizeof(grpc_server_security_context));
-  memset(ctx, 0, sizeof(grpc_server_security_context));
-  return ctx;
-}
-
-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, "server_security_context");
-  gpr_free(ctx);
-}
-
-/* --- grpc_auth_context --- */
-
-static grpc_auth_property_iterator empty_iterator = {NULL, 0, NULL};
-
-grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained) {
-  grpc_auth_context *ctx = gpr_malloc(sizeof(grpc_auth_context));
-  memset(ctx, 0, sizeof(grpc_auth_context));
-  gpr_ref_init(&ctx->refcount, 1);
-  if (chained != NULL) {
-    ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained");
-    ctx->peer_identity_property_name =
-        ctx->chained->peer_identity_property_name;
-  }
-  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, "chained");
-    if (ctx->properties.array != NULL) {
-      for (i = 0; i < ctx->properties.count; i++) {
-        grpc_auth_property_reset(&ctx->properties.array[i]);
-      }
-      gpr_free(ctx->properties.array);
-    }
-    gpr_free(ctx);
-  }
-}
-
-const char *grpc_auth_context_peer_identity_property_name(
-    const grpc_auth_context *ctx) {
-  GRPC_API_TRACE("grpc_auth_context_peer_identity_property_name(ctx=%p)", 1,
-                 (ctx));
-  return ctx->peer_identity_property_name;
-}
-
-int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx,
-                                                      const char *name) {
-  grpc_auth_property_iterator it =
-      grpc_auth_context_find_properties_by_name(ctx, name);
-  const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it);
-  GRPC_API_TRACE(
-      "grpc_auth_context_set_peer_identity_property_name(ctx=%p, name=%s)", 2,
-      (ctx, name));
-  if (prop == NULL) {
-    gpr_log(GPR_ERROR, "Property name %s not found in auth context.",
-            name != NULL ? name : "NULL");
-    return 0;
-  }
-  ctx->peer_identity_property_name = prop->name;
-  return 1;
-}
-
-int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx) {
-  GRPC_API_TRACE("grpc_auth_context_peer_is_authenticated(ctx=%p)", 1, (ctx));
-  return ctx->peer_identity_property_name == NULL ? 0 : 1;
-}
-
-grpc_auth_property_iterator grpc_auth_context_property_iterator(
-    const grpc_auth_context *ctx) {
-  grpc_auth_property_iterator it = empty_iterator;
-  GRPC_API_TRACE("grpc_auth_context_property_iterator(ctx=%p)", 1, (ctx));
-  if (ctx == NULL) return it;
-  it.ctx = ctx;
-  return it;
-}
-
-const grpc_auth_property *grpc_auth_property_iterator_next(
-    grpc_auth_property_iterator *it) {
-  GRPC_API_TRACE("grpc_auth_property_iterator_next(it=%p)", 1, (it));
-  if (it == NULL || it->ctx == NULL) return NULL;
-  while (it->index == it->ctx->properties.count) {
-    if (it->ctx->chained == NULL) return NULL;
-    it->ctx = it->ctx->chained;
-    it->index = 0;
-  }
-  if (it->name == NULL) {
-    return &it->ctx->properties.array[it->index++];
-  } else {
-    while (it->index < it->ctx->properties.count) {
-      const grpc_auth_property *prop = &it->ctx->properties.array[it->index++];
-      GPR_ASSERT(prop->name != NULL);
-      if (strcmp(it->name, prop->name) == 0) {
-        return prop;
-      }
-    }
-    /* We could not find the name, try another round. */
-    return grpc_auth_property_iterator_next(it);
-  }
-}
-
-grpc_auth_property_iterator grpc_auth_context_find_properties_by_name(
-    const grpc_auth_context *ctx, const char *name) {
-  grpc_auth_property_iterator it = empty_iterator;
-  GRPC_API_TRACE("grpc_auth_context_find_properties_by_name(ctx=%p, name=%s)",
-                 2, (ctx, name));
-  if (ctx == NULL || name == NULL) return empty_iterator;
-  it.ctx = ctx;
-  it.name = name;
-  return it;
-}
-
-grpc_auth_property_iterator grpc_auth_context_peer_identity(
-    const grpc_auth_context *ctx) {
-  GRPC_API_TRACE("grpc_auth_context_peer_identity(ctx=%p)", 1, (ctx));
-  if (ctx == NULL) return empty_iterator;
-  return grpc_auth_context_find_properties_by_name(
-      ctx, ctx->peer_identity_property_name);
-}
-
-static void ensure_auth_context_capacity(grpc_auth_context *ctx) {
-  if (ctx->properties.count == ctx->properties.capacity) {
-    ctx->properties.capacity =
-        GPR_MAX(ctx->properties.capacity + 8, ctx->properties.capacity * 2);
-    ctx->properties.array =
-        gpr_realloc(ctx->properties.array,
-                    ctx->properties.capacity * sizeof(grpc_auth_property));
-  }
-}
-
-void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name,
-                                    const char *value, size_t value_length) {
-  grpc_auth_property *prop;
-  GRPC_API_TRACE(
-      "grpc_auth_context_add_property(ctx=%p, name=%s, value=%*.*s, "
-      "value_length=%lu)",
-      6, (ctx, name, (int)value_length, (int)value_length, value,
-          (unsigned long)value_length));
-  ensure_auth_context_capacity(ctx);
-  prop = &ctx->properties.array[ctx->properties.count++];
-  prop->name = gpr_strdup(name);
-  prop->value = gpr_malloc(value_length + 1);
-  memcpy(prop->value, value, value_length);
-  prop->value[value_length] = '\0';
-  prop->value_length = value_length;
-}
-
-void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx,
-                                            const char *name,
-                                            const char *value) {
-  grpc_auth_property *prop;
-  GRPC_API_TRACE(
-      "grpc_auth_context_add_cstring_property(ctx=%p, name=%s, value=%s)", 3,
-      (ctx, name, value));
-  ensure_auth_context_capacity(ctx);
-  prop = &ctx->properties.array[ctx->properties.count++];
-  prop->name = gpr_strdup(name);
-  prop->value = gpr_strdup(value);
-  prop->value_length = strlen(value);
-}
-
-void grpc_auth_property_reset(grpc_auth_property *property) {
-  gpr_free(property->name);
-  gpr_free(property->value);
-  memset(property, 0, sizeof(grpc_auth_property));
-}
-
-static void auth_context_pointer_arg_destroy(void *p) {
-  GRPC_AUTH_CONTEXT_UNREF(p, "auth_context_pointer_arg");
-}
-
-static void *auth_context_pointer_arg_copy(void *p) {
-  return GRPC_AUTH_CONTEXT_REF(p, "auth_context_pointer_arg");
-}
-
-static int auth_context_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); }
-
-static const grpc_arg_pointer_vtable auth_context_pointer_vtable = {
-    auth_context_pointer_arg_copy, auth_context_pointer_arg_destroy,
-    auth_context_pointer_cmp};
-
-grpc_arg grpc_auth_context_to_arg(grpc_auth_context *p) {
-  grpc_arg arg;
-  memset(&arg, 0, sizeof(grpc_arg));
-  arg.type = GRPC_ARG_POINTER;
-  arg.key = GRPC_AUTH_CONTEXT_ARG;
-  arg.value.pointer.p = p;
-  arg.value.pointer.vtable = &auth_context_pointer_vtable;
-  return arg;
-}
-
-grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg) {
-  if (strcmp(arg->key, GRPC_AUTH_CONTEXT_ARG) != 0) return NULL;
-  if (arg->type != GRPC_ARG_POINTER) {
-    gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
-            GRPC_AUTH_CONTEXT_ARG);
-    return NULL;
-  }
-  return arg->value.pointer.p;
-}
-
-grpc_auth_context *grpc_find_auth_context_in_args(
-    const grpc_channel_args *args) {
-  size_t i;
-  if (args == NULL) return NULL;
-  for (i = 0; i < args->num_args; i++) {
-    grpc_auth_context *p = grpc_auth_context_from_arg(&args->args[i]);
-    if (p != NULL) return p;
-  }
-  return NULL;
-}
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
deleted file mode 100644
index 794258e..0000000
--- a/src/core/security/security_context.h
+++ /dev/null
@@ -1,114 +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_SECURITY_SECURITY_CONTEXT_H
-#define GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H
-
-#include "src/core/iomgr/pollset.h"
-#include "src/core/security/credentials.h"
-
-/* --- grpc_auth_context ---
-
-   High level authentication context object. Can optionally be chained. */
-
-/* Property names are always NULL terminated. */
-
-typedef struct {
-  grpc_auth_property *array;
-  size_t count;
-  size_t capacity;
-} grpc_auth_property_array;
-
-struct grpc_auth_context {
-  struct grpc_auth_context *chained;
-  grpc_auth_property_array properties;
-  gpr_refcount refcount;
-  const char *peer_identity_property_name;
-  grpc_pollset *pollset;
-};
-
-/* Creation. */
-grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained);
-
-/* Refcounting. */
-#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
-
-void grpc_auth_property_reset(grpc_auth_property *property);
-
-/* --- grpc_client_security_context ---
-
-   Internal client-side security context. */
-
-typedef struct {
-  grpc_call_credentials *creds;
-  grpc_auth_context *auth_context;
-} grpc_client_security_context;
-
-grpc_client_security_context *grpc_client_security_context_create(void);
-void grpc_client_security_context_destroy(void *ctx);
-
-/* --- grpc_server_security_context ---
-
-   Internal server-side security context. */
-
-typedef struct {
-  grpc_auth_context *auth_context;
-} grpc_server_security_context;
-
-grpc_server_security_context *grpc_server_security_context_create(void);
-void grpc_server_security_context_destroy(void *ctx);
-
-/* --- Channel args for auth context --- */
-#define GRPC_AUTH_CONTEXT_ARG "grpc.auth_context"
-
-grpc_arg grpc_auth_context_to_arg(grpc_auth_context *c);
-grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg);
-grpc_auth_context *grpc_find_auth_context_in_args(
-    const grpc_channel_args *args);
-
-#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
deleted file mode 100644
index 3d8e5e8..0000000
--- a/src/core/security/server_auth_filter.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <string.h>
-
-#include "src/core/security/auth_filters.h"
-#include "src/core/security/credentials.h"
-#include "src/core/security/security_context.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-typedef struct call_data {
-  grpc_metadata_batch *recv_initial_metadata;
-  /* Closure to call when finished with the auth_on_recv hook. */
-  grpc_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_closure auth_on_recv;
-  grpc_transport_stream_op transport_op;
-  grpc_metadata_array md;
-  const grpc_metadata *consumed_md;
-  size_t num_consumed_md;
-  grpc_auth_context *auth_context;
-} call_data;
-
-typedef struct channel_data {
-  grpc_auth_context *auth_context;
-  grpc_server_credentials *creds;
-} channel_data;
-
-static grpc_metadata_array metadata_batch_to_md_array(
-    const grpc_metadata_batch *batch) {
-  grpc_linked_mdelem *l;
-  grpc_metadata_array result;
-  grpc_metadata_array_init(&result);
-  for (l = batch->list.head; l != NULL; l = l->next) {
-    grpc_metadata *usr_md = NULL;
-    grpc_mdelem *md = l->md;
-    grpc_mdstr *key = md->key;
-    grpc_mdstr *value = md->value;
-    if (result.count == result.capacity) {
-      result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2);
-      result.metadata =
-          gpr_realloc(result.metadata, result.capacity * sizeof(grpc_metadata));
-    }
-    usr_md = &result.metadata[result.count++];
-    usr_md->key = grpc_mdstr_as_c_string(key);
-    usr_md->value = grpc_mdstr_as_c_string(value);
-    usr_md->value_length = GPR_SLICE_LENGTH(value->slice);
-  }
-  return result;
-}
-
-static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) {
-  grpc_call_element *elem = user_data;
-  call_data *calld = elem->call_data;
-  size_t i;
-  for (i = 0; i < calld->num_consumed_md; i++) {
-    const grpc_metadata *consumed_md = &calld->consumed_md[i];
-    /* Maybe we could do a pointer comparison but we do not have any guarantee
-       that the metadata processor used the same pointers for consumed_md in the
-       callback. */
-    if (GPR_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) ||
-        GPR_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) {
-      continue;
-    }
-    if (memcmp(GPR_SLICE_START_PTR(md->key->slice), consumed_md->key,
-               GPR_SLICE_LENGTH(md->key->slice)) == 0 &&
-        memcmp(GPR_SLICE_START_PTR(md->value->slice), consumed_md->value,
-               GPR_SLICE_LENGTH(md->value->slice)) == 0) {
-      return NULL; /* Delete. */
-    }
-  }
-  return md;
-}
-
-/* called from application code */
-static void on_md_processing_done(
-    void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md,
-    const grpc_metadata *response_md, size_t num_response_md,
-    grpc_status_code status, const char *error_details) {
-  grpc_call_element *elem = user_data;
-  call_data *calld = elem->call_data;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  /* TODO(jboeuf): Implement support for response_md. */
-  if (response_md != NULL && num_response_md > 0) {
-    gpr_log(GPR_INFO,
-            "response_md in auth metadata processing not supported for now. "
-            "Ignoring...");
-  }
-
-  if (status == GRPC_STATUS_OK) {
-    calld->consumed_md = consumed_md;
-    calld->num_consumed_md = num_consumed_md;
-    grpc_metadata_batch_filter(calld->recv_initial_metadata, remove_consumed_md,
-                               elem);
-    grpc_metadata_array_destroy(&calld->md);
-    calld->on_done_recv->cb(&exec_ctx, calld->on_done_recv->cb_arg, 1);
-  } else {
-    gpr_slice message;
-    grpc_transport_stream_op close_op;
-    memset(&close_op, 0, sizeof(close_op));
-    grpc_metadata_array_destroy(&calld->md);
-    error_details = error_details != NULL
-                        ? error_details
-                        : "Authentication metadata processing failed.";
-    message = gpr_slice_from_copied_string(error_details);
-    calld->transport_op.send_initial_metadata = NULL;
-    if (calld->transport_op.send_message != NULL) {
-      grpc_byte_stream_destroy(&exec_ctx, calld->transport_op.send_message);
-      calld->transport_op.send_message = NULL;
-    }
-    calld->transport_op.send_trailing_metadata = NULL;
-    grpc_transport_stream_op_add_close(&close_op, status, &message);
-    grpc_call_next_op(&exec_ctx, elem, &close_op);
-    calld->on_done_recv->cb(&exec_ctx, calld->on_done_recv->cb_arg, 0);
-  }
-
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-static void auth_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
-                         bool success) {
-  grpc_call_element *elem = user_data;
-  call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
-  if (success) {
-    if (chand->creds->processor.process != NULL) {
-      calld->md = metadata_batch_to_md_array(calld->recv_initial_metadata);
-      chand->creds->processor.process(
-          chand->creds->processor.state, calld->auth_context,
-          calld->md.metadata, calld->md.count, on_md_processing_done, elem);
-      return;
-    }
-  }
-  calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success);
-}
-
-static void set_recv_ops_md_callbacks(grpc_call_element *elem,
-                                      grpc_transport_stream_op *op) {
-  call_data *calld = elem->call_data;
-
-  if (op->recv_initial_metadata != NULL) {
-    /* substitute our callback for the higher callback */
-    calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready = &calld->auth_on_recv;
-    calld->transport_op = *op;
-  }
-}
-
-/* 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 auth_start_transport_op(grpc_exec_ctx *exec_ctx,
-                                    grpc_call_element *elem,
-                                    grpc_transport_stream_op *op) {
-  set_recv_ops_md_callbacks(elem, op);
-  grpc_call_next_op(exec_ctx, elem, op);
-}
-
-/* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
-  /* grab pointers to our data from the call element */
-  call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
-  grpc_server_security_context *server_ctx = NULL;
-
-  /* initialize members */
-  memset(calld, 0, sizeof(*calld));
-  grpc_closure_init(&calld->auth_on_recv, auth_on_recv, elem);
-
-  if (args->context[GRPC_CONTEXT_SECURITY].value != NULL) {
-    args->context[GRPC_CONTEXT_SECURITY].destroy(
-        args->context[GRPC_CONTEXT_SECURITY].value);
-  }
-
-  server_ctx = grpc_server_security_context_create();
-  server_ctx->auth_context = grpc_auth_context_create(chand->auth_context);
-  calld->auth_context = server_ctx->auth_context;
-
-  args->context[GRPC_CONTEXT_SECURITY].value = server_ctx;
-  args->context[GRPC_CONTEXT_SECURITY].destroy =
-      grpc_server_security_context_destroy;
-}
-
-static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                        grpc_pollset *pollset) {}
-
-/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {}
-
-/* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
-  grpc_auth_context *auth_context =
-      grpc_find_auth_context_in_args(args->channel_args);
-  grpc_server_credentials *creds =
-      grpc_find_server_credentials_in_args(args->channel_args);
-  /* grab pointers to our data from the channel element */
-  channel_data *chand = elem->channel_data;
-
-  GPR_ASSERT(!args->is_last);
-  GPR_ASSERT(auth_context != NULL);
-  GPR_ASSERT(creds != NULL);
-
-  /* initialize members */
-  chand->auth_context =
-      GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter");
-  chand->creds = grpc_server_credentials_ref(creds);
-}
-
-/* Destructor for channel data */
-static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem) {
-  /* grab pointers to our data from the channel element */
-  channel_data *chand = elem->channel_data;
-  GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter");
-  grpc_server_credentials_unref(chand->creds);
-}
-
-const grpc_channel_filter grpc_server_auth_filter = {
-    auth_start_transport_op, grpc_channel_next_op, sizeof(call_data),
-    init_call_elem, set_pollset, destroy_call_elem, sizeof(channel_data),
-    init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer,
-    "server-auth"};
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
deleted file mode 100644
index 91547eb..0000000
--- a/src/core/security/server_secure_chttp2.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/grpc.h>
-
-#include <string.h>
-
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/http_server_filter.h"
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/iomgr/resolve_address.h"
-#include "src/core/iomgr/tcp_server.h"
-#include "src/core/security/auth_filters.h"
-#include "src/core/security/credentials.h"
-#include "src/core/security/security_connector.h"
-#include "src/core/security/security_context.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/server.h"
-#include "src/core/transport/chttp2_transport.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
-
-typedef struct grpc_server_secure_state {
-  grpc_server *server;
-  grpc_tcp_server *tcp;
-  grpc_server_security_connector *sc;
-  grpc_server_credentials *creds;
-  int is_shutdown;
-  gpr_mu mu;
-  gpr_refcount refcount;
-  grpc_closure destroy_closure;
-  grpc_closure *destroy_callback;
-} grpc_server_secure_state;
-
-static void state_ref(grpc_server_secure_state *state) {
-  gpr_ref(&state->refcount);
-}
-
-static void state_unref(grpc_server_secure_state *state) {
-  if (gpr_unref(&state->refcount)) {
-    /* ensure all threads have unlocked */
-    gpr_mu_lock(&state->mu);
-    gpr_mu_unlock(&state->mu);
-    /* clean up */
-    GRPC_SECURITY_CONNECTOR_UNREF(&state->sc->base, "server");
-    grpc_server_credentials_unref(state->creds);
-    gpr_free(state);
-  }
-}
-
-static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep,
-                            grpc_transport *transport,
-                            grpc_auth_context *auth_context) {
-  static grpc_channel_filter const *extra_filters[] = {
-      &grpc_server_auth_filter, &grpc_http_server_filter};
-  grpc_server_secure_state *state = statep;
-  grpc_channel_args *args_copy;
-  grpc_arg args_to_add[2];
-  args_to_add[0] = grpc_server_credentials_to_arg(state->creds);
-  args_to_add[1] = grpc_auth_context_to_arg(auth_context);
-  args_copy = grpc_channel_args_copy_and_add(
-      grpc_server_get_channel_args(state->server), args_to_add,
-      GPR_ARRAY_SIZE(args_to_add));
-  grpc_server_setup_transport(exec_ctx, state->server, transport, extra_filters,
-                              GPR_ARRAY_SIZE(extra_filters), args_copy);
-  grpc_channel_args_destroy(args_copy);
-}
-
-static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep,
-                                     grpc_security_status status,
-                                     grpc_endpoint *secure_endpoint,
-                                     grpc_auth_context *auth_context) {
-  grpc_server_secure_state *state = statep;
-  grpc_transport *transport;
-  if (status == GRPC_SECURITY_OK) {
-    if (secure_endpoint) {
-      gpr_mu_lock(&state->mu);
-      if (!state->is_shutdown) {
-        transport = grpc_create_chttp2_transport(
-            exec_ctx, grpc_server_get_channel_args(state->server),
-            secure_endpoint, 0);
-        setup_transport(exec_ctx, state, transport, auth_context);
-        grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
-      } else {
-        /* We need to consume this here, because the server may already have
-         * gone away. */
-        grpc_endpoint_destroy(exec_ctx, secure_endpoint);
-      }
-      gpr_mu_unlock(&state->mu);
-    }
-  } else {
-    gpr_log(GPR_ERROR, "Secure transport failed with error %d", status);
-  }
-  state_unref(state);
-}
-
-static void on_accept(grpc_exec_ctx *exec_ctx, void *statep, grpc_endpoint *tcp,
-                      grpc_tcp_server_acceptor *acceptor) {
-  grpc_server_secure_state *state = statep;
-  state_ref(state);
-  grpc_server_security_connector_do_handshake(
-      exec_ctx, state->sc, acceptor, tcp, on_secure_handshake_done, state);
-}
-
-/* Server callback: start listening on our ports */
-static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
-                  grpc_pollset **pollsets, size_t pollset_count) {
-  grpc_server_secure_state *state = statep;
-  grpc_tcp_server_start(exec_ctx, state->tcp, pollsets, pollset_count,
-                        on_accept, state);
-}
-
-static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, bool success) {
-  grpc_server_secure_state *state = statep;
-  if (state->destroy_callback != NULL) {
-    state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg,
-                                success);
-  }
-  grpc_server_security_connector_shutdown(exec_ctx, state->sc);
-  state_unref(state);
-}
-
-/* Server callback: destroy the tcp listener (so we don't generate further
-   callbacks) */
-static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
-                    grpc_closure *callback) {
-  grpc_server_secure_state *state = statep;
-  grpc_tcp_server *tcp;
-  gpr_mu_lock(&state->mu);
-  state->is_shutdown = 1;
-  state->destroy_callback = callback;
-  tcp = state->tcp;
-  gpr_mu_unlock(&state->mu);
-  grpc_tcp_server_unref(exec_ctx, tcp);
-}
-
-int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
-                                      grpc_server_credentials *creds) {
-  grpc_resolved_addresses *resolved = NULL;
-  grpc_tcp_server *tcp = NULL;
-  grpc_server_secure_state *state = NULL;
-  size_t i;
-  unsigned count = 0;
-  int port_num = -1;
-  int port_temp;
-  grpc_security_status status = GRPC_SECURITY_ERROR;
-  grpc_server_security_connector *sc = NULL;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  GRPC_API_TRACE(
-      "grpc_server_add_secure_http2_port("
-      "server=%p, addr=%s, creds=%p)",
-      3, (server, addr, creds));
-
-  /* create security context */
-  if (creds == NULL) goto error;
-  status = grpc_server_credentials_create_security_connector(creds, &sc);
-  if (status != GRPC_SECURITY_OK) {
-    gpr_log(GPR_ERROR,
-            "Unable to create secure server with credentials of type %s.",
-            creds->type);
-    goto error;
-  }
-  sc->channel_args = grpc_server_get_channel_args(server);
-
-  /* resolve address */
-  resolved = grpc_blocking_resolve_address(addr, "https");
-  if (!resolved) {
-    goto error;
-  }
-  state = gpr_malloc(sizeof(*state));
-  memset(state, 0, sizeof(*state));
-  grpc_closure_init(&state->destroy_closure, destroy_done, state);
-  tcp = grpc_tcp_server_create(&state->destroy_closure);
-  if (!tcp) {
-    goto error;
-  }
-
-  state->server = server;
-  state->tcp = tcp;
-  state->sc = sc;
-  state->creds = grpc_server_credentials_ref(creds);
-  state->is_shutdown = 0;
-  gpr_mu_init(&state->mu);
-  gpr_ref_init(&state->refcount, 1);
-
-  for (i = 0; i < resolved->naddrs; i++) {
-    port_temp = grpc_tcp_server_add_port(
-        tcp, (struct sockaddr *)&resolved->addrs[i].addr,
-        resolved->addrs[i].len);
-    if (port_temp > 0) {
-      if (port_num == -1) {
-        port_num = port_temp;
-      } else {
-        GPR_ASSERT(port_num == port_temp);
-      }
-      count++;
-    }
-  }
-  if (count == 0) {
-    gpr_log(GPR_ERROR, "No address added out of total %d resolved",
-            resolved->naddrs);
-    goto error;
-  }
-  if (count != resolved->naddrs) {
-    gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
-            count, resolved->naddrs);
-    /* if it's an error, don't we want to goto error; here ? */
-  }
-  grpc_resolved_addresses_destroy(resolved);
-
-  /* Register with the server only upon success */
-  grpc_server_add_listener(&exec_ctx, server, state, start, destroy);
-
-  grpc_exec_ctx_finish(&exec_ctx);
-  return port_num;
-
-/* Error path: cleanup and return */
-error:
-  if (resolved) {
-    grpc_resolved_addresses_destroy(resolved);
-  }
-  if (tcp) {
-    grpc_tcp_server_unref(&exec_ctx, tcp);
-  } else {
-    if (sc) {
-      GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "server");
-    }
-    if (state) {
-      gpr_free(state);
-    }
-  }
-  grpc_exec_ctx_finish(&exec_ctx);
-  return 0;
-}
diff --git a/src/core/statistics/census_init.c b/src/core/statistics/census_init.c
deleted file mode 100644
index b6a962f..0000000
--- a/src/core/statistics/census_init.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/statistics/census_interface.h"
-
-#include <grpc/support/log.h>
-#include "src/core/statistics/census_rpc_stats.h"
-#include "src/core/statistics/census_tracing.h"
-
-void census_init(void) {
-  census_tracing_init();
-  census_stats_store_init();
-}
-
-void census_shutdown(void) {
-  census_stats_store_shutdown();
-  census_tracing_shutdown();
-}
diff --git a/src/core/statistics/census_interface.h b/src/core/statistics/census_interface.h
deleted file mode 100644
index c43acbd..0000000
--- a/src/core/statistics/census_interface.h
+++ /dev/null
@@ -1,76 +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_STATISTICS_CENSUS_INTERFACE_H
-#define GRPC_INTERNAL_CORE_STATISTICS_CENSUS_INTERFACE_H
-
-#include <grpc/support/port_platform.h>
-
-/* Maximum length of an individual census trace annotation. */
-#define CENSUS_MAX_ANNOTATION_LENGTH 200
-
-/* Structure of a census op id. Define as structure because 64bit integer is not
-   available on every platform for C89. */
-typedef struct census_op_id {
-  uint32_t upper;
-  uint32_t lower;
-} census_op_id;
-
-typedef struct census_rpc_stats census_rpc_stats;
-
-/* Initializes Census library. No-op if Census is already initialized. */
-void census_init(void);
-
-/* Shutdown Census Library. */
-void census_shutdown(void);
-
-/* Annotates grpc method name on a census_op_id. The method name has the format
-   of <full quantified rpc service name>/<rpc function name>. Returns 0 iff
-   op_id and method_name are all valid. op_id is valid after its creation and
-   before calling census_tracing_end_op().
-
-   TODO(hongyu): Figure out valid characters set for service name and command
-   name and document requirements here.*/
-int census_add_method_tag(census_op_id op_id, const char *method_name);
-
-/* Annotates tracing information to a specific op_id.
-   Up to CENSUS_MAX_ANNOTATION_LENGTH bytes are recorded. */
-void census_tracing_print(census_op_id op_id, const char *annotation);
-
-/* Starts tracing for an RPC. Returns a locally unique census_op_id */
-census_op_id census_tracing_start_op(void);
-
-/* Ends tracing. Calling this function will invalidate the input op_id. */
-void census_tracing_end_op(census_op_id op_id);
-
-#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_INTERFACE_H */
diff --git a/src/core/statistics/census_log.c b/src/core/statistics/census_log.c
deleted file mode 100644
index 257ba58..0000000
--- a/src/core/statistics/census_log.c
+++ /dev/null
@@ -1,603 +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.
- *
- */
-
-/* Available log space is divided up in blocks of
-   CENSUS_LOG_2_MAX_RECORD_SIZE bytes. A block can be in one of the
-   following three data structures:
-   - Free blocks (free_block_list)
-   - Blocks with unread data (dirty_block_list)
-   - Blocks currently attached to cores (core_local_blocks[])
-
-   census_log_start_write() moves a block from core_local_blocks[] to the
-   end of dirty_block_list when block:
-   - is out-of-space OR
-   - has an incomplete record (an incomplete record occurs when a thread calls
-     census_log_start_write() and is context-switched before calling
-     census_log_end_write()
-   So, blocks in dirty_block_list are ordered, from oldest to newest, by time
-   when block is detached from the core.
-
-   census_log_read_next() first iterates over dirty_block_list and then
-   core_local_blocks[]. It moves completely read blocks from dirty_block_list
-   to free_block_list. Blocks in core_local_blocks[] are not freed, even when
-   completely read.
-
-   If log is configured to discard old records and free_block_list is empty,
-   census_log_start_write() iterates over dirty_block_list to allocate a
-   new block. It moves the oldest available block (no pending read/write) to
-   core_local_blocks[].
-
-   core_local_block_struct is used to implement a map from core id to the block
-   associated with that core. This mapping is advisory. It is possible that the
-   block returned by this mapping is no longer associated with that core. This
-   mapping is updated, lazily, by census_log_start_write().
-
-   Locking in block struct:
-
-   Exclusive g_log.lock must be held before calling any functions operatong on
-   block structs except census_log_start_write() and
-   census_log_end_write().
-
-   Writes to a block are serialized via writer_lock.
-   census_log_start_write() acquires this lock and
-   census_log_end_write() releases it. On failure to acquire the lock,
-   writer allocates a new block for the current core and updates
-   core_local_block accordingly.
-
-   Simultaneous read and write access is allowed. Reader can safely read up to
-   committed bytes (bytes_committed).
-
-   reader_lock protects the block, currently being read, from getting recycled.
-   start_read() acquires reader_lock and end_read() releases the lock.
-
-   Read/write access to a block is disabled via try_disable_access(). It returns
-   with both writer_lock and reader_lock held. These locks are subsequently
-   released by enable_access() to enable access to the block.
-
-   A note on naming: Most function/struct names are prepended by cl_
-   (shorthand for census_log). Further, functions that manipulate structures
-   include the name of the structure, which will be passed as the first
-   argument. E.g. cl_block_initialize() will initialize a cl_block.
-*/
-#include "src/core/statistics/census_log.h"
-#include <string.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/atm.h>
-#include <grpc/support/cpu.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
-
-/* End of platform specific code */
-
-typedef struct census_log_block_list_struct {
-  struct census_log_block_list_struct *next;
-  struct census_log_block_list_struct *prev;
-  struct census_log_block *block;
-} cl_block_list_struct;
-
-typedef struct census_log_block {
-  /* Pointer to underlying buffer */
-  char *buffer;
-  gpr_atm writer_lock;
-  gpr_atm reader_lock;
-  /* Keeps completely written bytes. Declared atomic because accessed
-     simultaneously by reader and writer. */
-  gpr_atm bytes_committed;
-  /* Bytes already read */
-  int32_t bytes_read;
-  /* Links for list */
-  cl_block_list_struct link;
-/* We want this structure to be cacheline aligned. We assume the following
-   sizes for the various parts on 32/64bit systems:
-   type                 32b size    64b size
-   char*                   4           8
-   3x gpr_atm             12          24
-   int32_t               4           8 (assumes padding)
-   cl_block_list_struct   12          24
-   TOTAL                  32          64
-
-   Depending on the size of our cacheline and the architecture, we
-   selectively add char buffering to this structure. The size is checked
-   via assert in census_log_initialize(). */
-#if defined(GPR_ARCH_64)
-#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 64)
-#else
-#if defined(GPR_ARCH_32)
-#define CL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 32)
-#else
-#error "Unknown architecture"
-#endif
-#endif
-#if CL_BLOCK_PAD_SIZE > 0
-  char padding[CL_BLOCK_PAD_SIZE];
-#endif
-} cl_block;
-
-/* A list of cl_blocks, doubly-linked through cl_block::link. */
-typedef struct census_log_block_list {
-  int32_t count;           /* Number of items in list. */
-  cl_block_list_struct ht; /* head/tail of linked list. */
-} cl_block_list;
-
-/* Cacheline aligned block pointers to avoid false sharing. Block pointer must
-   be initialized via set_block(), before calling other functions */
-typedef struct census_log_core_local_block {
-  gpr_atm block;
-/* Ensure cachline alignment: we assume sizeof(gpr_atm) == 4 or 8 */
-#if defined(GPR_ARCH_64)
-#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 8)
-#else
-#if defined(GPR_ARCH_32)
-#define CL_CORE_LOCAL_BLOCK_PAD_SIZE (GPR_CACHELINE_SIZE - 4)
-#else
-#error "Unknown architecture"
-#endif
-#endif
-#if CL_CORE_LOCAL_BLOCK_PAD_SIZE > 0
-  char padding[CL_CORE_LOCAL_BLOCK_PAD_SIZE];
-#endif
-} cl_core_local_block;
-
-struct census_log {
-  int discard_old_records;
-  /* Number of cores (aka hardware-contexts) */
-  unsigned num_cores;
-  /* number of CENSUS_LOG_2_MAX_RECORD_SIZE blocks in log */
-  int32_t num_blocks;
-  cl_block *blocks;                       /* Block metadata. */
-  cl_core_local_block *core_local_blocks; /* Keeps core to block mappings. */
-  gpr_mu lock;
-  int initialized; /* has log been initialized? */
-  /* Keeps the state of the reader iterator. A value of 0 indicates that
-     iterator has reached the end. census_log_init_reader() resets the
-     value to num_core to restart iteration. */
-  uint32_t read_iterator_state;
-  /* Points to the block being read. If non-NULL, the block is locked for
-     reading (block_being_read_->reader_lock is held). */
-  cl_block *block_being_read;
-  /* A non-zero value indicates that log is full. */
-  gpr_atm is_full;
-  char *buffer;
-  cl_block_list free_block_list;
-  cl_block_list dirty_block_list;
-  gpr_atm out_of_space_count;
-};
-
-/* Single internal log */
-static struct census_log g_log;
-
-/* Functions that operate on an atomic memory location used as a lock */
-
-/* Returns non-zero if lock is acquired */
-static int cl_try_lock(gpr_atm *lock) { return gpr_atm_acq_cas(lock, 0, 1); }
-
-static void cl_unlock(gpr_atm *lock) { gpr_atm_rel_store(lock, 0); }
-
-/* Functions that operate on cl_core_local_block's */
-
-static void cl_core_local_block_set_block(cl_core_local_block *clb,
-                                          cl_block *block) {
-  gpr_atm_rel_store(&clb->block, (gpr_atm)block);
-}
-
-static cl_block *cl_core_local_block_get_block(cl_core_local_block *clb) {
-  return (cl_block *)gpr_atm_acq_load(&clb->block);
-}
-
-/* Functions that operate on cl_block_list_struct's */
-
-static void cl_block_list_struct_initialize(cl_block_list_struct *bls,
-                                            cl_block *block) {
-  bls->next = bls->prev = bls;
-  bls->block = block;
-}
-
-/* Functions that operate on cl_block_list's */
-
-static void cl_block_list_initialize(cl_block_list *list) {
-  list->count = 0;
-  cl_block_list_struct_initialize(&list->ht, NULL);
-}
-
-/* Returns head of *this, or NULL if empty. */
-static cl_block *cl_block_list_head(cl_block_list *list) {
-  return list->ht.next->block;
-}
-
-/* Insert element *e after *pos. */
-static void cl_block_list_insert(cl_block_list *list, cl_block_list_struct *pos,
-                                 cl_block_list_struct *e) {
-  list->count++;
-  e->next = pos->next;
-  e->prev = pos;
-  e->next->prev = e;
-  e->prev->next = e;
-}
-
-/* Insert block at the head of the list */
-static void cl_block_list_insert_at_head(cl_block_list *list, cl_block *block) {
-  cl_block_list_insert(list, &list->ht, &block->link);
-}
-
-/* Insert block at the tail of the list */
-static void cl_block_list_insert_at_tail(cl_block_list *list, cl_block *block) {
-  cl_block_list_insert(list, list->ht.prev, &block->link);
-}
-
-/* Removes block *b. Requires *b be in the list. */
-static void cl_block_list_remove(cl_block_list *list, cl_block *b) {
-  list->count--;
-  b->link.next->prev = b->link.prev;
-  b->link.prev->next = b->link.next;
-}
-
-/* Functions that operate on cl_block's */
-
-static void cl_block_initialize(cl_block *block, char *buffer) {
-  block->buffer = buffer;
-  gpr_atm_rel_store(&block->writer_lock, 0);
-  gpr_atm_rel_store(&block->reader_lock, 0);
-  gpr_atm_rel_store(&block->bytes_committed, 0);
-  block->bytes_read = 0;
-  cl_block_list_struct_initialize(&block->link, block);
-}
-
-/* Guards against exposing partially written buffer to the reader. */
-static void cl_block_set_bytes_committed(cl_block *block,
-                                         int32_t bytes_committed) {
-  gpr_atm_rel_store(&block->bytes_committed, bytes_committed);
-}
-
-static int32_t cl_block_get_bytes_committed(cl_block *block) {
-  return gpr_atm_acq_load(&block->bytes_committed);
-}
-
-/* Tries to disable future read/write access to this block. Succeeds if:
-   - no in-progress write AND
-   - no in-progress read AND
-   - 'discard_data' set to true OR no unread data
-   On success, clears the block state and returns with writer_lock_ and
-   reader_lock_ held. These locks are released by a subsequent
-   cl_block_access_enable() call. */
-static int cl_block_try_disable_access(cl_block *block, int discard_data) {
-  if (!cl_try_lock(&block->writer_lock)) {
-    return 0;
-  }
-  if (!cl_try_lock(&block->reader_lock)) {
-    cl_unlock(&block->writer_lock);
-    return 0;
-  }
-  if (!discard_data &&
-      (block->bytes_read != cl_block_get_bytes_committed(block))) {
-    cl_unlock(&block->reader_lock);
-    cl_unlock(&block->writer_lock);
-    return 0;
-  }
-  cl_block_set_bytes_committed(block, 0);
-  block->bytes_read = 0;
-  return 1;
-}
-
-static void cl_block_enable_access(cl_block *block) {
-  cl_unlock(&block->reader_lock);
-  cl_unlock(&block->writer_lock);
-}
-
-/* Returns with writer_lock held. */
-static void *cl_block_start_write(cl_block *block, size_t size) {
-  int32_t bytes_committed;
-  if (!cl_try_lock(&block->writer_lock)) {
-    return NULL;
-  }
-  bytes_committed = cl_block_get_bytes_committed(block);
-  if (bytes_committed + size > CENSUS_LOG_MAX_RECORD_SIZE) {
-    cl_unlock(&block->writer_lock);
-    return NULL;
-  }
-  return block->buffer + bytes_committed;
-}
-
-/* Releases writer_lock and increments committed bytes by 'bytes_written'.
-  'bytes_written' must be <= 'size' specified in the corresponding
-  StartWrite() call. This function is thread-safe. */
-static void cl_block_end_write(cl_block *block, size_t bytes_written) {
-  cl_block_set_bytes_committed(
-      block, cl_block_get_bytes_committed(block) + bytes_written);
-  cl_unlock(&block->writer_lock);
-}
-
-/* Returns a pointer to the first unread byte in buffer. The number of bytes
-   available are returned in 'bytes_available'. Acquires reader lock that is
-   released by a subsequent cl_block_end_read() call. Returns NULL if:
-   - read in progress
-   - no data available */
-static void *cl_block_start_read(cl_block *block, size_t *bytes_available) {
-  void *record;
-  if (!cl_try_lock(&block->reader_lock)) {
-    return NULL;
-  }
-  /* bytes_committed may change from under us. Use bytes_available to update
-     bytes_read below. */
-  *bytes_available = cl_block_get_bytes_committed(block) - block->bytes_read;
-  if (*bytes_available == 0) {
-    cl_unlock(&block->reader_lock);
-    return NULL;
-  }
-  record = block->buffer + block->bytes_read;
-  block->bytes_read += *bytes_available;
-  return record;
-}
-
-static void cl_block_end_read(cl_block *block) {
-  cl_unlock(&block->reader_lock);
-}
-
-/* Internal functions operating on g_log */
-
-/* Allocates a new free block (or recycles an available dirty block if log is
-   configured to discard old records). Returns NULL if out-of-space. */
-static cl_block *cl_allocate_block(void) {
-  cl_block *block = cl_block_list_head(&g_log.free_block_list);
-  if (block != NULL) {
-    cl_block_list_remove(&g_log.free_block_list, block);
-    return block;
-  }
-  if (!g_log.discard_old_records) {
-    /* No free block and log is configured to keep old records. */
-    return NULL;
-  }
-  /* Recycle dirty block. Start from the oldest. */
-  for (block = cl_block_list_head(&g_log.dirty_block_list); block != NULL;
-       block = block->link.next->block) {
-    if (cl_block_try_disable_access(block, 1 /* discard data */)) {
-      cl_block_list_remove(&g_log.dirty_block_list, block);
-      return block;
-    }
-  }
-  return NULL;
-}
-
-/* Allocates a new block and updates core id => block mapping. 'old_block'
-   points to the block that the caller thinks is attached to
-   'core_id'. 'old_block' may be NULL. Returns non-zero if:
-   - allocated a new block OR
-   - 'core_id' => 'old_block' mapping changed (another thread allocated a
-     block before lock was acquired). */
-static int cl_allocate_core_local_block(int32_t core_id, cl_block *old_block) {
-  /* Now that we have the lock, check if core-local mapping has changed. */
-  cl_core_local_block *core_local_block = &g_log.core_local_blocks[core_id];
-  cl_block *block = cl_core_local_block_get_block(core_local_block);
-  if ((block != NULL) && (block != old_block)) {
-    return 1;
-  }
-  if (block != NULL) {
-    cl_core_local_block_set_block(core_local_block, NULL);
-    cl_block_list_insert_at_tail(&g_log.dirty_block_list, block);
-  }
-  block = cl_allocate_block();
-  if (block == NULL) {
-    gpr_atm_rel_store(&g_log.is_full, 1);
-    return 0;
-  }
-  cl_core_local_block_set_block(core_local_block, block);
-  cl_block_enable_access(block);
-  return 1;
-}
-
-static cl_block *cl_get_block(void *record) {
-  uintptr_t p = (uintptr_t)((char *)record - g_log.buffer);
-  uintptr_t index = p >> CENSUS_LOG_2_MAX_RECORD_SIZE;
-  return &g_log.blocks[index];
-}
-
-/* Gets the next block to read and tries to free 'prev' block (if not NULL).
-   Returns NULL if reached the end. */
-static cl_block *cl_next_block_to_read(cl_block *prev) {
-  cl_block *block = NULL;
-  if (g_log.read_iterator_state == g_log.num_cores) {
-    /* We are traversing dirty list; find the next dirty block. */
-    if (prev != NULL) {
-      /* Try to free the previous block if there is no unread data. This block
-         may have unread data if previously incomplete record completed between
-         read_next() calls. */
-      block = prev->link.next->block;
-      if (cl_block_try_disable_access(prev, 0 /* do not discard data */)) {
-        cl_block_list_remove(&g_log.dirty_block_list, prev);
-        cl_block_list_insert_at_head(&g_log.free_block_list, prev);
-        gpr_atm_rel_store(&g_log.is_full, 0);
-      }
-    } else {
-      block = cl_block_list_head(&g_log.dirty_block_list);
-    }
-    if (block != NULL) {
-      return block;
-    }
-    /* We are done with the dirty list; moving on to core-local blocks. */
-  }
-  while (g_log.read_iterator_state > 0) {
-    g_log.read_iterator_state--;
-    block = cl_core_local_block_get_block(
-        &g_log.core_local_blocks[g_log.read_iterator_state]);
-    if (block != NULL) {
-      return block;
-    }
-  }
-  return NULL;
-}
-
-/* External functions: primary stats_log interface */
-void census_log_initialize(size_t size_in_mb, int discard_old_records) {
-  int32_t ix;
-  /* Check cacheline alignment. */
-  GPR_ASSERT(sizeof(cl_block) % GPR_CACHELINE_SIZE == 0);
-  GPR_ASSERT(sizeof(cl_core_local_block) % GPR_CACHELINE_SIZE == 0);
-  GPR_ASSERT(!g_log.initialized);
-  g_log.discard_old_records = discard_old_records;
-  g_log.num_cores = gpr_cpu_num_cores();
-  /* Ensure at least as many blocks as there are cores. */
-  g_log.num_blocks = GPR_MAX(
-      g_log.num_cores, (size_in_mb << 20) >> CENSUS_LOG_2_MAX_RECORD_SIZE);
-  gpr_mu_init(&g_log.lock);
-  g_log.read_iterator_state = 0;
-  g_log.block_being_read = NULL;
-  gpr_atm_rel_store(&g_log.is_full, 0);
-  g_log.core_local_blocks = (cl_core_local_block *)gpr_malloc_aligned(
-      g_log.num_cores * sizeof(cl_core_local_block), GPR_CACHELINE_SIZE_LOG);
-  memset(g_log.core_local_blocks, 0,
-         g_log.num_cores * sizeof(cl_core_local_block));
-  g_log.blocks = (cl_block *)gpr_malloc_aligned(
-      g_log.num_blocks * sizeof(cl_block), GPR_CACHELINE_SIZE_LOG);
-  memset(g_log.blocks, 0, g_log.num_blocks * sizeof(cl_block));
-  g_log.buffer = gpr_malloc(g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE);
-  memset(g_log.buffer, 0, g_log.num_blocks * CENSUS_LOG_MAX_RECORD_SIZE);
-  cl_block_list_initialize(&g_log.free_block_list);
-  cl_block_list_initialize(&g_log.dirty_block_list);
-  for (ix = 0; ix < g_log.num_blocks; ++ix) {
-    cl_block *block = g_log.blocks + ix;
-    cl_block_initialize(block,
-                        g_log.buffer + (CENSUS_LOG_MAX_RECORD_SIZE * ix));
-    cl_block_try_disable_access(block, 1 /* discard data */);
-    cl_block_list_insert_at_tail(&g_log.free_block_list, block);
-  }
-  gpr_atm_rel_store(&g_log.out_of_space_count, 0);
-  g_log.initialized = 1;
-}
-
-void census_log_shutdown(void) {
-  GPR_ASSERT(g_log.initialized);
-  gpr_mu_destroy(&g_log.lock);
-  gpr_free_aligned(g_log.core_local_blocks);
-  g_log.core_local_blocks = NULL;
-  gpr_free_aligned(g_log.blocks);
-  g_log.blocks = NULL;
-  gpr_free(g_log.buffer);
-  g_log.buffer = NULL;
-  g_log.initialized = 0;
-}
-
-void *census_log_start_write(size_t size) {
-  /* Used to bound number of times block allocation is attempted. */
-  int32_t attempts_remaining = g_log.num_blocks;
-  /* TODO(aveitch): move this inside the do loop when current_cpu is fixed */
-  int32_t core_id = gpr_cpu_current_cpu();
-  GPR_ASSERT(g_log.initialized);
-  if (size > CENSUS_LOG_MAX_RECORD_SIZE) {
-    return NULL;
-  }
-  do {
-    int allocated;
-    void *record = NULL;
-    cl_block *block =
-        cl_core_local_block_get_block(&g_log.core_local_blocks[core_id]);
-    if (block && (record = cl_block_start_write(block, size))) {
-      return record;
-    }
-    /* Need to allocate a new block. We are here if:
-       - No block associated with the core OR
-       - Write in-progress on the block OR
-       - block is out of space */
-    if (gpr_atm_acq_load(&g_log.is_full)) {
-      gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
-      return NULL;
-    }
-    gpr_mu_lock(&g_log.lock);
-    allocated = cl_allocate_core_local_block(core_id, block);
-    gpr_mu_unlock(&g_log.lock);
-    if (!allocated) {
-      gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
-      return NULL;
-    }
-  } while (attempts_remaining--);
-  /* Give up. */
-  gpr_atm_no_barrier_fetch_add(&g_log.out_of_space_count, 1);
-  return NULL;
-}
-
-void census_log_end_write(void *record, size_t bytes_written) {
-  GPR_ASSERT(g_log.initialized);
-  cl_block_end_write(cl_get_block(record), bytes_written);
-}
-
-void census_log_init_reader(void) {
-  GPR_ASSERT(g_log.initialized);
-  gpr_mu_lock(&g_log.lock);
-  /* If a block is locked for reading unlock it. */
-  if (g_log.block_being_read != NULL) {
-    cl_block_end_read(g_log.block_being_read);
-    g_log.block_being_read = NULL;
-  }
-  g_log.read_iterator_state = g_log.num_cores;
-  gpr_mu_unlock(&g_log.lock);
-}
-
-const void *census_log_read_next(size_t *bytes_available) {
-  GPR_ASSERT(g_log.initialized);
-  gpr_mu_lock(&g_log.lock);
-  if (g_log.block_being_read != NULL) {
-    cl_block_end_read(g_log.block_being_read);
-  }
-  do {
-    g_log.block_being_read = cl_next_block_to_read(g_log.block_being_read);
-    if (g_log.block_being_read != NULL) {
-      void *record =
-          cl_block_start_read(g_log.block_being_read, bytes_available);
-      if (record != NULL) {
-        gpr_mu_unlock(&g_log.lock);
-        return record;
-      }
-    }
-  } while (g_log.block_being_read != NULL);
-  gpr_mu_unlock(&g_log.lock);
-  return NULL;
-}
-
-size_t census_log_remaining_space(void) {
-  size_t space;
-  GPR_ASSERT(g_log.initialized);
-  gpr_mu_lock(&g_log.lock);
-  if (g_log.discard_old_records) {
-    /* Remaining space is not meaningful; just return the entire log space. */
-    space = g_log.num_blocks << CENSUS_LOG_2_MAX_RECORD_SIZE;
-  } else {
-    space = g_log.free_block_list.count * CENSUS_LOG_MAX_RECORD_SIZE;
-  }
-  gpr_mu_unlock(&g_log.lock);
-  return space;
-}
-
-int census_log_out_of_space_count(void) {
-  GPR_ASSERT(g_log.initialized);
-  return gpr_atm_acq_load(&g_log.out_of_space_count);
-}
diff --git a/src/core/statistics/census_log.h b/src/core/statistics/census_log.h
deleted file mode 100644
index 356437c..0000000
--- a/src/core/statistics/census_log.h
+++ /dev/null
@@ -1,91 +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_STATISTICS_CENSUS_LOG_H
-#define GRPC_INTERNAL_CORE_STATISTICS_CENSUS_LOG_H
-
-#include <stddef.h>
-
-/* Maximum record size, in bytes. */
-#define CENSUS_LOG_2_MAX_RECORD_SIZE 14 /* 2^14 = 16KB */
-#define CENSUS_LOG_MAX_RECORD_SIZE (1 << CENSUS_LOG_2_MAX_RECORD_SIZE)
-
-/* Initialize the statistics logging subsystem with the given log size. A log
-   size of 0 will result in the smallest possible log for the platform
-   (approximately CENSUS_LOG_MAX_RECORD_SIZE * gpr_cpu_num_cores()). If
-   discard_old_records is non-zero, then new records will displace older ones
-   when the log is full. This function must be called before any other
-   census_log functions.
-*/
-void census_log_initialize(size_t size_in_mb, int discard_old_records);
-
-/* Shutdown the logging subsystem. Caller must ensure that:
-   - no in progress or future call to any census_log functions
-   - no incomplete records
-*/
-void census_log_shutdown(void);
-
-/* Allocates and returns a 'size' bytes record and marks it in use. A
-   subsequent census_log_end_write() marks the record complete. The
-   'bytes_written' census_log_end_write() argument must be <=
-   'size'. Returns NULL if out-of-space AND:
-       - log is configured to keep old records OR
-       - all blocks are pinned by incomplete records.
-*/
-void *census_log_start_write(size_t size);
-
-void census_log_end_write(void *record, size_t bytes_written);
-
-/* census_log_read_next() iterates over blocks with data and for each block
-   returns a pointer to the first unread byte. The number of bytes that can be
-   read are returned in 'bytes_available'. Reader is expected to read all
-   available data. Reading the data consumes it i.e. it cannot be read again.
-   census_log_read_next() returns NULL if the end is reached i.e last block
-   is read. census_log_init_reader() starts the iteration or aborts the
-   current iteration.
-*/
-void census_log_init_reader(void);
-const void *census_log_read_next(size_t *bytes_available);
-
-/* Returns estimated remaining space across all blocks, in bytes. If log is
-   configured to discard old records, returns total log space. Otherwise,
-   returns space available in empty blocks (partially filled blocks are
-   treated as full).
-*/
-size_t census_log_remaining_space(void);
-
-/* Returns the number of times gprc_stats_log_start_write() failed due to
-   out-of-space. */
-int census_log_out_of_space_count(void);
-
-#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_LOG_H */
diff --git a/src/core/statistics/census_rpc_stats.c b/src/core/statistics/census_rpc_stats.c
deleted file mode 100644
index 524a607..0000000
--- a/src/core/statistics/census_rpc_stats.c
+++ /dev/null
@@ -1,253 +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 <string.h>
-
-#include "src/core/statistics/census_interface.h"
-#include "src/core/statistics/census_rpc_stats.h"
-#include "src/core/statistics/hash_table.h"
-#include "src/core/statistics/census_tracing.h"
-#include "src/core/statistics/window_stats.h"
-#include "src/core/support/murmur_hash.h"
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-
-#define NUM_INTERVALS 3
-#define MINUTE_INTERVAL 0
-#define HOUR_INTERVAL 1
-#define TOTAL_INTERVAL 2
-
-/* for easier typing */
-typedef census_per_method_rpc_stats per_method_stats;
-
-/* Ensure mu is only initialized once. */
-static gpr_once g_stats_store_mu_init = GPR_ONCE_INIT;
-/* Guards two stats stores. */
-static gpr_mu g_mu;
-static census_ht *g_client_stats_store = NULL;
-static census_ht *g_server_stats_store = NULL;
-
-static void init_mutex(void) { gpr_mu_init(&g_mu); }
-
-static void init_mutex_once(void) {
-  gpr_once_init(&g_stats_store_mu_init, init_mutex);
-}
-
-static int cmp_str_keys(const void *k1, const void *k2) {
-  return strcmp((const char *)k1, (const char *)k2);
-}
-
-/* TODO(hongyu): replace it with cityhash64 */
-static uint64_t simple_hash(const void *k) {
-  size_t len = strlen(k);
-  uint64_t higher = gpr_murmur_hash3((const char *)k, len / 2, 0);
-  return higher << 32 |
-         gpr_murmur_hash3((const char *)k + len / 2, len - len / 2, 0);
-}
-
-static void delete_stats(void *stats) {
-  census_window_stats_destroy((struct census_window_stats *)stats);
-}
-
-static void delete_key(void *key) { gpr_free(key); }
-
-static const census_ht_option ht_opt = {
-    CENSUS_HT_POINTER /* key type */, 1999 /* n_of_buckets */,
-    simple_hash /* hash function */, cmp_str_keys /* key comparator */,
-    delete_stats /* data deleter */, delete_key /* key deleter */
-};
-
-static void init_rpc_stats(void *stats) {
-  memset(stats, 0, sizeof(census_rpc_stats));
-}
-
-static void stat_add_proportion(double p, void *base, const void *addme) {
-  census_rpc_stats *b = (census_rpc_stats *)base;
-  census_rpc_stats *a = (census_rpc_stats *)addme;
-  b->cnt += p * a->cnt;
-  b->rpc_error_cnt += p * a->rpc_error_cnt;
-  b->app_error_cnt += p * a->app_error_cnt;
-  b->elapsed_time_ms += p * a->elapsed_time_ms;
-  b->api_request_bytes += p * a->api_request_bytes;
-  b->wire_request_bytes += p * a->wire_request_bytes;
-  b->api_response_bytes += p * a->api_response_bytes;
-  b->wire_response_bytes += p * a->wire_response_bytes;
-}
-
-static void stat_add(void *base, const void *addme) {
-  stat_add_proportion(1.0, base, addme);
-}
-
-static gpr_timespec min_hour_total_intervals[3] = {
-    {60, 0}, {3600, 0}, {36000000, 0}};
-
-static const census_window_stats_stat_info window_stats_settings = {
-    sizeof(census_rpc_stats), init_rpc_stats, stat_add, stat_add_proportion};
-
-census_rpc_stats *census_rpc_stats_create_empty(void) {
-  census_rpc_stats *ret =
-      (census_rpc_stats *)gpr_malloc(sizeof(census_rpc_stats));
-  memset(ret, 0, sizeof(census_rpc_stats));
-  return ret;
-}
-
-void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats *data) {
-  int i = 0;
-  for (i = 0; i < data->num_entries; i++) {
-    if (data->stats[i].method != NULL) {
-      gpr_free((void *)data->stats[i].method);
-    }
-  }
-  if (data->stats != NULL) {
-    gpr_free(data->stats);
-  }
-  data->num_entries = 0;
-  data->stats = NULL;
-}
-
-static void record_stats(census_ht *store, census_op_id op_id,
-                         const census_rpc_stats *stats) {
-  gpr_mu_lock(&g_mu);
-  if (store != NULL) {
-    census_trace_obj *trace = NULL;
-    census_internal_lock_trace_store();
-    trace = census_get_trace_obj_locked(op_id);
-    if (trace != NULL) {
-      const char *method_name = census_get_trace_method_name(trace);
-      struct census_window_stats *window_stats = NULL;
-      census_ht_key key;
-      key.ptr = (void *)method_name;
-      window_stats = census_ht_find(store, key);
-      census_internal_unlock_trace_store();
-      if (window_stats == NULL) {
-        window_stats = census_window_stats_create(3, min_hour_total_intervals,
-                                                  30, &window_stats_settings);
-        key.ptr = gpr_strdup(key.ptr);
-        census_ht_insert(store, key, (void *)window_stats);
-      }
-      census_window_stats_add(window_stats, gpr_now(GPR_CLOCK_REALTIME), stats);
-    } else {
-      census_internal_unlock_trace_store();
-    }
-  }
-  gpr_mu_unlock(&g_mu);
-}
-
-void census_record_rpc_client_stats(census_op_id op_id,
-                                    const census_rpc_stats *stats) {
-  record_stats(g_client_stats_store, op_id, stats);
-}
-
-void census_record_rpc_server_stats(census_op_id op_id,
-                                    const census_rpc_stats *stats) {
-  record_stats(g_server_stats_store, op_id, stats);
-}
-
-/* Get stats from input stats store */
-static void get_stats(census_ht *store, census_aggregated_rpc_stats *data) {
-  GPR_ASSERT(data != NULL);
-  if (data->num_entries != 0) {
-    census_aggregated_rpc_stats_set_empty(data);
-  }
-  gpr_mu_lock(&g_mu);
-  if (store != NULL) {
-    size_t n;
-    unsigned i, j;
-    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;
-      data->stats =
-          (per_method_stats *)gpr_malloc(sizeof(per_method_stats) * n);
-      for (i = 0; i < n; i++) {
-        census_window_stats_sums sums[NUM_INTERVALS];
-        for (j = 0; j < NUM_INTERVALS; j++) {
-          sums[j].statistic = (void *)census_rpc_stats_create_empty();
-        }
-        data->stats[i].method = gpr_strdup(kv[i].k.ptr);
-        census_window_stats_get_sums(kv[i].v, now, sums);
-        data->stats[i].minute_stats =
-            *(census_rpc_stats *)sums[MINUTE_INTERVAL].statistic;
-        data->stats[i].hour_stats =
-            *(census_rpc_stats *)sums[HOUR_INTERVAL].statistic;
-        data->stats[i].total_stats =
-            *(census_rpc_stats *)sums[TOTAL_INTERVAL].statistic;
-        for (j = 0; j < NUM_INTERVALS; j++) {
-          gpr_free(sums[j].statistic);
-        }
-      }
-      gpr_free(kv);
-    }
-  }
-  gpr_mu_unlock(&g_mu);
-}
-
-void census_get_client_stats(census_aggregated_rpc_stats *data) {
-  get_stats(g_client_stats_store, data);
-}
-
-void census_get_server_stats(census_aggregated_rpc_stats *data) {
-  get_stats(g_server_stats_store, data);
-}
-
-void census_stats_store_init(void) {
-  init_mutex_once();
-  gpr_mu_lock(&g_mu);
-  if (g_client_stats_store == NULL && g_server_stats_store == NULL) {
-    g_client_stats_store = census_ht_create(&ht_opt);
-    g_server_stats_store = census_ht_create(&ht_opt);
-  } else {
-    gpr_log(GPR_ERROR, "Census stats store already initialized.");
-  }
-  gpr_mu_unlock(&g_mu);
-}
-
-void census_stats_store_shutdown(void) {
-  init_mutex_once();
-  gpr_mu_lock(&g_mu);
-  if (g_client_stats_store != NULL) {
-    census_ht_destroy(g_client_stats_store);
-    g_client_stats_store = NULL;
-  } else {
-    gpr_log(GPR_ERROR, "Census server stats store not initialized.");
-  }
-  if (g_server_stats_store != NULL) {
-    census_ht_destroy(g_server_stats_store);
-    g_server_stats_store = NULL;
-  } else {
-    gpr_log(GPR_ERROR, "Census client stats store not initialized.");
-  }
-  gpr_mu_unlock(&g_mu);
-}
diff --git a/src/core/statistics/census_rpc_stats.h b/src/core/statistics/census_rpc_stats.h
deleted file mode 100644
index 8bdbc49..0000000
--- a/src/core/statistics/census_rpc_stats.h
+++ /dev/null
@@ -1,101 +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_STATISTICS_CENSUS_RPC_STATS_H
-#define GRPC_INTERNAL_CORE_STATISTICS_CENSUS_RPC_STATS_H
-
-#include "src/core/statistics/census_interface.h"
-#include <grpc/support/port_platform.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct census_rpc_stats {
-  uint64_t cnt;
-  uint64_t rpc_error_cnt;
-  uint64_t app_error_cnt;
-  double elapsed_time_ms;
-  double api_request_bytes;
-  double wire_request_bytes;
-  double api_response_bytes;
-  double wire_response_bytes;
-};
-
-/* Creates an empty rpc stats object on heap. */
-census_rpc_stats *census_rpc_stats_create_empty(void);
-
-typedef struct census_per_method_rpc_stats {
-  const char *method;
-  census_rpc_stats minute_stats; /* cumulative stats in the past minute */
-  census_rpc_stats hour_stats;   /* cumulative stats in the past hour */
-  census_rpc_stats total_stats;  /* cumulative stats from last gc */
-} census_per_method_rpc_stats;
-
-typedef struct census_aggregated_rpc_stats {
-  int num_entries;
-  census_per_method_rpc_stats *stats;
-} census_aggregated_rpc_stats;
-
-/* Initializes an aggregated rpc stats object to an empty state. */
-void census_aggregated_rpc_stats_set_empty(census_aggregated_rpc_stats *data);
-
-/* Records client side stats of a rpc. */
-void census_record_rpc_client_stats(census_op_id op_id,
-                                    const census_rpc_stats *stats);
-
-/* Records server side stats of a rpc. */
-void census_record_rpc_server_stats(census_op_id op_id,
-                                    const census_rpc_stats *stats);
-
-/* The following two functions are intended for inprocess query of
-   per-service per-method stats from grpc implementations. */
-
-/* Populates *data_map with server side aggregated per-service per-method
-   stats.
-   DO NOT CALL from outside of grpc code. */
-void census_get_server_stats(census_aggregated_rpc_stats *data_map);
-
-/* Populates *data_map with client side aggregated per-service per-method
-   stats.
-   DO NOT CALL from outside of grpc code. */
-void census_get_client_stats(census_aggregated_rpc_stats *data_map);
-
-void census_stats_store_init(void);
-void census_stats_store_shutdown(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_RPC_STATS_H */
diff --git a/src/core/statistics/census_tracing.c b/src/core/statistics/census_tracing.c
deleted file mode 100644
index dc0f8a2..0000000
--- a/src/core/statistics/census_tracing.c
+++ /dev/null
@@ -1,238 +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/statistics/census_interface.h"
-#include "src/core/statistics/census_tracing.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include "src/core/statistics/hash_table.h"
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/sync.h>
-
-void census_trace_obj_destroy(census_trace_obj *obj) {
-  census_trace_annotation *p = obj->annotations;
-  while (p != NULL) {
-    census_trace_annotation *next = p->next;
-    gpr_free(p);
-    p = next;
-  }
-  gpr_free(obj->method);
-  gpr_free(obj);
-}
-
-static void delete_trace_obj(void *obj) {
-  census_trace_obj_destroy((census_trace_obj *)obj);
-}
-
-static const census_ht_option ht_opt = {
-    CENSUS_HT_UINT64 /* key type */, 571 /* n_of_buckets */, NULL /* hash */,
-    NULL /* compare_keys */, delete_trace_obj /* delete data */,
-    NULL /* delete key */
-};
-
-static gpr_once g_init_mutex_once = GPR_ONCE_INIT;
-static gpr_mu g_mu; /* Guards following two static variables. */
-static census_ht *g_trace_store = NULL;
-static uint64_t g_id = 0;
-
-static census_ht_key op_id_as_key(census_op_id *id) {
-  return *(census_ht_key *)id;
-}
-
-static uint64_t op_id_2_uint64(census_op_id *id) {
-  uint64_t ret;
-  memcpy(&ret, id, sizeof(census_op_id));
-  return ret;
-}
-
-static void init_mutex(void) { gpr_mu_init(&g_mu); }
-
-static void init_mutex_once(void) {
-  gpr_once_init(&g_init_mutex_once, init_mutex);
-}
-
-census_op_id census_tracing_start_op(void) {
-  gpr_mu_lock(&g_mu);
-  {
-    census_trace_obj *ret = gpr_malloc(sizeof(census_trace_obj));
-    memset(ret, 0, sizeof(census_trace_obj));
-    g_id++;
-    memcpy(&ret->id, &g_id, sizeof(census_op_id));
-    ret->rpc_stats.cnt = 1;
-    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);
-    return ret->id;
-  }
-}
-
-int census_add_method_tag(census_op_id op_id, const char *method) {
-  int ret = 0;
-  census_trace_obj *trace = NULL;
-  gpr_mu_lock(&g_mu);
-  trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
-  if (trace == NULL) {
-    ret = 1;
-  } else {
-    trace->method = gpr_strdup(method);
-  }
-  gpr_mu_unlock(&g_mu);
-  return ret;
-}
-
-void census_tracing_print(census_op_id op_id, const char *anno_txt) {
-  census_trace_obj *trace = NULL;
-  gpr_mu_lock(&g_mu);
-  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(GPR_CLOCK_REALTIME);
-    {
-      char *d = anno->txt;
-      const char *s = anno_txt;
-      int n = 0;
-      for (; n < CENSUS_MAX_ANNOTATION_LENGTH && *s != '\0'; ++n) {
-        *d++ = *s++;
-      }
-      *d = '\0';
-    }
-    anno->next = trace->annotations;
-    trace->annotations = anno;
-  }
-  gpr_mu_unlock(&g_mu);
-}
-
-void census_tracing_end_op(census_op_id op_id) {
-  census_trace_obj *trace = NULL;
-  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(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);
-    census_ht_erase(g_trace_store, op_id_as_key(&op_id));
-  }
-  gpr_mu_unlock(&g_mu);
-}
-
-void census_tracing_init(void) {
-  init_mutex_once();
-  gpr_mu_lock(&g_mu);
-  if (g_trace_store == NULL) {
-    g_id = 1;
-    g_trace_store = census_ht_create(&ht_opt);
-  } else {
-    gpr_log(GPR_ERROR, "Census trace store already initialized.");
-  }
-  gpr_mu_unlock(&g_mu);
-}
-
-void census_tracing_shutdown(void) {
-  gpr_mu_lock(&g_mu);
-  if (g_trace_store != NULL) {
-    census_ht_destroy(g_trace_store);
-    g_trace_store = NULL;
-  } else {
-    gpr_log(GPR_ERROR, "Census trace store is not initialized.");
-  }
-  gpr_mu_unlock(&g_mu);
-}
-
-void census_internal_lock_trace_store(void) { gpr_mu_lock(&g_mu); }
-
-void census_internal_unlock_trace_store(void) { gpr_mu_unlock(&g_mu); }
-
-census_trace_obj *census_get_trace_obj_locked(census_op_id op_id) {
-  if (g_trace_store == NULL) {
-    gpr_log(GPR_ERROR, "Census trace store is not initialized.");
-    return NULL;
-  }
-  return (census_trace_obj *)census_ht_find(g_trace_store,
-                                            op_id_as_key(&op_id));
-}
-
-const char *census_get_trace_method_name(const census_trace_obj *trace) {
-  return trace->method;
-}
-
-static census_trace_annotation *dup_annotation_chain(
-    census_trace_annotation *from) {
-  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));
-    to = &(*to)->next;
-  }
-  return ret;
-}
-
-static census_trace_obj *trace_obj_dup(census_trace_obj *from) {
-  census_trace_obj *to = NULL;
-  GPR_ASSERT(from != NULL);
-  to = gpr_malloc(sizeof(census_trace_obj));
-  to->id = from->id;
-  to->ts = from->ts;
-  to->rpc_stats = from->rpc_stats;
-  to->method = gpr_strdup(from->method);
-  to->annotations = dup_annotation_chain(from->annotations);
-  return to;
-}
-
-census_trace_obj **census_get_active_ops(int *num_active_ops) {
-  census_trace_obj **ret = NULL;
-  gpr_mu_lock(&g_mu);
-  if (g_trace_store != NULL) {
-    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) {
-      size_t i = 0;
-      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);
-      }
-    }
-    gpr_free(all_kvs);
-  }
-  gpr_mu_unlock(&g_mu);
-  return ret;
-}
diff --git a/src/core/statistics/census_tracing.h b/src/core/statistics/census_tracing.h
deleted file mode 100644
index bb3f255..0000000
--- a/src/core/statistics/census_tracing.h
+++ /dev/null
@@ -1,96 +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_STATISTICS_CENSUS_TRACING_H
-#define GRPC_INTERNAL_CORE_STATISTICS_CENSUS_TRACING_H
-
-#include <grpc/support/time.h>
-#include "src/core/statistics/census_rpc_stats.h"
-
-/* WARNING: The data structures and APIs provided by this file are for GRPC
-   library's internal use ONLY. They might be changed in backward-incompatible
-   ways and are not subject to any deprecation policy.
-   They are not recommended for external use.
- */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Struct for a trace annotation. */
-typedef struct census_trace_annotation {
-  gpr_timespec ts;                            /* timestamp of the annotation */
-  char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */
-  struct census_trace_annotation *next;
-} census_trace_annotation;
-
-typedef struct census_trace_obj {
-  census_op_id id;
-  gpr_timespec ts;
-  census_rpc_stats rpc_stats;
-  char *method;
-  census_trace_annotation *annotations;
-} census_trace_obj;
-
-/* Deletes trace object. */
-void census_trace_obj_destroy(census_trace_obj *obj);
-
-/* Initializes trace store. This function is thread safe. */
-void census_tracing_init(void);
-
-/* Shutsdown trace store. This function is thread safe. */
-void census_tracing_shutdown(void);
-
-/* Gets trace obj corresponding to the input op_id. Returns NULL if trace store
-   is not initialized or trace obj is not found. Requires trace store being
-   locked before calling this function. */
-census_trace_obj *census_get_trace_obj_locked(census_op_id op_id);
-
-/* The following two functions acquire and release the trace store global lock.
-   They are for census internal use only. */
-void census_internal_lock_trace_store(void);
-void census_internal_unlock_trace_store(void);
-
-/* Gets method name associated with the input trace object. */
-const char *census_get_trace_method_name(const census_trace_obj *trace);
-
-/* Returns an array of pointers to trace objects of currently active operations
-   and fills in number of active operations. Returns NULL if there are no active
-   operations.
-   Caller owns the returned objects. */
-census_trace_obj **census_get_active_ops(int *num_active_ops);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_STATISTICS_CENSUS_TRACING_H */
diff --git a/src/core/statistics/hash_table.c b/src/core/statistics/hash_table.c
deleted file mode 100644
index 0cadcd4..0000000
--- a/src/core/statistics/hash_table.c
+++ /dev/null
@@ -1,303 +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/statistics/hash_table.h"
-
-#include <stdio.h>
-#include <stddef.h>
-
-#include <grpc/support/log.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/port_platform.h>
-
-#define CENSUS_HT_NUM_BUCKETS 1999
-
-/* A single hash table data entry */
-typedef struct ht_entry {
-  census_ht_key key;
-  void *data;
-  struct ht_entry *next;
-} ht_entry;
-
-/* hash table bucket */
-typedef struct bucket {
-  /* NULL if bucket is empty */
-  ht_entry *next;
-  /* -1 if all buckets are empty. */
-  int32_t prev_non_empty_bucket;
-  /* -1 if all buckets are empty. */
-  int32_t next_non_empty_bucket;
-} bucket;
-
-struct unresizable_hash_table {
-  /* Number of entries in the table */
-  size_t size;
-  /* Number of buckets */
-  uint32_t num_buckets;
-  /* Array of buckets initialized at creation time. Memory consumption is
-     16 bytes per bucket on a 64-bit platform. */
-  bucket *buckets;
-  /* Index of the first non-empty bucket. -1 iff size == 0. */
-  int32_t first_non_empty_bucket;
-  /* Index of the last non_empty bucket. -1 iff size == 0. */
-  int32_t last_non_empty_bucket;
-  /* Immutable options of this hash table, initialized at creation time. */
-  census_ht_option options;
-};
-
-typedef struct entry_locator {
-  int32_t bucket_idx;
-  int is_first_in_chain;
-  int found;
-  ht_entry *prev_entry;
-} entry_locator;
-
-/* Asserts if option is not valid. */
-void check_options(const census_ht_option *option) {
-  GPR_ASSERT(option != NULL);
-  GPR_ASSERT(option->num_buckets > 0);
-  GPR_ASSERT(option->key_type == CENSUS_HT_UINT64 ||
-             option->key_type == CENSUS_HT_POINTER);
-  if (option->key_type == CENSUS_HT_UINT64) {
-    GPR_ASSERT(option->hash == NULL);
-  } else if (option->key_type == CENSUS_HT_POINTER) {
-    GPR_ASSERT(option->hash != NULL);
-    GPR_ASSERT(option->compare_keys != NULL);
-  }
-}
-
-#define REMOVE_NEXT(options, ptr) \
-  do {                            \
-    ht_entry *tmp = (ptr)->next;  \
-    (ptr)->next = tmp->next;      \
-    delete_entry(options, tmp);   \
-  } while (0)
-
-static void delete_entry(const census_ht_option *opt, ht_entry *p) {
-  if (opt->delete_data != NULL) {
-    opt->delete_data(p->data);
-  }
-  if (opt->delete_key != NULL) {
-    opt->delete_key(p->key.ptr);
-  }
-  gpr_free(p);
-}
-
-static uint64_t hash(const census_ht_option *opt, census_ht_key key) {
-  return opt->key_type == CENSUS_HT_UINT64 ? key.val : opt->hash(key.ptr);
-}
-
-census_ht *census_ht_create(const census_ht_option *option) {
-  int i;
-  census_ht *ret = NULL;
-  check_options(option);
-  ret = (census_ht *)gpr_malloc(sizeof(census_ht));
-  ret->size = 0;
-  ret->num_buckets = option->num_buckets;
-  ret->buckets = (bucket *)gpr_malloc(sizeof(bucket) * ret->num_buckets);
-  ret->options = *option;
-  /* initialize each bucket */
-  for (i = 0; i < ret->options.num_buckets; i++) {
-    ret->buckets[i].prev_non_empty_bucket = -1;
-    ret->buckets[i].next_non_empty_bucket = -1;
-    ret->buckets[i].next = NULL;
-  }
-  return ret;
-}
-
-static int32_t find_bucket_idx(const census_ht *ht, census_ht_key key) {
-  return hash(&ht->options, key) % ht->num_buckets;
-}
-
-static int keys_match(const census_ht_option *opt, const ht_entry *p,
-                      const census_ht_key key) {
-  GPR_ASSERT(opt->key_type == CENSUS_HT_UINT64 ||
-             opt->key_type == CENSUS_HT_POINTER);
-  if (opt->key_type == CENSUS_HT_UINT64) return p->key.val == key.val;
-  return !opt->compare_keys((p->key).ptr, key.ptr);
-}
-
-static entry_locator ht_find(const census_ht *ht, census_ht_key key) {
-  entry_locator loc = {0, 0, 0, NULL};
-  int32_t idx = 0;
-  ht_entry *ptr = NULL;
-  GPR_ASSERT(ht != NULL);
-  idx = find_bucket_idx(ht, key);
-  ptr = ht->buckets[idx].next;
-  if (ptr == NULL) {
-    /* bucket is empty */
-    return loc;
-  }
-  if (keys_match(&ht->options, ptr, key)) {
-    loc.bucket_idx = idx;
-    loc.is_first_in_chain = 1;
-    loc.found = 1;
-    return loc;
-  } else {
-    for (; ptr->next != NULL; ptr = ptr->next) {
-      if (keys_match(&ht->options, ptr->next, key)) {
-        loc.bucket_idx = idx;
-        loc.is_first_in_chain = 0;
-        loc.found = 1;
-        loc.prev_entry = ptr;
-        return loc;
-      }
-    }
-  }
-  /* Could not find the key */
-  return loc;
-}
-
-void *census_ht_find(const census_ht *ht, census_ht_key key) {
-  entry_locator loc = ht_find(ht, key);
-  if (loc.found == 0) {
-    return NULL;
-  }
-  return loc.is_first_in_chain ? ht->buckets[loc.bucket_idx].next->data
-                               : loc.prev_entry->next->data;
-}
-
-void census_ht_insert(census_ht *ht, census_ht_key key, void *data) {
-  int32_t idx = find_bucket_idx(ht, key);
-  ht_entry *ptr = NULL;
-  entry_locator loc = ht_find(ht, key);
-  if (loc.found) {
-    /* Replace old value with new value. */
-    ptr = loc.is_first_in_chain ? ht->buckets[loc.bucket_idx].next
-                                : loc.prev_entry->next;
-    if (ht->options.delete_data != NULL) {
-      ht->options.delete_data(ptr->data);
-    }
-    ptr->data = data;
-    return;
-  }
-
-  /* first entry in the table. */
-  if (ht->size == 0) {
-    ht->buckets[idx].next_non_empty_bucket = -1;
-    ht->buckets[idx].prev_non_empty_bucket = -1;
-    ht->first_non_empty_bucket = idx;
-    ht->last_non_empty_bucket = idx;
-  } else if (ht->buckets[idx].next == NULL) {
-    /* first entry in the bucket. */
-    ht->buckets[ht->last_non_empty_bucket].next_non_empty_bucket = idx;
-    ht->buckets[idx].prev_non_empty_bucket = ht->last_non_empty_bucket;
-    ht->buckets[idx].next_non_empty_bucket = -1;
-    ht->last_non_empty_bucket = idx;
-  }
-  ptr = (ht_entry *)gpr_malloc(sizeof(ht_entry));
-  ptr->key = key;
-  ptr->data = data;
-  ptr->next = ht->buckets[idx].next;
-  ht->buckets[idx].next = ptr;
-  ht->size++;
-}
-
-void census_ht_erase(census_ht *ht, census_ht_key key) {
-  entry_locator loc = ht_find(ht, key);
-  if (loc.found == 0) {
-    /* noop if not found */
-    return;
-  }
-  ht->size--;
-  if (loc.is_first_in_chain) {
-    bucket *b = &ht->buckets[loc.bucket_idx];
-    GPR_ASSERT(b->next != NULL);
-    /* The only entry in the bucket */
-    if (b->next->next == NULL) {
-      int prev = b->prev_non_empty_bucket;
-      int next = b->next_non_empty_bucket;
-      if (prev != -1) {
-        ht->buckets[prev].next_non_empty_bucket = next;
-      } else {
-        ht->first_non_empty_bucket = next;
-      }
-      if (next != -1) {
-        ht->buckets[next].prev_non_empty_bucket = prev;
-      } else {
-        ht->last_non_empty_bucket = prev;
-      }
-    }
-    REMOVE_NEXT(&ht->options, b);
-  } else {
-    GPR_ASSERT(loc.prev_entry->next != NULL);
-    REMOVE_NEXT(&ht->options, loc.prev_entry);
-  }
-}
-
-/* Returns NULL if input table is empty. */
-census_ht_kv *census_ht_get_all_elements(const census_ht *ht, size_t *num) {
-  census_ht_kv *ret = NULL;
-  int i = 0;
-  int32_t idx = -1;
-  GPR_ASSERT(ht != NULL && num != NULL);
-  *num = ht->size;
-  if (*num == 0) {
-    return NULL;
-  }
-
-  ret = (census_ht_kv *)gpr_malloc(sizeof(census_ht_kv) * ht->size);
-  idx = ht->first_non_empty_bucket;
-  while (idx >= 0) {
-    ht_entry *ptr = ht->buckets[idx].next;
-    for (; ptr != NULL; ptr = ptr->next) {
-      ret[i].k = ptr->key;
-      ret[i].v = ptr->data;
-      i++;
-    }
-    idx = ht->buckets[idx].next_non_empty_bucket;
-  }
-  return ret;
-}
-
-static void ht_delete_entry_chain(const census_ht_option *options,
-                                  ht_entry *first) {
-  if (first == NULL) {
-    return;
-  }
-  if (first->next != NULL) {
-    ht_delete_entry_chain(options, first->next);
-  }
-  delete_entry(options, first);
-}
-
-void census_ht_destroy(census_ht *ht) {
-  unsigned i;
-  for (i = 0; i < ht->num_buckets; ++i) {
-    ht_delete_entry_chain(&ht->options, ht->buckets[i].next);
-  }
-  gpr_free(ht->buckets);
-  gpr_free(ht);
-}
-
-size_t census_ht_get_size(const census_ht *ht) { return ht->size; }
diff --git a/src/core/statistics/hash_table.h b/src/core/statistics/hash_table.h
deleted file mode 100644
index d9860a9..0000000
--- a/src/core/statistics/hash_table.h
+++ /dev/null
@@ -1,131 +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_STATISTICS_HASH_TABLE_H
-#define GRPC_INTERNAL_CORE_STATISTICS_HASH_TABLE_H
-
-#include <stddef.h>
-
-#include <grpc/support/port_platform.h>
-
-/* A chain based hash table with fixed number of buckets.
-   Your probably shouldn't use this code directly. It is implemented for the
-   use case in census trace store and stats store, where number of entries in
-   the table is in the scale of upto several thousands, entries are added and
-   removed from the table very frequently (~100k/s), the frequency of find()
-   operations is roughly several times of the frequency of insert() and erase()
-   Comparing to find(), the insert(), erase() and get_all_entries() operations
-   are much less freqent (<1/s).
-
-   Per bucket memory overhead is about (8 + sizeof(intptr_t) bytes.
-   Per entry memory overhead is about (8 + 2 * sizeof(intptr_t) bytes.
-
-   All functions are not thread-safe. Synchronization will be provided in the
-   upper layer (in trace store and stats store).
-*/
-
-/* Opaque hash table struct */
-typedef struct unresizable_hash_table census_ht;
-
-/* Currently, the hash_table can take two types of keys. (uint64 for trace
-   store and const char* for stats store). */
-typedef union {
-  uint64_t val;
-  void *ptr;
-} census_ht_key;
-
-typedef enum census_ht_key_type {
-  CENSUS_HT_UINT64 = 0,
-  CENSUS_HT_POINTER = 1
-} census_ht_key_type;
-
-typedef struct census_ht_option {
-  /* Type of hash key */
-  census_ht_key_type key_type;
-  /* Desired number of buckets, preferably a prime number */
-  int32_t num_buckets;
-  /* Fucntion to calculate uint64 hash value of the key. Only takes effect if
-     key_type is POINTER. */
-  uint64_t (*hash)(const void *);
-  /* Function to compare two keys, returns 0 iff equal. Only takes effect if
-     key_type is POINTER */
-  int (*compare_keys)(const void *k1, const void *k2);
-  /* Value deleter. NULL if no specialized delete function is needed. */
-  void (*delete_data)(void *);
-  /* Key deleter. NULL if table does not own the key. (e.g. key is part of the
-     value or key is not owned by the table.) */
-  void (*delete_key)(void *);
-} census_ht_option;
-
-/* Creates a hashtable with fixed number of buckets according to the settings
-   specified in 'options' arg. Function pointers "hash" and "compare_keys" must
-   be provided if key_type is POINTER. Asserts if fail to create. */
-census_ht *census_ht_create(const census_ht_option *options);
-
-/* Deletes hash table instance. Frees all dynamic memory owned by ht.*/
-void census_ht_destroy(census_ht *ht);
-
-/* Inserts the input key-val pair into hash_table. If an entry with the same key
-   exists in the table, the corresponding value will be overwritten by the input
-   val. */
-void census_ht_insert(census_ht *ht, census_ht_key key, void *val);
-
-/* Returns pointer to data, returns NULL if not found. */
-void *census_ht_find(const census_ht *ht, census_ht_key key);
-
-/* Erase hash table entry with input key. Noop if key is not found. */
-void census_ht_erase(census_ht *ht, census_ht_key key);
-
-typedef struct census_ht_kv {
-  census_ht_key k;
-  void *v;
-} census_ht_kv;
-
-/* Returns an array of pointers to all values in the hash table. Order of the
-   elements can be arbitrary. Sets 'num' to the size of returned array. Caller
-   owns returned array. */
-census_ht_kv *census_ht_get_all_elements(const census_ht *ht, size_t *num);
-
-/* Returns number of elements kept. */
-size_t census_ht_get_size(const census_ht *ht);
-
-/* Functor applied on each key-value pair while iterating through entries in the
-   table. The functor should not mutate data. */
-typedef void (*census_ht_itr_cb)(census_ht_key key, const void *val_ptr,
-                                 void *state);
-
-/* Iterates through all key-value pairs in the hash_table. The callback function
-   should not invalidate data entries. */
-uint64_t census_ht_for_all(const census_ht *ht, census_ht_itr_cb);
-
-#endif /* GRPC_INTERNAL_CORE_STATISTICS_HASH_TABLE_H */
diff --git a/src/core/statistics/window_stats.c b/src/core/statistics/window_stats.c
deleted file mode 100644
index 3f29408..0000000
--- a/src/core/statistics/window_stats.c
+++ /dev/null
@@ -1,316 +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/statistics/window_stats.h"
-#include <math.h>
-#include <stddef.h>
-#include <string.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
-#include <grpc/support/useful.h>
-
-/* typedefs make typing long names easier. Use cws (for census_window_stats) */
-typedef census_window_stats_stat_info cws_stat_info;
-typedef struct census_window_stats_sum cws_sum;
-
-/* Each interval is composed of a number of buckets, which hold a count of
-   entries and a single statistic */
-typedef struct census_window_stats_bucket {
-  int64_t count;
-  void *statistic;
-} cws_bucket;
-
-/* Each interval has a set of buckets, and the variables needed to keep
-   track of their current state */
-typedef struct census_window_stats_interval_stats {
-  /* The buckets. There will be 'granularity' + 1 of these. */
-  cws_bucket *buckets;
-  /* Index of the bucket containing the smallest time interval. */
-  int bottom_bucket;
-  /* The smallest time storable in the current window. */
-  int64_t bottom;
-  /* The largest time storable in the current window + 1ns */
-  int64_t top;
-  /* The width of each bucket in ns. */
-  int64_t width;
-} cws_interval_stats;
-
-typedef struct census_window_stats {
-  /* Number of intervals. */
-  int nintervals;
-  /* Number of buckets in each interval. 'granularity' + 1. */
-  int nbuckets;
-  /* Record of stat_info. */
-  cws_stat_info stat_info;
-  /* Stats for each interval. */
-  cws_interval_stats *interval_stats;
-  /* The time the newset stat was recorded. */
-  int64_t newest_time;
-} window_stats;
-
-/* Calculate an actual bucket index from a logical index 'IDX'. Other
-   parameters supply information on the interval struct and overall stats. */
-#define BUCKET_IDX(IS, IDX, WSTATS) \
-  ((IS->bottom_bucket + (IDX)) % WSTATS->nbuckets)
-
-/* The maximum seconds value we can have in a valid timespec. More than this
-   will result in overflow in timespec_to_ns(). This works out to ~292 years.
-   TODO: consider using doubles instead of int64. */
-static int64_t max_seconds = (GPR_INT64_MAX - GPR_NS_PER_SEC) / GPR_NS_PER_SEC;
-
-static int64_t timespec_to_ns(const gpr_timespec ts) {
-  if (ts.tv_sec > max_seconds) {
-    return GPR_INT64_MAX - 1;
-  }
-  return ts.tv_sec * GPR_NS_PER_SEC + ts.tv_nsec;
-}
-
-static void cws_initialize_statistic(void *statistic,
-                                     const cws_stat_info *stat_info) {
-  if (stat_info->stat_initialize == NULL) {
-    memset(statistic, 0, stat_info->stat_size);
-  } else {
-    stat_info->stat_initialize(statistic);
-  }
-}
-
-/* Create and initialize a statistic */
-static void *cws_create_statistic(const cws_stat_info *stat_info) {
-  void *stat = gpr_malloc(stat_info->stat_size);
-  cws_initialize_statistic(stat, stat_info);
-  return stat;
-}
-
-window_stats *census_window_stats_create(int nintervals,
-                                         const gpr_timespec intervals[],
-                                         int granularity,
-                                         const cws_stat_info *stat_info) {
-  window_stats *ret;
-  int i;
-  /* validate inputs */
-  GPR_ASSERT(nintervals > 0 && granularity > 2 && intervals != NULL &&
-             stat_info != NULL);
-  for (i = 0; i < nintervals; i++) {
-    int64_t ns = timespec_to_ns(intervals[i]);
-    GPR_ASSERT(intervals[i].tv_sec >= 0 && intervals[i].tv_nsec >= 0 &&
-               intervals[i].tv_nsec < GPR_NS_PER_SEC && ns >= 100 &&
-               granularity * 10 <= ns);
-  }
-  /* Allocate and initialize relevant data structures */
-  ret = (window_stats *)gpr_malloc(sizeof(window_stats));
-  ret->nintervals = nintervals;
-  ret->nbuckets = granularity + 1;
-  ret->stat_info = *stat_info;
-  ret->interval_stats =
-      (cws_interval_stats *)gpr_malloc(nintervals * sizeof(cws_interval_stats));
-  for (i = 0; i < nintervals; i++) {
-    int64_t size_ns = timespec_to_ns(intervals[i]);
-    cws_interval_stats *is = ret->interval_stats + i;
-    cws_bucket *buckets = is->buckets =
-        (cws_bucket *)gpr_malloc(ret->nbuckets * sizeof(cws_bucket));
-    int b;
-    for (b = 0; b < ret->nbuckets; b++) {
-      buckets[b].statistic = cws_create_statistic(stat_info);
-      buckets[b].count = 0;
-    }
-    is->bottom_bucket = 0;
-    is->bottom = 0;
-    is->width = size_ns / granularity;
-    /* Check for possible overflow issues, and maximize interval size if the
-       user requested something large enough. */
-    if ((GPR_INT64_MAX - is->width) > size_ns) {
-      is->top = size_ns + is->width;
-    } else {
-      is->top = GPR_INT64_MAX;
-      is->width = GPR_INT64_MAX / (granularity + 1);
-    }
-    /* If size doesn't divide evenly, we can have a width slightly too small;
-       better to have it slightly large. */
-    if ((size_ns - (granularity + 1) * is->width) > 0) {
-      is->width += 1;
-    }
-  }
-  ret->newest_time = 0;
-  return ret;
-}
-
-/* When we try adding a measurement above the current interval range, we
-   need to "shift" the buckets sufficiently to cover the new range. */
-static void cws_shift_buckets(const window_stats *wstats,
-                              cws_interval_stats *is, int64_t when_ns) {
-  int i;
-  /* number of bucket time widths to "shift" */
-  int shift;
-  /* number of buckets to clear */
-  int nclear;
-  GPR_ASSERT(when_ns >= is->top);
-  /* number of bucket time widths to "shift" */
-  shift = ((when_ns - is->top) / is->width) + 1;
-  /* number of buckets to clear - limited by actual number of buckets */
-  nclear = GPR_MIN(shift, wstats->nbuckets);
-  for (i = 0; i < nclear; i++) {
-    int b = BUCKET_IDX(is, i, wstats);
-    is->buckets[b].count = 0;
-    cws_initialize_statistic(is->buckets[b].statistic, &wstats->stat_info);
-  }
-  /* adjust top/bottom times and current bottom bucket */
-  is->bottom_bucket = BUCKET_IDX(is, shift, wstats);
-  is->top += shift * is->width;
-  is->bottom += shift * is->width;
-}
-
-void census_window_stats_add(window_stats *wstats, const gpr_timespec when,
-                             const void *stat_value) {
-  int i;
-  int64_t when_ns = timespec_to_ns(when);
-  GPR_ASSERT(wstats->interval_stats != NULL);
-  for (i = 0; i < wstats->nintervals; i++) {
-    cws_interval_stats *is = wstats->interval_stats + i;
-    cws_bucket *bucket;
-    if (when_ns < is->bottom) { /* Below smallest time in interval: drop */
-      continue;
-    }
-    if (when_ns >= is->top) { /* above limit: shift buckets */
-      cws_shift_buckets(wstats, is, when_ns);
-    }
-    /* Add the stat. */
-    GPR_ASSERT(is->bottom <= when_ns && when_ns < is->top);
-    bucket = is->buckets +
-             BUCKET_IDX(is, (when_ns - is->bottom) / is->width, wstats);
-    bucket->count++;
-    wstats->stat_info.stat_add(bucket->statistic, stat_value);
-  }
-  if (when_ns > wstats->newest_time) {
-    wstats->newest_time = when_ns;
-  }
-}
-
-/* Add a specific bucket contents to an accumulating total. */
-static void cws_add_bucket_to_sum(cws_sum *sum, const cws_bucket *bucket,
-                                  const cws_stat_info *stat_info) {
-  sum->count += bucket->count;
-  stat_info->stat_add(sum->statistic, bucket->statistic);
-}
-
-/* Add a proportion to an accumulating sum. */
-static void cws_add_proportion_to_sum(double p, cws_sum *sum,
-                                      const cws_bucket *bucket,
-                                      const cws_stat_info *stat_info) {
-  sum->count += p * bucket->count;
-  stat_info->stat_add_proportion(p, sum->statistic, bucket->statistic);
-}
-
-void census_window_stats_get_sums(const window_stats *wstats,
-                                  const gpr_timespec when, cws_sum sums[]) {
-  int i;
-  int64_t when_ns = timespec_to_ns(when);
-  GPR_ASSERT(wstats->interval_stats != NULL);
-  for (i = 0; i < wstats->nintervals; i++) {
-    int when_bucket;
-    int new_bucket;
-    double last_proportion = 1.0;
-    double bottom_proportion;
-    cws_interval_stats *is = wstats->interval_stats + i;
-    cws_sum *sum = sums + i;
-    sum->count = 0;
-    cws_initialize_statistic(sum->statistic, &wstats->stat_info);
-    if (when_ns < is->bottom) {
-      continue;
-    }
-    if (when_ns >= is->top) {
-      cws_shift_buckets(wstats, is, when_ns);
-    }
-    /* Calculating the appropriate amount of which buckets to use can get
-       complicated. Essentially there are two cases:
-       1) if the "top" bucket (new_bucket, where the newest additions to the
-       stats recorded are entered) corresponds to 'when', then we need
-       to take a proportion of it - (if when < newest_time) or the full
-       thing. We also (possibly) need to take a corresponding
-       proportion of the bottom bucket.
-       2) Other cases, we just take a straight proportion.
-     */
-    when_bucket = (when_ns - is->bottom) / is->width;
-    new_bucket = (wstats->newest_time - is->bottom) / is->width;
-    if (new_bucket == when_bucket) {
-      int64_t bottom_bucket_time = is->bottom + when_bucket * is->width;
-      if (when_ns < wstats->newest_time) {
-        last_proportion = (double)(when_ns - bottom_bucket_time) /
-                          (double)(wstats->newest_time - bottom_bucket_time);
-        bottom_proportion =
-            (double)(is->width - (when_ns - bottom_bucket_time)) / is->width;
-      } else {
-        bottom_proportion =
-            (double)(is->width - (wstats->newest_time - bottom_bucket_time)) /
-            is->width;
-      }
-    } else {
-      last_proportion =
-          (double)(when_ns + 1 - is->bottom - when_bucket * is->width) /
-          is->width;
-      bottom_proportion = 1.0 - last_proportion;
-    }
-    cws_add_proportion_to_sum(last_proportion, sum,
-                              is->buckets + BUCKET_IDX(is, when_bucket, wstats),
-                              &wstats->stat_info);
-    if (when_bucket != 0) { /* last bucket isn't also bottom bucket */
-      int b;
-      /* Add all of "bottom" bucket if we are looking at a subset of the
-         full interval, or a proportion if we are adding full interval. */
-      cws_add_proportion_to_sum(
-          (when_bucket == wstats->nbuckets - 1 ? bottom_proportion : 1.0), sum,
-          is->buckets + is->bottom_bucket, &wstats->stat_info);
-      /* Add all the remaining buckets (everything but top and bottom). */
-      for (b = 1; b < when_bucket; b++) {
-        cws_add_bucket_to_sum(sum, is->buckets + BUCKET_IDX(is, b, wstats),
-                              &wstats->stat_info);
-      }
-    }
-  }
-}
-
-void census_window_stats_destroy(window_stats *wstats) {
-  int i;
-  GPR_ASSERT(wstats->interval_stats != NULL);
-  for (i = 0; i < wstats->nintervals; i++) {
-    int b;
-    for (b = 0; b < wstats->nbuckets; b++) {
-      gpr_free(wstats->interval_stats[i].buckets[b].statistic);
-    }
-    gpr_free(wstats->interval_stats[i].buckets);
-  }
-  gpr_free(wstats->interval_stats);
-  /* Ensure any use-after free triggers assert. */
-  wstats->interval_stats = NULL;
-  gpr_free(wstats);
-}
diff --git a/src/core/statistics/window_stats.h b/src/core/statistics/window_stats.h
deleted file mode 100644
index f4732e9..0000000
--- a/src/core/statistics/window_stats.h
+++ /dev/null
@@ -1,173 +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_STATISTICS_WINDOW_STATS_H
-#define GRPC_INTERNAL_CORE_STATISTICS_WINDOW_STATS_H
-
-#include <grpc/support/time.h>
-
-/* Keep rolling sums of a user-defined statistic (containing a number of
-   measurements) over a a number of time intervals ("windows"). For example,
-   you can use a window_stats object to answer questions such as
-   "Approximately how many RPCs/s did I receive over the past minute, and
-   approximately how many bytes did I send out over that period?".
-
-   The type of data to record, and the time intervals to keep are specified
-   when creating the object via a call to census_window_stats_create().
-
-   A window's interval is divided into one or more "buckets"; the interval
-   must be divisible by the number of buckets. Internally, these buckets
-   control the granularity of window_stats' measurements. Increasing the
-   number of buckets lets the object respond more quickly to changes in the
-   overall rate of data added into the object, at the cost of additional
-   memory usage.
-
-   Here's some code which keeps one minute/hour measurements for two values
-   (latency in seconds and bytes transferred), with each interval divided into
-   4 buckets.
-
-    typedef struct my_stat {
-      double latency;
-      int bytes;
-    } my_stat;
-
-    void add_my_stat(void* base, const void* addme) {
-      my_stat* b = (my_stat*)base;
-      const my_stat* a = (const my_stat*)addme;
-      b->latency += a->latency;
-      b->bytes += a->bytes;
-    }
-
-    void add_proportion_my_stat(double p, void* base, const void* addme) {
-      (my_stat*)result->latency += p * (const my_stat*)base->latency;
-      (my_stat*)result->bytes += p * (const my_stat*)base->bytes;
-    }
-
-    #define kNumIntervals 2
-    #define kMinInterval 0
-    #define kHourInterval 1
-    #define kNumBuckets 4
-
-    const struct census_window_stats_stat_info kMyStatInfo
-        = { sizeof(my_stat), NULL, add_my_stat, add_proportion_my_stat };
-    gpr_timespec intervals[kNumIntervals] = {{60, 0}, {3600, 0}};
-    my_stat stat;
-    my_stat sums[kNumIntervals];
-    census_window_stats_sums result[kNumIntervals];
-    struct census_window_stats* stats
-        = census_window_stats_create(kNumIntervals, intervals, kNumBuckets,
-                                     &kMyStatInfo);
-    // Record a new event, taking 15.3ms, transferring 1784 bytes.
-    stat.latency = 0.153;
-    stat.bytes = 1784;
-    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(GPR_CLOCK_REALTIME), result);
-    printf("%d events/min, average time %gs, average bytes %g\n",
-           result[kMinInterval].count,
-           (my_stat*)result[kMinInterval].statistic->latency /
-             result[kMinInterval].count,
-           (my_stat*)result[kMinInterval].statistic->bytes /
-             result[kMinInterval].count
-          );
-    printf("%d events/hr, average time %gs, average bytes %g\n",
-           result[kHourInterval].count,
-           (my_stat*)result[kHourInterval].statistic->latency /
-             result[kHourInterval].count,
-           (my_stat*)result[kHourInterval].statistic->bytes /
-             result[kHourInterval].count
-          );
-*/
-
-/* Opaque structure for representing window_stats object */
-struct census_window_stats;
-
-/* Information provided by API user on the information they want to record */
-typedef struct census_window_stats_stat_info {
-  /* Number of bytes in user-defined object. */
-  size_t stat_size;
-  /* Function to initialize a user-defined statistics object. If this is set
-   * to NULL, then the object will be zero-initialized. */
-  void (*stat_initialize)(void *stat);
-  /* Function to add one user-defined statistics object ('addme') to 'base' */
-  void (*stat_add)(void *base, const void *addme);
-  /* As for previous function, but only add a proportion 'p'. This API will
-     currently only use 'p' values in the range [0,1], but other values are
-     possible in the future, and should be supported. */
-  void (*stat_add_proportion)(double p, void *base, const void *addme);
-} census_window_stats_stat_info;
-
-/* Create a new window_stats object. 'nintervals' is the number of
-   'intervals', and must be >=1. 'granularity' is the number of buckets, with
-   a larger number using more memory, but providing greater accuracy of
-   results. 'granularity should be > 2. We also require that each interval be
-   at least 10 * 'granularity' nanoseconds in size. 'stat_info' contains
-   information about the statistic to be gathered. Intervals greater than ~192
-   years will be treated as essentially infinite in size. This function will
-   GPR_ASSERT() if the object cannot be created or any of the parameters have
-   invalid values. This function is thread-safe. */
-struct census_window_stats *census_window_stats_create(
-    int nintervals, const gpr_timespec intervals[], int granularity,
-    const census_window_stats_stat_info *stat_info);
-
-/* Add a new measurement (in 'stat_value'), as of a given time ('when').
-   This function is thread-compatible. */
-void census_window_stats_add(struct census_window_stats *wstats,
-                             const gpr_timespec when, const void *stat_value);
-
-/* Structure used to record a single intervals sum for a given statistic */
-typedef struct census_window_stats_sum {
-  /* Total count of samples. Note that because some internal interpolation
-     is performed, the count of samples returned for each interval may not be an
-     integral value. */
-  double count;
-  /* Sum for statistic */
-  void *statistic;
-} census_window_stats_sums;
-
-/* Retrieve a set of all values stored in a window_stats object 'wstats'. The
-   number of 'sums' MUST be the same as the number 'nintervals' used in
-   census_window_stats_create(). This function is thread-compatible. */
-void census_window_stats_get_sums(const struct census_window_stats *wstats,
-                                  const gpr_timespec when,
-                                  struct census_window_stats_sum sums[]);
-
-/* Destroy a window_stats object. Once this function has been called, the
-   object will no longer be usable from any of the above functions (and
-   calling them will most likely result in a NULL-pointer dereference or
-   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 */
diff --git a/src/core/support/alloc.c b/src/core/support/alloc.c
deleted file mode 100644
index 0a064b2..0000000
--- a/src/core/support/alloc.c
+++ /dev/null
@@ -1,90 +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/support/alloc.h>
-
-#include <stdlib.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include "src/core/profiling/timers.h"
-
-static gpr_allocation_functions g_alloc_functions = {malloc, realloc, free};
-
-gpr_allocation_functions gpr_get_allocation_functions() {
-  return g_alloc_functions;
-}
-
-void gpr_set_allocation_functions(gpr_allocation_functions functions) {
-  GPR_ASSERT(functions.malloc_fn != NULL);
-  GPR_ASSERT(functions.realloc_fn != NULL);
-  GPR_ASSERT(functions.free_fn != NULL);
-  g_alloc_functions = functions;
-}
-
-void *gpr_malloc(size_t size) {
-  void *p;
-  GPR_TIMER_BEGIN("gpr_malloc", 0);
-  p = g_alloc_functions.malloc_fn(size);
-  if (!p) {
-    abort();
-  }
-  GPR_TIMER_END("gpr_malloc", 0);
-  return p;
-}
-
-void gpr_free(void *p) {
-  GPR_TIMER_BEGIN("gpr_free", 0);
-  g_alloc_functions.free_fn(p);
-  GPR_TIMER_END("gpr_free", 0);
-}
-
-void *gpr_realloc(void *p, size_t size) {
-  GPR_TIMER_BEGIN("gpr_realloc", 0);
-  p = g_alloc_functions.realloc_fn(p, size);
-  if (!p) {
-    abort();
-  }
-  GPR_TIMER_END("gpr_realloc", 0);
-  return p;
-}
-
-void *gpr_malloc_aligned(size_t size, size_t alignment_log) {
-  size_t alignment = ((size_t)1) << alignment_log;
-  size_t extra = alignment - 1 + sizeof(void *);
-  void *p = gpr_malloc(size + extra);
-  void **ret = (void **)(((uintptr_t)p + extra) & ~(alignment - 1));
-  ret[-1] = p;
-  return (void *)ret;
-}
-
-void gpr_free_aligned(void *ptr) { free(((void **)ptr)[-1]); }
diff --git a/src/core/support/block_annotate.h b/src/core/support/block_annotate.h
deleted file mode 100644
index 3cd8eee..0000000
--- a/src/core/support/block_annotate.h
+++ /dev/null
@@ -1,48 +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_SUPPORT_BLOCK_ANNOTATE_H
-#define GRPC_INTERNAL_CORE_SUPPORT_BLOCK_ANNOTATE_H
-
-/* These annotations identify the beginning and end of regions where
-   the code may block for reasons other than synchronization functions.
-   These include poll, epoll, and getaddrinfo. */
-
-#define GRPC_SCHEDULING_START_BLOCKING_REGION \
-  do {                                        \
-  } while (0)
-#define GRPC_SCHEDULING_END_BLOCKING_REGION \
-  do {                                      \
-  } while (0)
-
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_BLOCK_ANNOTATE_H */
diff --git a/src/core/support/cmdline.c b/src/core/support/cmdline.c
deleted file mode 100644
index b517f30..0000000
--- a/src/core/support/cmdline.c
+++ /dev/null
@@ -1,347 +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/support/cmdline.h>
-
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-typedef enum { ARGTYPE_INT, ARGTYPE_BOOL, ARGTYPE_STRING } argtype;
-
-typedef struct arg {
-  const char *name;
-  const char *help;
-  argtype type;
-  void *value;
-  struct arg *next;
-} arg;
-
-struct gpr_cmdline {
-  const char *description;
-  arg *args;
-  const char *argv0;
-
-  const char *extra_arg_name;
-  const char *extra_arg_help;
-  void (*extra_arg)(void *user_data, const char *arg);
-  void *extra_arg_user_data;
-
-  int (*state)(gpr_cmdline *cl, char *arg);
-  arg *cur_arg;
-
-  int survive_failure;
-};
-
-static int normal_state(gpr_cmdline *cl, char *arg);
-
-gpr_cmdline *gpr_cmdline_create(const char *description) {
-  gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline));
-  memset(cl, 0, sizeof(gpr_cmdline));
-
-  cl->description = description;
-  cl->state = normal_state;
-
-  return cl;
-}
-
-void gpr_cmdline_set_survive_failure(gpr_cmdline *cl) {
-  cl->survive_failure = 1;
-}
-
-void gpr_cmdline_destroy(gpr_cmdline *cl) {
-  while (cl->args) {
-    arg *a = cl->args;
-    cl->args = a->next;
-    gpr_free(a);
-  }
-  gpr_free(cl);
-}
-
-static void add_arg(gpr_cmdline *cl, const char *name, const char *help,
-                    argtype type, void *value) {
-  arg *a;
-
-  for (a = cl->args; a; a = a->next) {
-    GPR_ASSERT(0 != strcmp(a->name, name));
-  }
-
-  a = gpr_malloc(sizeof(arg));
-  memset(a, 0, sizeof(arg));
-  a->name = name;
-  a->help = help;
-  a->type = type;
-  a->value = value;
-  a->next = cl->args;
-  cl->args = a;
-}
-
-void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name, const char *help,
-                         int *value) {
-  add_arg(cl, name, help, ARGTYPE_INT, value);
-}
-
-void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name, const char *help,
-                          int *value) {
-  add_arg(cl, name, help, ARGTYPE_BOOL, value);
-}
-
-void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help,
-                            char **value) {
-  add_arg(cl, name, help, ARGTYPE_STRING, value);
-}
-
-void gpr_cmdline_on_extra_arg(
-    gpr_cmdline *cl, const char *name, const char *help,
-    void (*on_extra_arg)(void *user_data, const char *arg), void *user_data) {
-  GPR_ASSERT(!cl->extra_arg);
-  GPR_ASSERT(on_extra_arg);
-
-  cl->extra_arg = on_extra_arg;
-  cl->extra_arg_user_data = user_data;
-  cl->extra_arg_name = name;
-  cl->extra_arg_help = help;
-}
-
-/* recursively descend argument list, adding the last element
-   to s first - so that arguments are added in the order they were
-   added to the list by api calls */
-static void add_args_to_usage(gpr_strvec *s, arg *a) {
-  char *tmp;
-
-  if (!a) return;
-  add_args_to_usage(s, a->next);
-
-  switch (a->type) {
-    case ARGTYPE_BOOL:
-      gpr_asprintf(&tmp, " [--%s|--no-%s]", a->name, a->name);
-      gpr_strvec_add(s, tmp);
-      break;
-    case ARGTYPE_STRING:
-      gpr_asprintf(&tmp, " [--%s=string]", a->name);
-      gpr_strvec_add(s, tmp);
-      break;
-    case ARGTYPE_INT:
-      gpr_asprintf(&tmp, " [--%s=int]", a->name);
-      gpr_strvec_add(s, tmp);
-      break;
-  }
-}
-
-char *gpr_cmdline_usage_string(gpr_cmdline *cl, const char *argv0) {
-  /* TODO(ctiller): make this prettier */
-  gpr_strvec s;
-  char *tmp;
-  const char *name = strrchr(argv0, '/');
-
-  if (name) {
-    name++;
-  } else {
-    name = argv0;
-  }
-
-  gpr_strvec_init(&s);
-
-  gpr_asprintf(&tmp, "Usage: %s", name);
-  gpr_strvec_add(&s, tmp);
-  add_args_to_usage(&s, cl->args);
-  if (cl->extra_arg) {
-    gpr_asprintf(&tmp, " [%s...]", cl->extra_arg_name);
-    gpr_strvec_add(&s, tmp);
-  }
-  gpr_strvec_add(&s, gpr_strdup("\n"));
-
-  tmp = gpr_strvec_flatten(&s, NULL);
-  gpr_strvec_destroy(&s);
-  return tmp;
-}
-
-static int print_usage_and_die(gpr_cmdline *cl) {
-  char *usage = gpr_cmdline_usage_string(cl, cl->argv0);
-  fprintf(stderr, "%s", usage);
-  gpr_free(usage);
-  if (!cl->survive_failure) {
-    exit(1);
-  }
-  return 0;
-}
-
-static int extra_state(gpr_cmdline *cl, char *str) {
-  if (!cl->extra_arg) {
-    return print_usage_and_die(cl);
-  }
-  cl->extra_arg(cl->extra_arg_user_data, str);
-  return 1;
-}
-
-static arg *find_arg(gpr_cmdline *cl, char *name) {
-  arg *a;
-
-  for (a = cl->args; a; a = a->next) {
-    if (0 == strcmp(a->name, name)) {
-      break;
-    }
-  }
-
-  if (!a) {
-    fprintf(stderr, "Unknown argument: %s\n", name);
-    return NULL;
-  }
-
-  return a;
-}
-
-static int value_state(gpr_cmdline *cl, char *str) {
-  long intval;
-  char *end;
-
-  GPR_ASSERT(cl->cur_arg);
-
-  switch (cl->cur_arg->type) {
-    case ARGTYPE_INT:
-      intval = strtol(str, &end, 0);
-      if (*end || intval < INT_MIN || intval > INT_MAX) {
-        fprintf(stderr, "expected integer, got '%s' for %s\n", str,
-                cl->cur_arg->name);
-        return print_usage_and_die(cl);
-      }
-      *(int *)cl->cur_arg->value = (int)intval;
-      break;
-    case ARGTYPE_BOOL:
-      if (0 == strcmp(str, "1") || 0 == strcmp(str, "true")) {
-        *(int *)cl->cur_arg->value = 1;
-      } else if (0 == strcmp(str, "0") || 0 == strcmp(str, "false")) {
-        *(int *)cl->cur_arg->value = 0;
-      } else {
-        fprintf(stderr, "expected boolean, got '%s' for %s\n", str,
-                cl->cur_arg->name);
-        return print_usage_and_die(cl);
-      }
-      break;
-    case ARGTYPE_STRING:
-      *(char **)cl->cur_arg->value = str;
-      break;
-  }
-
-  cl->state = normal_state;
-  return 1;
-}
-
-static int normal_state(gpr_cmdline *cl, char *str) {
-  char *eq = NULL;
-  char *tmp = NULL;
-  char *arg_name = NULL;
-  int r = 1;
-
-  if (0 == strcmp(str, "-help") || 0 == strcmp(str, "--help") ||
-      0 == strcmp(str, "-h")) {
-    return print_usage_and_die(cl);
-  }
-
-  cl->cur_arg = NULL;
-
-  if (str[0] == '-') {
-    if (str[1] == '-') {
-      if (str[2] == 0) {
-        /* handle '--' to move to just extra args */
-        cl->state = extra_state;
-        return 1;
-      }
-      str += 2;
-    } else {
-      str += 1;
-    }
-    /* first byte of str is now past the leading '-' or '--' */
-    if (str[0] == 'n' && str[1] == 'o' && str[2] == '-') {
-      /* str is of the form '--no-foo' - it's a flag disable */
-      str += 3;
-      cl->cur_arg = find_arg(cl, str);
-      if (cl->cur_arg == NULL) {
-        return print_usage_and_die(cl);
-      }
-      if (cl->cur_arg->type != ARGTYPE_BOOL) {
-        fprintf(stderr, "%s is not a flag argument\n", str);
-        return print_usage_and_die(cl);
-      }
-      *(int *)cl->cur_arg->value = 0;
-      return 1; /* early out */
-    }
-    eq = strchr(str, '=');
-    if (eq != NULL) {
-      /* copy the string into a temp buffer and extract the name */
-      tmp = arg_name = gpr_malloc((size_t)(eq - str + 1));
-      memcpy(arg_name, str, (size_t)(eq - str));
-      arg_name[eq - str] = 0;
-    } else {
-      arg_name = str;
-    }
-    cl->cur_arg = find_arg(cl, arg_name);
-    if (cl->cur_arg == NULL) {
-      return print_usage_and_die(cl);
-    }
-    if (eq != NULL) {
-      /* str was of the type --foo=value, parse the value */
-      r = value_state(cl, eq + 1);
-    } else if (cl->cur_arg->type != ARGTYPE_BOOL) {
-      /* flag types don't have a '--foo value' variant, other types do */
-      cl->state = value_state;
-    } else {
-      /* flag parameter: just set the value */
-      *(int *)cl->cur_arg->value = 1;
-    }
-  } else {
-    r = extra_state(cl, str);
-  }
-
-  gpr_free(tmp);
-  return r;
-}
-
-int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) {
-  int i;
-
-  GPR_ASSERT(argc >= 1);
-  cl->argv0 = argv[0];
-
-  for (i = 1; i < argc; i++) {
-    if (!cl->state(cl, argv[i])) {
-      return 0;
-    }
-  }
-  return 1;
-}
diff --git a/src/core/support/cpu_iphone.c b/src/core/support/cpu_iphone.c
deleted file mode 100644
index 82b49b4..0000000
--- a/src/core/support/cpu_iphone.c
+++ /dev/null
@@ -1,49 +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/support/port_platform.h>
-
-#ifdef GPR_CPU_IPHONE
-
-/* Probably 2 instead of 1, but see comment on gpr_cpu_current_cpu. */
-unsigned gpr_cpu_num_cores(void) { return 1; }
-
-/* Most code that's using this is using it to shard across work queues. So
-   unless profiling shows it's a problem or there appears a way to detect the
-   currently running CPU core, let's have it shard the default way.
-   Note that the interface in cpu.h lets gpr_cpu_num_cores return 0, but doing
-   it makes it impossible for gpr_cpu_current_cpu to satisfy its stated range,
-   and some code might be relying on it. */
-unsigned gpr_cpu_current_cpu(void) { return 0; }
-
-#endif /* GPR_CPU_IPHONE */
diff --git a/src/core/support/cpu_linux.c b/src/core/support/cpu_linux.c
deleted file mode 100644
index 7af6a8f..0000000
--- a/src/core/support/cpu_linux.c
+++ /dev/null
@@ -1,78 +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 _GNU_SOURCE
-#define _GNU_SOURCE
-#endif /* _GNU_SOURCE */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_CPU_LINUX
-
-#include <sched.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <grpc/support/cpu.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-
-static int ncpus = 0;
-
-static void init_num_cpus() {
-  /* 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;
-  }
-}
-
-unsigned gpr_cpu_num_cores(void) {
-  static gpr_once once = GPR_ONCE_INIT;
-  gpr_once_init(&once, init_num_cpus);
-  return (unsigned)ncpus;
-}
-
-unsigned gpr_cpu_current_cpu(void) {
-  int cpu = sched_getcpu();
-  if (cpu < 0) {
-    gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno));
-    return 0;
-  }
-  return (unsigned)cpu;
-}
-
-#endif /* GPR_CPU_LINUX */
diff --git a/src/core/support/cpu_posix.c b/src/core/support/cpu_posix.c
deleted file mode 100644
index 8f01c28..0000000
--- a/src/core/support/cpu_posix.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_CPU_POSIX
-
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-
-static __thread char magic_thread_local;
-
-static long ncpus = 0;
-
-static void init_ncpus() {
-  ncpus = sysconf(_SC_NPROCESSORS_ONLN);
-  if (ncpus < 1 || ncpus > INT32_MAX) {
-    gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1");
-    ncpus = 1;
-  }
-}
-
-unsigned gpr_cpu_num_cores(void) {
-  static gpr_once once = GPR_ONCE_INIT;
-  gpr_once_init(&once, init_ncpus);
-  return (unsigned)ncpus;
-}
-
-/* This is a cheap, but good enough, pointer hash for sharding things: */
-static size_t shard_ptr(const void *info) {
-  size_t x = (size_t)info;
-  return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) % gpr_cpu_num_cores();
-}
-
-unsigned gpr_cpu_current_cpu(void) {
-  /* NOTE: there's no way I know to return the actual cpu index portably...
-     most code that's using this is using it to shard across work queues though,
-     so here we use thread identity instead to achieve a similar though not
-     identical effect */
-  return (unsigned)shard_ptr(&magic_thread_local);
-}
-
-#endif /* GPR_CPU_POSIX */
diff --git a/src/core/support/cpu_windows.c b/src/core/support/cpu_windows.c
deleted file mode 100644
index ce32eb0..0000000
--- a/src/core/support/cpu_windows.c
+++ /dev/null
@@ -1,47 +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/support/port_platform.h>
-
-#ifdef GPR_WIN32
-#include <grpc/support/log.h>
-
-unsigned gpr_cpu_num_cores(void) {
-  SYSTEM_INFO si;
-  GetSystemInfo(&si);
-  return si.dwNumberOfProcessors;
-}
-
-unsigned gpr_cpu_current_cpu(void) { return GetCurrentProcessorNumber(); }
-
-#endif /* GPR_WIN32 */
diff --git a/src/core/support/env.h b/src/core/support/env.h
deleted file mode 100644
index 24172d8..0000000
--- a/src/core/support/env.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_SUPPORT_ENV_H
-#define GRPC_INTERNAL_CORE_SUPPORT_ENV_H
-
-#include <stdio.h>
-
-#include <grpc/support/slice.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Env utility functions */
-
-/* Gets the environment variable value with the specified name.
-   Returns a newly allocated string. It is the responsability of the caller to
-   gpr_free the return value if not NULL (which means that the environment
-   variable exists). */
-char *gpr_getenv(const char *name);
-
-/* Sets the the environment with the specified name to the specified value. */
-void gpr_setenv(const char *name, const char *value);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_ENV_H */
diff --git a/src/core/support/env_linux.c b/src/core/support/env_linux.c
deleted file mode 100644
index fe51f84..0000000
--- a/src/core/support/env_linux.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* for secure_getenv. */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_LINUX_ENV
-
-#include "src/core/support/env.h"
-
-#include <dlfcn.h>
-#include <features.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/support/string.h"
-
-char *gpr_getenv(const char *name) {
-#if defined(GPR_BACKWARDS_COMPATIBILITY_MODE)
-  typedef char *(*getenv_type)(const char *);
-  static getenv_type getenv_func = NULL;
-  /* Check to see which getenv variant is supported (go from most
-   * to least secure) */
-  const char *names[] = {"secure_getenv", "__secure_getenv", "getenv"};
-  for (size_t i = 0; getenv_func == NULL && i < GPR_ARRAY_SIZE(names); i++) {
-    getenv_func = (getenv_type)dlsym(RTLD_DEFAULT, names[i]);
-    if (getenv_func != NULL && strstr(names[i], "secure") == NULL) {
-      gpr_log(GPR_DEBUG,
-              "Warning: insecure environment read function '%s' used",
-              names[i]);
-    }
-  }
-  char *result = getenv_func(name);
-  return result == NULL ? result : gpr_strdup(result);
-#elif __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17)
-  char *result = secure_getenv(name);
-  return result == NULL ? result : gpr_strdup(result);
-#else
-  gpr_log(GPR_DEBUG, "Warning: insecure environment read function '%s' used",
-          "getenv");
-  char *result = getenv(name);
-  return result == NULL ? result : gpr_strdup(result);
-#endif
-}
-
-void gpr_setenv(const char *name, const char *value) {
-  int res = setenv(name, value, 1);
-  GPR_ASSERT(res == 0);
-}
-
-#endif /* GPR_LINUX_ENV */
diff --git a/src/core/support/env_posix.c b/src/core/support/env_posix.c
deleted file mode 100644
index 1dd2af5..0000000
--- a/src/core/support/env_posix.c
+++ /dev/null
@@ -1,57 +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/support/port_platform.h>
-
-#ifdef GPR_POSIX_ENV
-
-#include "src/core/support/env.h"
-
-#include <stdlib.h>
-
-#include <grpc/support/log.h>
-
-#include "src/core/support/string.h"
-#include <grpc/support/string_util.h>
-
-char *gpr_getenv(const char *name) {
-  char *result = getenv(name);
-  return result == NULL ? result : gpr_strdup(result);
-}
-
-void gpr_setenv(const char *name, const char *value) {
-  int res = setenv(name, value, 1);
-  GPR_ASSERT(res == 0);
-}
-
-#endif /* GPR_POSIX_ENV */
diff --git a/src/core/support/env_win32.c b/src/core/support/env_win32.c
deleted file mode 100644
index 1025828..0000000
--- a/src/core/support/env_win32.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WIN32
-
-#include "src/core/support/env.h"
-#include "src/core/support/string.h"
-
-#ifdef __MINGW32__
-errno_t getenv_s(size_t *size_needed, char *buffer, size_t size,
-                 const char *varname);
-#else
-#include <stdlib.h>
-#endif
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-char *gpr_getenv(const char *name) {
-  size_t size;
-  char *result = NULL;
-  errno_t err;
-
-  err = getenv_s(&size, NULL, 0, name);
-  if (err || (size == 0)) return NULL;
-  result = gpr_malloc(size);
-  err = getenv_s(&size, result, size, name);
-  if (err) {
-    gpr_free(result);
-    return NULL;
-  }
-  return result;
-}
-
-void gpr_setenv(const char *name, const char *value) {
-  errno_t res = _putenv_s(name, value);
-  GPR_ASSERT(res == 0);
-}
-
-#endif /* GPR_WIN32 */
diff --git a/src/core/support/histogram.c b/src/core/support/histogram.c
deleted file mode 100644
index 20ed2b1..0000000
--- a/src/core/support/histogram.c
+++ /dev/null
@@ -1,244 +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/support/histogram.h>
-
-#include <math.h>
-#include <stddef.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-/* Histograms are stored with exponentially increasing bucket sizes.
-   The first bucket is [0, m) where m = 1 + resolution
-   Bucket n (n>=1) contains [m**n, m**(n+1))
-   There are sufficient buckets to reach max_bucket_start */
-
-struct gpr_histogram {
-  /* Sum of all values seen so far */
-  double sum;
-  /* Sum of squares of all values seen so far */
-  double sum_of_squares;
-  /* number of values seen so far */
-  double count;
-  /* m in the description */
-  double multiplier;
-  double one_on_log_multiplier;
-  /* minimum value seen */
-  double min_seen;
-  /* maximum value seen */
-  double max_seen;
-  /* maximum representable value */
-  double max_possible;
-  /* number of buckets */
-  size_t num_buckets;
-  /* the buckets themselves */
-  uint32_t *buckets;
-};
-
-/* determine a bucket index given a value - does no bounds checking */
-static size_t bucket_for_unchecked(gpr_histogram *h, double x) {
-  return (size_t)(log(x) * h->one_on_log_multiplier);
-}
-
-/* bounds checked version of the above */
-static size_t bucket_for(gpr_histogram *h, double x) {
-  size_t bucket = bucket_for_unchecked(h, GPR_CLAMP(x, 1.0, h->max_possible));
-  GPR_ASSERT(bucket < h->num_buckets);
-  return bucket;
-}
-
-/* at what value does a bucket start? */
-static double bucket_start(gpr_histogram *h, double x) {
-  return pow(h->multiplier, x);
-}
-
-gpr_histogram *gpr_histogram_create(double resolution,
-                                    double max_bucket_start) {
-  gpr_histogram *h = gpr_malloc(sizeof(gpr_histogram));
-  GPR_ASSERT(resolution > 0.0);
-  GPR_ASSERT(max_bucket_start > resolution);
-  h->sum = 0.0;
-  h->sum_of_squares = 0.0;
-  h->multiplier = 1.0 + resolution;
-  h->one_on_log_multiplier = 1.0 / log(1.0 + resolution);
-  h->max_possible = max_bucket_start;
-  h->count = 0.0;
-  h->min_seen = max_bucket_start;
-  h->max_seen = 0.0;
-  h->num_buckets = bucket_for_unchecked(h, max_bucket_start) + 1;
-  GPR_ASSERT(h->num_buckets > 1);
-  GPR_ASSERT(h->num_buckets < 100000000);
-  h->buckets = gpr_malloc(sizeof(uint32_t) * h->num_buckets);
-  memset(h->buckets, 0, sizeof(uint32_t) * h->num_buckets);
-  return h;
-}
-
-void gpr_histogram_destroy(gpr_histogram *h) {
-  gpr_free(h->buckets);
-  gpr_free(h);
-}
-
-void gpr_histogram_add(gpr_histogram *h, double x) {
-  h->sum += x;
-  h->sum_of_squares += x * x;
-  h->count++;
-  if (x < h->min_seen) {
-    h->min_seen = x;
-  }
-  if (x > h->max_seen) {
-    h->max_seen = x;
-  }
-  h->buckets[bucket_for(h, x)]++;
-}
-
-int gpr_histogram_merge(gpr_histogram *dst, const gpr_histogram *src) {
-  if ((dst->num_buckets != src->num_buckets) ||
-      (dst->multiplier != src->multiplier)) {
-    /* Fail because these histograms don't match */
-    return 0;
-  }
-  gpr_histogram_merge_contents(dst, src->buckets, src->num_buckets,
-                               src->min_seen, src->max_seen, src->sum,
-                               src->sum_of_squares, src->count);
-  return 1;
-}
-
-void gpr_histogram_merge_contents(gpr_histogram *dst, const uint32_t *data,
-                                  size_t data_count, double min_seen,
-                                  double max_seen, double sum,
-                                  double sum_of_squares, double count) {
-  size_t i;
-  GPR_ASSERT(dst->num_buckets == data_count);
-  dst->sum += sum;
-  dst->sum_of_squares += sum_of_squares;
-  dst->count += count;
-  if (min_seen < dst->min_seen) {
-    dst->min_seen = min_seen;
-  }
-  if (max_seen > dst->max_seen) {
-    dst->max_seen = max_seen;
-  }
-  for (i = 0; i < dst->num_buckets; i++) {
-    dst->buckets[i] += data[i];
-  }
-}
-
-static double threshold_for_count_below(gpr_histogram *h, double count_below) {
-  double count_so_far;
-  double lower_bound;
-  double upper_bound;
-  size_t lower_idx;
-  size_t upper_idx;
-
-  if (h->count == 0) {
-    return 0.0;
-  }
-
-  if (count_below <= 0) {
-    return h->min_seen;
-  }
-  if (count_below >= h->count) {
-    return h->max_seen;
-  }
-
-  /* find the lowest bucket that gets us above count_below */
-  count_so_far = 0.0;
-  for (lower_idx = 0; lower_idx < h->num_buckets; lower_idx++) {
-    count_so_far += h->buckets[lower_idx];
-    if (count_so_far >= count_below) {
-      break;
-    }
-  }
-  if (count_so_far == count_below) {
-    /* this bucket hits the threshold exactly... we should be midway through
-       any run of zero values following the bucket */
-    for (upper_idx = lower_idx + 1; upper_idx < h->num_buckets; upper_idx++) {
-      if (h->buckets[upper_idx]) {
-        break;
-      }
-    }
-    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, (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],
-                     h->min_seen, h->max_seen);
-  }
-}
-
-double gpr_histogram_percentile(gpr_histogram *h, double percentile) {
-  return threshold_for_count_below(h, h->count * percentile / 100.0);
-}
-
-double gpr_histogram_mean(gpr_histogram *h) {
-  GPR_ASSERT(h->count != 0);
-  return h->sum / h->count;
-}
-
-double gpr_histogram_stddev(gpr_histogram *h) {
-  return sqrt(gpr_histogram_variance(h));
-}
-
-double gpr_histogram_variance(gpr_histogram *h) {
-  if (h->count == 0) return 0.0;
-  return (h->sum_of_squares * h->count - h->sum * h->sum) /
-         (h->count * h->count);
-}
-
-double gpr_histogram_maximum(gpr_histogram *h) { return h->max_seen; }
-
-double gpr_histogram_minimum(gpr_histogram *h) { return h->min_seen; }
-
-double gpr_histogram_count(gpr_histogram *h) { return h->count; }
-
-double gpr_histogram_sum(gpr_histogram *h) { return h->sum; }
-
-double gpr_histogram_sum_of_squares(gpr_histogram *h) {
-  return h->sum_of_squares;
-}
-
-const uint32_t *gpr_histogram_get_contents(gpr_histogram *h, size_t *size) {
-  *size = h->num_buckets;
-  return h->buckets;
-}
diff --git a/src/core/support/host_port.c b/src/core/support/host_port.c
deleted file mode 100644
index 23f65b1..0000000
--- a/src/core/support/host_port.c
+++ /dev/null
@@ -1,110 +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/support/host_port.h>
-
-#include <string.h>
-
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-int gpr_join_host_port(char **out, const char *host, int port) {
-  if (host[0] != '[' && strchr(host, ':') != NULL) {
-    /* IPv6 literals must be enclosed in brackets. */
-    return gpr_asprintf(out, "[%s]:%d", host, port);
-  } else {
-    /* Ordinary non-bracketed host:port. */
-    return gpr_asprintf(out, "%s:%d", host, port);
-  }
-}
-
-int gpr_split_host_port(const char *name, char **host, char **port) {
-  const char *host_start;
-  size_t host_len;
-  const char *port_start;
-
-  *host = NULL;
-  *port = NULL;
-
-  if (name[0] == '[') {
-    /* Parse a bracketed host, typically an IPv6 literal. */
-    const char *rbracket = strchr(name, ']');
-    if (rbracket == NULL) {
-      /* Unmatched [ */
-      return 0;
-    }
-    if (rbracket[1] == '\0') {
-      /* ]<end> */
-      port_start = NULL;
-    } else if (rbracket[1] == ':') {
-      /* ]:<port?> */
-      port_start = rbracket + 2;
-    } else {
-      /* ]<invalid> */
-      return 0;
-    }
-    host_start = name + 1;
-    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. */
-      return 0;
-    }
-  } else {
-    const char *colon = strchr(name, ':');
-    if (colon != NULL && strchr(colon + 1, ':') == NULL) {
-      /* Exactly 1 colon.  Split into host:port. */
-      host_start = name;
-      host_len = (size_t)(colon - name);
-      port_start = colon + 1;
-    } else {
-      /* 0 or 2+ colons.  Bare hostname or IPv6 litearal. */
-      host_start = name;
-      host_len = strlen(name);
-      port_start = NULL;
-    }
-  }
-
-  /* Allocate return values. */
-  *host = gpr_malloc(host_len + 1);
-  memcpy(*host, host_start, host_len);
-  (*host)[host_len] = '\0';
-
-  if (port_start != NULL) {
-    *port = gpr_strdup(port_start);
-  }
-
-  return 1;
-}
diff --git a/src/core/support/load_file.c b/src/core/support/load_file.c
deleted file mode 100644
index 650bd62..0000000
--- a/src/core/support/load_file.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/support/load_file.h"
-
-#include <errno.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/support/block_annotate.h"
-#include "src/core/support/string.h"
-
-gpr_slice gpr_load_file(const char *filename, int add_null_terminator,
-                        int *success) {
-  unsigned char *contents = NULL;
-  size_t contents_size = 0;
-  char *error_msg = NULL;
-  gpr_slice result = gpr_empty_slice();
-  FILE *file;
-  size_t bytes_read = 0;
-
-  GRPC_SCHEDULING_START_BLOCKING_REGION;
-  file = fopen(filename, "rb");
-  if (file == NULL) {
-    gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename,
-                 strerror(errno));
-    GPR_ASSERT(error_msg != NULL);
-    goto end;
-  }
-  fseek(file, 0, SEEK_END);
-  /* 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);
-  if (bytes_read < contents_size) {
-    GPR_ASSERT(ferror(file));
-    gpr_asprintf(&error_msg, "Error %s occured while reading file %s.",
-                 strerror(errno), filename);
-    GPR_ASSERT(error_msg != NULL);
-    goto end;
-  }
-  if (success != NULL) *success = 1;
-  if (add_null_terminator) {
-    contents[contents_size++] = 0;
-  }
-  result = gpr_slice_new(contents, contents_size, gpr_free);
-
-end:
-  if (error_msg != NULL) {
-    gpr_log(GPR_ERROR, "%s", error_msg);
-    gpr_free(error_msg);
-    if (success != NULL) *success = 0;
-  }
-  if (file != NULL) fclose(file);
-  GRPC_SCHEDULING_END_BLOCKING_REGION;
-  return result;
-}
diff --git a/src/core/support/load_file.h b/src/core/support/load_file.h
deleted file mode 100644
index 746319a..0000000
--- a/src/core/support/load_file.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_SUPPORT_LOAD_FILE_H
-#define GRPC_INTERNAL_CORE_SUPPORT_LOAD_FILE_H
-
-#include <stdio.h>
-
-#include <grpc/support/slice.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Loads the content of a file into a slice. add_null_terminator will add
-   a NULL terminator if non-zero. The success parameter, if not NULL,
-   will be set to 1 in case of success and 0 in case of failure. */
-gpr_slice gpr_load_file(const char *filename, int add_null_terminator,
-                        int *success);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_LOAD_FILE_H */
diff --git a/src/core/support/log.c b/src/core/support/log.c
deleted file mode 100644
index 04156a5..0000000
--- a/src/core/support/log.c
+++ /dev/null
@@ -1,66 +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/support/log.h>
-#include <grpc/support/port_platform.h>
-
-#include <stdio.h>
-#include <string.h>
-
-extern void gpr_default_log(gpr_log_func_args *args);
-static gpr_log_func g_log_func = gpr_default_log;
-
-const char *gpr_log_severity_string(gpr_log_severity severity) {
-  switch (severity) {
-    case GPR_LOG_SEVERITY_DEBUG:
-      return "D";
-    case GPR_LOG_SEVERITY_INFO:
-      return "I";
-    case GPR_LOG_SEVERITY_ERROR:
-      return "E";
-  }
-  GPR_UNREACHABLE_CODE(return "UNKNOWN");
-}
-
-void gpr_log_message(const char *file, int line, gpr_log_severity severity,
-                     const char *message) {
-  gpr_log_func_args lfargs;
-  memset(&lfargs, 0, sizeof(lfargs));
-  lfargs.file = file;
-  lfargs.line = line;
-  lfargs.severity = severity;
-  lfargs.message = message;
-  g_log_func(&lfargs);
-}
-
-void gpr_set_log_function(gpr_log_func f) { g_log_func = f; }
diff --git a/src/core/support/log_android.c b/src/core/support/log_android.c
deleted file mode 100644
index 5d0c7d8..0000000
--- a/src/core/support/log_android.c
+++ /dev/null
@@ -1,87 +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/support/port_platform.h>
-
-#ifdef GPR_ANDROID
-
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <android/log.h>
-
-static android_LogPriority severity_to_log_priority(gpr_log_severity severity) {
-  switch (severity) {
-    case GPR_LOG_SEVERITY_DEBUG:
-      return ANDROID_LOG_DEBUG;
-    case GPR_LOG_SEVERITY_INFO:
-      return ANDROID_LOG_INFO;
-    case GPR_LOG_SEVERITY_ERROR:
-      return ANDROID_LOG_ERROR;
-  }
-  return ANDROID_LOG_DEFAULT;
-}
-
-void gpr_log(const char *file, int line, gpr_log_severity severity,
-             const char *format, ...) {
-  char *message = NULL;
-  va_list args;
-  va_start(args, format);
-  vasprintf(&message, format, args);
-  va_end(args);
-  gpr_log_message(file, line, severity, message);
-  free(message);
-}
-
-void gpr_default_log(gpr_log_func_args *args) {
-  char *final_slash;
-  const char *display_file;
-  char *output = NULL;
-
-  final_slash = strrchr(args->file, '/');
-  if (final_slash == NULL)
-    display_file = args->file;
-  else
-    display_file = final_slash + 1;
-
-  asprintf(&output, "%s:%d] %s", display_file, args->line, args->message);
-
-  __android_log_write(severity_to_log_priority(args->severity), "GRPC", output);
-
-  /* allocated by asprintf => use free, not gpr_free */
-  free(output);
-}
-
-#endif /* GPR_ANDROID */
diff --git a/src/core/support/log_linux.c b/src/core/support/log_linux.c
deleted file mode 100644
index d66b7a3..0000000
--- a/src/core/support/log_linux.c
+++ /dev/null
@@ -1,105 +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 _POSIX_SOURCE
-#define _POSIX_SOURCE
-#endif
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <grpc/support/port_platform.h>
-
-#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>
-#include <string.h>
-#include <time.h>
-#include <linux/unistd.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-
-static long gettid(void) { return syscall(__NR_gettid); }
-
-void gpr_log(const char *file, int line, gpr_log_severity severity,
-             const char *format, ...) {
-  char *message = NULL;
-  va_list args;
-  va_start(args, format);
-  if (vasprintf(&message, format, args) == -1) {
-    va_end(args);
-    return;
-  }
-  va_end(args);
-  gpr_log_message(file, line, severity, message);
-  free(message);
-}
-
-void gpr_default_log(gpr_log_func_args *args) {
-  char *final_slash;
-  char *prefix;
-  const char *display_file;
-  char time_buffer[64];
-  time_t timer;
-  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
-  struct tm tm;
-
-  timer = (time_t)now.tv_sec;
-  final_slash = strrchr(args->file, '/');
-  if (final_slash == NULL)
-    display_file = args->file;
-  else
-    display_file = final_slash + 1;
-
-  if (!localtime_r(&timer, &tm)) {
-    strcpy(time_buffer, "error:localtime");
-  } else if (0 ==
-             strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
-    strcpy(time_buffer, "error:strftime");
-  }
-
-  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);
-
-  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
deleted file mode 100644
index 3ff171f..0000000
--- a/src/core/support/log_posix.c
+++ /dev/null
@@ -1,102 +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/support/port_platform.h>
-
-#if defined(GPR_POSIX_LOG)
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-#include <time.h>
-#include <pthread.h>
-
-static intptr_t gettid(void) { return (intptr_t)pthread_self(); }
-
-void gpr_log(const char *file, int line, gpr_log_severity severity,
-             const char *format, ...) {
-  char buf[64];
-  char *allocated = NULL;
-  char *message = NULL;
-  int ret;
-  va_list args;
-  va_start(args, format);
-  ret = vsnprintf(buf, sizeof(buf), format, args);
-  va_end(args);
-  if (ret < 0) {
-    message = NULL;
-  } else if ((size_t)ret <= sizeof(buf) - 1) {
-    message = buf;
-  } else {
-    message = allocated = gpr_malloc((size_t)ret + 1);
-    va_start(args, format);
-    vsnprintf(message, (size_t)(ret + 1), format, args);
-    va_end(args);
-  }
-  gpr_log_message(file, line, severity, message);
-  gpr_free(allocated);
-}
-
-void gpr_default_log(gpr_log_func_args *args) {
-  char *final_slash;
-  const char *display_file;
-  char time_buffer[64];
-  time_t timer;
-  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
-  struct tm tm;
-
-  timer = (time_t)now.tv_sec;
-  final_slash = strrchr(args->file, '/');
-  if (final_slash == NULL)
-    display_file = args->file;
-  else
-    display_file = final_slash + 1;
-
-  if (!localtime_r(&timer, &tm)) {
-    strcpy(time_buffer, "error:localtime");
-  } else if (0 ==
-             strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
-    strcpy(time_buffer, "error:strftime");
-  }
-
-  fprintf(stderr, "%s%s.%09d %7tu %s:%d] %s\n",
-          gpr_log_severity_string(args->severity), time_buffer,
-          (int)(now.tv_nsec), gettid(), display_file, args->line,
-          args->message);
-}
-
-#endif /* defined(GPR_POSIX_LOG) */
diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c
deleted file mode 100644
index e18e667..0000000
--- a/src/core/support/log_win32.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WIN32
-
-#include <stdio.h>
-#include <stdarg.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log_win32.h>
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/support/string.h"
-#include "src/core/support/string_win32.h"
-
-void gpr_log(const char *file, int line, gpr_log_severity severity,
-             const char *format, ...) {
-  char *message = NULL;
-  va_list args;
-  int ret;
-
-  /* Determine the length. */
-  va_start(args, format);
-  ret = _vscprintf(format, args);
-  va_end(args);
-  if (ret < 0) {
-    message = NULL;
-  } else {
-    /* Allocate a new buffer, with space for the NUL terminator. */
-    size_t strp_buflen = (size_t)ret + 1;
-    message = gpr_malloc(strp_buflen);
-
-    /* Print to the buffer. */
-    va_start(args, format);
-    ret = vsnprintf_s(message, strp_buflen, _TRUNCATE, format, args);
-    va_end(args);
-    if ((size_t)ret != strp_buflen - 1) {
-      /* This should never happen. */
-      gpr_free(message);
-      message = NULL;
-    }
-  }
-
-  gpr_log_message(file, line, severity, message);
-  gpr_free(message);
-}
-
-/* Simple starter implementation */
-void gpr_default_log(gpr_log_func_args *args) {
-  char *final_slash;
-  const char *display_file;
-  char time_buffer[64];
-  time_t timer;
-  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
-  struct tm tm;
-
-  timer = (time_t)now.tv_sec;
-  final_slash = strrchr(args->file, '\\');
-  if (final_slash == NULL)
-    display_file = args->file;
-  else
-    display_file = final_slash + 1;
-
-  if (localtime_s(&tm, &timer)) {
-    strcpy(time_buffer, "error:localtime");
-  } else if (0 ==
-             strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
-    strcpy(time_buffer, "error:strftime");
-  }
-
-  fprintf(stderr, "%s%s.%09u %5lu %s:%d] %s\n",
-          gpr_log_severity_string(args->severity), time_buffer,
-          (int)(now.tv_nsec), GetCurrentThreadId(), display_file, args->line,
-          args->message);
-  fflush(stderr);
-}
-
-char *gpr_format_message(int messageid) {
-  LPTSTR tmessage;
-  char *message;
-  DWORD status = FormatMessage(
-      FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
-          FORMAT_MESSAGE_IGNORE_INSERTS,
-      NULL, (DWORD)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 */
diff --git a/src/core/support/murmur_hash.c b/src/core/support/murmur_hash.c
deleted file mode 100644
index a5261c0..0000000
--- a/src/core/support/murmur_hash.c
+++ /dev/null
@@ -1,96 +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/support/murmur_hash.h"
-
-#define ROTL32(x, r) ((x) << (r)) | ((x) >> (32 - (r)))
-
-#define FMIX32(h)    \
-  (h) ^= (h) >> 16;  \
-  (h) *= 0x85ebca6b; \
-  (h) ^= (h) >> 13;  \
-  (h) *= 0xc2b2ae35; \
-  (h) ^= (h) >> 16;
-
-/* Block read - if your platform needs to do endian-swapping or can only
-   handle aligned reads, do the conversion here */
-#define GETBLOCK32(p, i) (p)[(i)]
-
-uint32_t gpr_murmur_hash3(const void *key, size_t len, uint32_t seed) {
-  const uint8_t *data = (const uint8_t *)key;
-  const size_t nblocks = len / 4;
-  int i;
-
-  uint32_t h1 = seed;
-  uint32_t k1;
-
-  const uint32_t c1 = 0xcc9e2d51;
-  const uint32_t c2 = 0x1b873593;
-
-  const uint32_t *blocks = ((const uint32_t *)key) + nblocks;
-  const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
-
-  /* body */
-  for (i = -(int)nblocks; i; i++) {
-    k1 = GETBLOCK32(blocks, i);
-
-    k1 *= c1;
-    k1 = ROTL32(k1, 15);
-    k1 *= c2;
-
-    h1 ^= k1;
-    h1 = ROTL32(h1, 13);
-    h1 = h1 * 5 + 0xe6546b64;
-  }
-
-  k1 = 0;
-
-  /* tail */
-  switch (len & 3) {
-    case 3:
-      k1 ^= ((uint32_t)tail[2]) << 16;
-    case 2:
-      k1 ^= ((uint32_t)tail[1]) << 8;
-    case 1:
-      k1 ^= tail[0];
-      k1 *= c1;
-      k1 = ROTL32(k1, 15);
-      k1 *= c2;
-      h1 ^= k1;
-  };
-
-  /* finalization */
-  h1 ^= (uint32_t)len;
-  FMIX32(h1);
-  return h1;
-}
diff --git a/src/core/support/murmur_hash.h b/src/core/support/murmur_hash.h
deleted file mode 100644
index 0bf04f7..0000000
--- a/src/core/support/murmur_hash.h
+++ /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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_SUPPORT_MURMUR_HASH_H
-#define GRPC_INTERNAL_CORE_SUPPORT_MURMUR_HASH_H
-
-#include <grpc/support/port_platform.h>
-
-#include <stddef.h>
-
-/* compute the hash of key (length len) */
-uint32_t gpr_murmur_hash3(const void *key, size_t len, uint32_t seed);
-
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_MURMUR_HASH_H */
diff --git a/src/core/support/slice.c b/src/core/support/slice.c
deleted file mode 100644
index b9a7c77..0000000
--- a/src/core/support/slice.c
+++ /dev/null
@@ -1,343 +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/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice.h>
-
-#include <string.h>
-
-gpr_slice gpr_empty_slice(void) {
-  gpr_slice out;
-  out.refcount = 0;
-  out.data.inlined.length = 0;
-  return out;
-}
-
-gpr_slice gpr_slice_ref(gpr_slice slice) {
-  if (slice.refcount) {
-    slice.refcount->ref(slice.refcount);
-  }
-  return slice;
-}
-
-void gpr_slice_unref(gpr_slice slice) {
-  if (slice.refcount) {
-    slice.refcount->unref(slice.refcount);
-  }
-}
-
-/* gpr_slice_from_static_string support structure - a refcount that does
-   nothing */
-static void noop_ref_or_unref(void *unused) {}
-
-static gpr_slice_refcount noop_refcount = {noop_ref_or_unref,
-                                           noop_ref_or_unref};
-
-gpr_slice gpr_slice_from_static_string(const char *s) {
-  gpr_slice slice;
-  slice.refcount = &noop_refcount;
-  slice.data.refcounted.bytes = (uint8_t *)s;
-  slice.data.refcounted.length = strlen(s);
-  return slice;
-}
-
-/* gpr_slice_new support structures - we create a refcount object extended
-   with the user provided data pointer & destroy function */
-typedef struct new_slice_refcount {
-  gpr_slice_refcount rc;
-  gpr_refcount refs;
-  void (*user_destroy)(void *);
-  void *user_data;
-} new_slice_refcount;
-
-static void new_slice_ref(void *p) {
-  new_slice_refcount *r = p;
-  gpr_ref(&r->refs);
-}
-
-static void new_slice_unref(void *p) {
-  new_slice_refcount *r = p;
-  if (gpr_unref(&r->refs)) {
-    r->user_destroy(r->user_data);
-    gpr_free(r);
-  }
-}
-
-gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) {
-  gpr_slice slice;
-  new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount));
-  gpr_ref_init(&rc->refs, 1);
-  rc->rc.ref = new_slice_ref;
-  rc->rc.unref = new_slice_unref;
-  rc->user_destroy = destroy;
-  rc->user_data = p;
-
-  slice.refcount = &rc->rc;
-  slice.data.refcounted.bytes = p;
-  slice.data.refcounted.length = len;
-  return slice;
-}
-
-/* gpr_slice_new_with_len support structures - we create a refcount object
-   extended with the user provided data pointer & destroy function */
-typedef struct new_with_len_slice_refcount {
-  gpr_slice_refcount rc;
-  gpr_refcount refs;
-  void *user_data;
-  size_t user_length;
-  void (*user_destroy)(void *, size_t);
-} new_with_len_slice_refcount;
-
-static void new_with_len_ref(void *p) {
-  new_with_len_slice_refcount *r = p;
-  gpr_ref(&r->refs);
-}
-
-static void new_with_len_unref(void *p) {
-  new_with_len_slice_refcount *r = p;
-  if (gpr_unref(&r->refs)) {
-    r->user_destroy(r->user_data, r->user_length);
-    gpr_free(r);
-  }
-}
-
-gpr_slice gpr_slice_new_with_len(void *p, size_t len,
-                                 void (*destroy)(void *, size_t)) {
-  gpr_slice slice;
-  new_with_len_slice_refcount *rc =
-      gpr_malloc(sizeof(new_with_len_slice_refcount));
-  gpr_ref_init(&rc->refs, 1);
-  rc->rc.ref = new_with_len_ref;
-  rc->rc.unref = new_with_len_unref;
-  rc->user_destroy = destroy;
-  rc->user_data = p;
-  rc->user_length = len;
-
-  slice.refcount = &rc->rc;
-  slice.data.refcounted.bytes = p;
-  slice.data.refcounted.length = len;
-  return slice;
-}
-
-gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t length) {
-  gpr_slice slice = gpr_slice_malloc(length);
-  memcpy(GPR_SLICE_START_PTR(slice), source, length);
-  return slice;
-}
-
-gpr_slice gpr_slice_from_copied_string(const char *source) {
-  return gpr_slice_from_copied_buffer(source, strlen(source));
-}
-
-typedef struct {
-  gpr_slice_refcount base;
-  gpr_refcount refs;
-} malloc_refcount;
-
-static void malloc_ref(void *p) {
-  malloc_refcount *r = p;
-  gpr_ref(&r->refs);
-}
-
-static void malloc_unref(void *p) {
-  malloc_refcount *r = p;
-  if (gpr_unref(&r->refs)) {
-    gpr_free(r);
-  }
-}
-
-gpr_slice gpr_slice_malloc(size_t length) {
-  gpr_slice slice;
-
-  if (length > sizeof(slice.data.inlined.bytes)) {
-    /* Memory layout used by the slice created here:
-
-       +-----------+----------------------------------------------------------+
-       | refcount  | bytes                                                    |
-       +-----------+----------------------------------------------------------+
-
-       refcount is a malloc_refcount
-       bytes is an array of bytes of the requested length
-       Both parts are placed in the same allocation returned from gpr_malloc */
-    malloc_refcount *rc = gpr_malloc(sizeof(malloc_refcount) + length);
-
-    /* Initial refcount on rc is 1 - and it's up to the caller to release
-       this reference. */
-    gpr_ref_init(&rc->refs, 1);
-
-    rc->base.ref = malloc_ref;
-    rc->base.unref = malloc_unref;
-
-    /* Build up the slice to be returned. */
-    /* The slices refcount points back to the allocated block. */
-    slice.refcount = &rc->base;
-    /* The data bytes are placed immediately after the refcount struct */
-    slice.data.refcounted.bytes = (uint8_t *)(rc + 1);
-    /* And the length of the block is set to the requested length */
-    slice.data.refcounted.length = length;
-  } else {
-    /* small slice: just inline the data */
-    slice.refcount = NULL;
-    slice.data.inlined.length = (uint8_t)length;
-  }
-  return slice;
-}
-
-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 >= end);
-
-    /* Build the result */
-    subset.refcount = source.refcount;
-    /* Point into the source array */
-    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 = (uint8_t)(end - begin);
-    memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin,
-           end - begin);
-  }
-  return subset;
-}
-
-gpr_slice gpr_slice_sub(gpr_slice source, size_t begin, size_t end) {
-  gpr_slice subset;
-
-  if (end - begin <= sizeof(subset.data.inlined.bytes)) {
-    subset.refcount = NULL;
-    subset.data.inlined.length = (uint8_t)(end - begin);
-    memcpy(subset.data.inlined.bytes, GPR_SLICE_START_PTR(source) + begin,
-           end - begin);
-  } else {
-    subset = gpr_slice_sub_no_ref(source, begin, end);
-    /* Bump the refcount */
-    subset.refcount->ref(subset.refcount);
-  }
-  return subset;
-}
-
-gpr_slice gpr_slice_split_tail(gpr_slice *source, size_t split) {
-  gpr_slice tail;
-
-  if (source->refcount == NULL) {
-    /* inlined data, copy it out */
-    GPR_ASSERT(source->data.inlined.length >= split);
-    tail.refcount = NULL;
-    tail.data.inlined.length = (uint8_t)(source->data.inlined.length - split);
-    memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split,
-           tail.data.inlined.length);
-    source->data.inlined.length = (uint8_t)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 = (uint8_t)tail_length;
-      memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
-             tail_length);
-    } else {
-      /* Build the result */
-      tail.refcount = source->refcount;
-      /* Bump the refcount */
-      tail.refcount->ref(tail.refcount);
-      /* Point into the source array */
-      tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
-      tail.data.refcounted.length = tail_length;
-    }
-    source->data.refcounted.length = split;
-  }
-
-  return tail;
-}
-
-gpr_slice gpr_slice_split_head(gpr_slice *source, size_t split) {
-  gpr_slice head;
-
-  if (source->refcount == NULL) {
-    GPR_ASSERT(source->data.inlined.length >= split);
-
-    head.refcount = NULL;
-    head.data.inlined.length = (uint8_t)split;
-    memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split);
-    source->data.inlined.length =
-        (uint8_t)(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 = (uint8_t)split;
-    memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
-    source->data.refcounted.bytes += split;
-    source->data.refcounted.length -= split;
-  } else {
-    GPR_ASSERT(source->data.refcounted.length >= split);
-
-    /* Build the result */
-    head.refcount = source->refcount;
-    /* Bump the refcount */
-    head.refcount->ref(head.refcount);
-    /* Point into the source array */
-    head.data.refcounted.bytes = source->data.refcounted.bytes;
-    head.data.refcounted.length = split;
-    source->data.refcounted.bytes += split;
-    source->data.refcounted.length -= split;
-  }
-
-  return head;
-}
-
-int gpr_slice_cmp(gpr_slice a, gpr_slice 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));
-}
-
-int gpr_slice_str_cmp(gpr_slice a, const char *b) {
-  size_t b_length = strlen(b);
-  int d = (int)(GPR_SLICE_LENGTH(a) - b_length);
-  if (d != 0) return d;
-  return memcmp(GPR_SLICE_START_PTR(a), b, b_length);
-}
diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c
deleted file mode 100644
index 66f111d..0000000
--- a/src/core/support/slice_buffer.c
+++ /dev/null
@@ -1,282 +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/support/port_platform.h>
-#include <grpc/support/slice_buffer.h>
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-/* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
-#define GROW(x) (3 * (x) / 2)
-
-static void maybe_embiggen(gpr_slice_buffer *sb) {
-  if (sb->count == sb->capacity) {
-    sb->capacity = GROW(sb->capacity);
-    GPR_ASSERT(sb->capacity > sb->count);
-    if (sb->slices == sb->inlined) {
-      sb->slices = gpr_malloc(sb->capacity * sizeof(gpr_slice));
-      memcpy(sb->slices, sb->inlined, sb->count * sizeof(gpr_slice));
-    } else {
-      sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
-    }
-  }
-}
-
-void gpr_slice_buffer_init(gpr_slice_buffer *sb) {
-  sb->count = 0;
-  sb->length = 0;
-  sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS;
-  sb->slices = sb->inlined;
-}
-
-void gpr_slice_buffer_destroy(gpr_slice_buffer *sb) {
-  gpr_slice_buffer_reset_and_unref(sb);
-  if (sb->slices != sb->inlined) {
-    gpr_free(sb->slices);
-  }
-}
-
-uint8_t *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, size_t n) {
-  gpr_slice *back;
-  uint8_t *out;
-
-  sb->length += n;
-
-  if (sb->count == 0) goto add_new;
-  back = &sb->slices[sb->count - 1];
-  if (back->refcount) goto add_new;
-  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 = (uint8_t)(back->data.inlined.length + n);
-  return out;
-
-add_new:
-  maybe_embiggen(sb);
-  back = &sb->slices[sb->count];
-  sb->count++;
-  back->refcount = NULL;
-  back->data.inlined.length = (uint8_t)n;
-  return back->data.inlined.bytes;
-}
-
-size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice s) {
-  size_t out = sb->count;
-  maybe_embiggen(sb);
-  sb->slices[out] = s;
-  sb->length += GPR_SLICE_LENGTH(s);
-  sb->count = out + 1;
-  return out;
-}
-
-void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) {
-  size_t n = sb->count;
-  /* if both the last slice in the slice buffer and the slice being added
-     are inlined (that is, that they carry their data inside the slice data
-     structure), and the back slice is not full, then concatenate directly
-     into the back slice, preventing many small slices being passed into
-     writes */
-  if (!s.refcount && n) {
-    gpr_slice *back = &sb->slices[n - 1];
-    if (!back->refcount && back->data.inlined.length < GPR_SLICE_INLINED_SIZE) {
-      if (s.data.inlined.length + back->data.inlined.length <=
-          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 =
-            (uint8_t)(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,
-               s.data.inlined.bytes, cp1);
-        back->data.inlined.length = GPR_SLICE_INLINED_SIZE;
-        maybe_embiggen(sb);
-        back = &sb->slices[n];
-        sb->count = n + 1;
-        back->refcount = NULL;
-        back->data.inlined.length = (uint8_t)(s.data.inlined.length - cp1);
-        memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1,
-               s.data.inlined.length - cp1);
-      }
-      sb->length += s.data.inlined.length;
-      return; /* early out */
-    }
-  }
-  gpr_slice_buffer_add_indexed(sb, s);
-}
-
-void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *s, size_t n) {
-  size_t i;
-  for (i = 0; i < n; i++) {
-    gpr_slice_buffer_add(sb, s[i]);
-  }
-}
-
-void gpr_slice_buffer_pop(gpr_slice_buffer *sb) {
-  if (sb->count != 0) {
-    size_t count = --sb->count;
-    sb->length -= GPR_SLICE_LENGTH(sb->slices[count]);
-  }
-}
-
-void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) {
-  size_t i;
-
-  for (i = 0; i < sb->count; i++) {
-    gpr_slice_unref(sb->slices[i]);
-  }
-
-  sb->count = 0;
-  sb->length = 0;
-}
-
-void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b) {
-  GPR_SWAP(size_t, a->count, b->count);
-  GPR_SWAP(size_t, a->capacity, b->capacity);
-  GPR_SWAP(size_t, a->length, b->length);
-
-  if (a->slices == a->inlined) {
-    if (b->slices == b->inlined) {
-      /* swap contents of inlined buffer */
-      gpr_slice temp[GRPC_SLICE_BUFFER_INLINE_ELEMENTS];
-      memcpy(temp, a->slices, b->count * sizeof(gpr_slice));
-      memcpy(a->slices, b->slices, a->count * sizeof(gpr_slice));
-      memcpy(b->slices, temp, b->count * sizeof(gpr_slice));
-    } else {
-      /* a is inlined, b is not - copy a inlined into b, fix pointers */
-      a->slices = b->slices;
-      b->slices = b->inlined;
-      memcpy(b->slices, a->inlined, b->count * sizeof(gpr_slice));
-    }
-  } else if (b->slices == b->inlined) {
-    /* b is inlined, a is not - copy b inlined int a, fix pointers */
-    b->slices = a->slices;
-    a->slices = a->inlined;
-    memcpy(a->slices, b->inlined, a->count * sizeof(gpr_slice));
-  } else {
-    /* no inlining: easy swap */
-    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;
-}
-
-void gpr_slice_buffer_move_first(gpr_slice_buffer *src, size_t n,
-                                 gpr_slice_buffer *dst) {
-  size_t src_idx;
-  size_t output_len = dst->length + n;
-  size_t new_input_len = src->length - n;
-  GPR_ASSERT(src->length >= n);
-  if (src->length == n) {
-    gpr_slice_buffer_move_into(src, dst);
-    return;
-  }
-  src_idx = 0;
-  while (src_idx < src->capacity) {
-    gpr_slice slice = src->slices[src_idx];
-    size_t slice_len = GPR_SLICE_LENGTH(slice);
-    if (n > slice_len) {
-      gpr_slice_buffer_add(dst, slice);
-      n -= slice_len;
-      src_idx++;
-    } else if (n == slice_len) {
-      gpr_slice_buffer_add(dst, slice);
-      src_idx++;
-      break;
-    } else { /* n < slice_len */
-      src->slices[src_idx] = gpr_slice_split_tail(&slice, n);
-      GPR_ASSERT(GPR_SLICE_LENGTH(slice) == n);
-      GPR_ASSERT(GPR_SLICE_LENGTH(src->slices[src_idx]) == slice_len - n);
-      gpr_slice_buffer_add(dst, slice);
-      break;
-    }
-  }
-  GPR_ASSERT(dst->length == output_len);
-  memmove(src->slices, src->slices + src_idx,
-          sizeof(gpr_slice) * (src->count - src_idx));
-  src->count -= src_idx;
-  src->length = new_input_len;
-  GPR_ASSERT(src->count > 0);
-}
-
-void gpr_slice_buffer_trim_end(gpr_slice_buffer *sb, size_t n,
-                               gpr_slice_buffer *garbage) {
-  GPR_ASSERT(n <= sb->length);
-  sb->length -= n;
-  for (;;) {
-    size_t idx = sb->count - 1;
-    gpr_slice slice = sb->slices[idx];
-    size_t slice_len = GPR_SLICE_LENGTH(slice);
-    if (slice_len > n) {
-      sb->slices[idx] = gpr_slice_split_head(&slice, slice_len - n);
-      gpr_slice_buffer_add_indexed(garbage, slice);
-      return;
-    } else if (slice_len == n) {
-      gpr_slice_buffer_add_indexed(garbage, slice);
-      sb->count = idx;
-      return;
-    } else {
-      gpr_slice_buffer_add_indexed(garbage, slice);
-      n -= slice_len;
-      sb->count = idx;
-    }
-  }
-}
-
-gpr_slice gpr_slice_buffer_take_first(gpr_slice_buffer *sb) {
-  gpr_slice slice;
-  GPR_ASSERT(sb->count > 0);
-  slice = sb->slices[0];
-  memmove(&sb->slices[0], &sb->slices[1], (sb->count - 1) * sizeof(gpr_slice));
-  sb->count--;
-  sb->length -= GPR_SLICE_LENGTH(slice);
-  return slice;
-}
diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c
deleted file mode 100644
index 9daecd2..0000000
--- a/src/core/support/stack_lockfree.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "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 */
-  uint16_t index;
-#ifdef GPR_ARCH_64
-  uint16_t pad;
-  uint32_t aba_ctr;
-#else
-#ifdef GPR_ARCH_32
-  uint16_t 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 */
-
-#ifndef NDEBUG
-  /* Bitmap of pushed entries to check for double-push or pop */
-  gpr_atm pushed[(INVALID_ENTRY_INDEX + 1) / (8 * sizeof(gpr_atm))];
-#endif
-};
-
-gpr_stack_lockfree *gpr_stack_lockfree_create(size_t 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));
-#ifndef NDEBUG
-  memset(&stack->pushed, 0, sizeof(stack->pushed));
-#endif
-
-  GPR_ASSERT(sizeof(stack->entries->atm) == sizeof(stack->entries->contents));
-
-  /* Point the head at reserved dummy entry */
-  stack->head.contents.index = INVALID_ENTRY_INDEX;
-/* Fill in the pad and aba_ctr to avoid confusing memcheck tools */
-#ifdef GPR_ARCH_64
-  stack->head.contents.pad = 0;
-#endif
-  stack->head.contents.aba_ctr = 0;
-  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;
-  lockfree_node curent;
-  lockfree_node newent;
-
-  /* First fill in the entry's index and aba ctr for new head */
-  newhead.contents.index = (uint16_t)entry;
-#ifdef GPR_ARCH_64
-  /* Fill in the pad to avoid confusing memcheck tools */
-  newhead.contents.pad = 0;
-#endif
-
-  /* Also post-increment the aba_ctr */
-  curent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm);
-  newhead.contents.aba_ctr = ++curent.contents.aba_ctr;
-  gpr_atm_no_barrier_store(&stack->entries[entry].atm, curent.atm);
-
-#ifndef NDEBUG
-  /* Check for double push */
-  {
-    int pushed_index = entry / (int)(8 * sizeof(gpr_atm));
-    int pushed_bit = entry % (int)(8 * sizeof(gpr_atm));
-    gpr_atm old_val;
-
-    old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
-                                           ((gpr_atm)1 << pushed_bit));
-    GPR_ASSERT((old_val & (((gpr_atm)1) << pushed_bit)) == 0);
-  }
-#endif
-
-  do {
-    /* Atomically get the existing head value for use */
-    head.atm = gpr_atm_no_barrier_load(&(stack->head.atm));
-    /* Point to it */
-    newent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm);
-    newent.contents.index = head.contents.index;
-    gpr_atm_no_barrier_store(&stack->entries[entry].atm, newent.atm);
-  } 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));
-#ifndef NDEBUG
-  /* Check for valid pop */
-  {
-    int pushed_index = head.contents.index / (8 * sizeof(gpr_atm));
-    int pushed_bit = head.contents.index % (8 * sizeof(gpr_atm));
-    gpr_atm old_val;
-
-    old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
-                                           -((gpr_atm)1 << pushed_bit));
-    GPR_ASSERT((old_val & (((gpr_atm)1) << pushed_bit)) != 0);
-  }
-#endif
-
-  return head.contents.index;
-}
diff --git a/src/core/support/stack_lockfree.h b/src/core/support/stack_lockfree.h
deleted file mode 100644
index ca58dd0..0000000
--- a/src/core/support/stack_lockfree.h
+++ /dev/null
@@ -1,53 +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_SUPPORT_STACK_LOCKFREE_H
-#define GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H
-
-#include <stddef.h>
-
-typedef struct gpr_stack_lockfree gpr_stack_lockfree;
-
-/* 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(size_t entries);
-void gpr_stack_lockfree_destroy(gpr_stack_lockfree *stack);
-
-/* 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
deleted file mode 100644
index 1f541de..0000000
--- a/src/core/support/string.c
+++ /dev/null
@@ -1,296 +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/support/string.h"
-
-#include <ctype.h>
-#include <stddef.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/useful.h>
-
-char *gpr_strdup(const char *src) {
-  char *dst;
-  size_t len;
-
-  if (!src) {
-    return NULL;
-  }
-
-  len = strlen(src) + 1;
-  dst = gpr_malloc(len);
-
-  memcpy(dst, src, len);
-
-  return dst;
-}
-
-typedef struct {
-  size_t capacity;
-  size_t length;
-  char *data;
-} dump_out;
-
-static dump_out dump_out_create(void) {
-  dump_out r = {0, 0, NULL};
-  return r;
-}
-
-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);
-  }
-  out->data[out->length++] = c;
-}
-
-static void hexdump(dump_out *out, const char *buf, size_t len) {
-  static const char hex[16] = "0123456789abcdef";
-
-  const uint8_t *const beg = (const uint8_t *)buf;
-  const uint8_t *const end = beg + len;
-  const uint8_t *cur;
-
-  for (cur = beg; cur != end; ++cur) {
-    if (cur != beg) dump_out_append(out, ' ');
-    dump_out_append(out, hex[*cur >> 4]);
-    dump_out_append(out, hex[*cur & 0xf]);
-  }
-}
-
-static void asciidump(dump_out *out, const char *buf, size_t len) {
-  const uint8_t *const beg = (const uint8_t *)buf;
-  const uint8_t *const end = beg + len;
-  const uint8_t *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, (char)(isprint(*cur) ? *(char *)cur : '.'));
-  }
-  if (!out_was_empty) {
-    dump_out_append(out, '\'');
-  }
-}
-
-char *gpr_dump(const char *buf, size_t len, uint32_t 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, uint32_t 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, uint32_t *result) {
-  uint32_t out = 0;
-  uint32_t new;
-  size_t i;
-
-  if (len == 0) return 0; /* must have some bytes */
-
-  for (i = 0; i < len; i++) {
-    if (buf[i] < '0' || buf[i] > '9') return 0; /* bad char */
-    new = 10 * out + (uint32_t)(buf[i] - '0');
-    if (new < out) return 0; /* overflow */
-    out = new;
-  }
-
-  *result = out;
-  return 1;
-}
-
-void gpr_reverse_bytes(char *str, int len) {
-  char *p1, *p2;
-  for (p1 = str, p2 = str + len - 1; p2 > p1; ++p1, --p2) {
-    char temp = *p1;
-    *p1 = *p2;
-    *p2 = temp;
-  }
-}
-
-int gpr_ltoa(long value, char *string) {
-  long sign;
-  int i = 0;
-
-  if (value == 0) {
-    string[0] = '0';
-    string[1] = 0;
-    return 1;
-  }
-
-  sign = value < 0 ? -1 : 1;
-  while (value) {
-    string[i++] = (char)('0' + sign * (value % 10));
-    value /= 10;
-  }
-  if (sign < 0) string[i++] = '-';
-  gpr_reverse_bytes(string, i);
-  string[i] = 0;
-  return i;
-}
-
-int int64_ttoa(int64_t value, char *string) {
-  int64_t sign;
-  int i = 0;
-
-  if (value == 0) {
-    string[0] = '0';
-    string[1] = 0;
-    return 1;
-  }
-
-  sign = value < 0 ? -1 : 1;
-  while (value) {
-    string[i++] = (char)('0' + sign * (value % 10));
-    value /= 10;
-  }
-  if (sign < 0) string[i++] = '-';
-  gpr_reverse_bytes(string, i);
-  string[i] = 0;
-  return i;
-}
-
-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;
-  for (i = 0; i < nstrs; i++) {
-    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++) {
-    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;
-  }
-  out[out_length] = 0;
-  if (final_length != NULL) {
-    *final_length = out_length;
-  }
-  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 uint8_t *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)); }
-
-void gpr_strvec_destroy(gpr_strvec *sv) {
-  size_t i;
-  for (i = 0; i < sv->count; i++) {
-    gpr_free(sv->strs[i]);
-  }
-  gpr_free(sv->strs);
-}
-
-void gpr_strvec_add(gpr_strvec *sv, char *str) {
-  if (sv->count == sv->capacity) {
-    sv->capacity = GPR_MAX(sv->capacity + 8, sv->capacity * 2);
-    sv->strs = gpr_realloc(sv->strs, sizeof(char *) * sv->capacity);
-  }
-  sv->strs[sv->count++] = str;
-}
-
-char *gpr_strvec_flatten(gpr_strvec *sv, size_t *final_length) {
-  return gpr_strjoin((const char **)sv->strs, sv->count, final_length);
-}
diff --git a/src/core/support/string.h b/src/core/support/string.h
deleted file mode 100644
index e6755de..0000000
--- a/src/core/support/string.h
+++ /dev/null
@@ -1,121 +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_SUPPORT_STRING_H
-#define GRPC_INTERNAL_CORE_SUPPORT_STRING_H
-
-#include <stddef.h>
-
-#include <grpc/support/port_platform.h>
-#include <grpc/support/slice_buffer.h>
-#include <grpc/support/slice.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* String utility functions */
-
-/* Flags for gpr_dump function. */
-#define GPR_DUMP_HEX 0x00000001
-#define GPR_DUMP_ASCII 0x00000002
-
-/* 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, uint32_t flags);
-
-/* Calls gpr_dump on a slice. */
-char *gpr_dump_slice(gpr_slice slice, uint32_t flags);
-
-/* Parses an array of bytes into an integer (base 10). Returns 1 on success,
-   0 on failure. */
-int gpr_parse_bytes_to_uint32(const char *data, size_t length,
-                              uint32_t *result);
-
-/* Minimum buffer size for calling ltoa */
-#define GPR_LTOA_MIN_BUFSIZE (3 * sizeof(long))
-
-/* Convert a long to a string in base 10; returns the length of the
-   output string (or 0 on failure).
-   output must be at least GPR_LTOA_MIN_BUFSIZE bytes long. */
-int gpr_ltoa(long value, char *output);
-
-/* Minimum buffer size for calling int64toa */
-#define GPR_INT64TOA_MIN_BUFSIZE (3 * sizeof(int64_t))
-
-/* Convert an int64 to a string in base 10; returns the length of the
-output string (or 0 on failure).
-output must be at least GPR_INT64TOA_MIN_BUFSIZE bytes long.
-NOTE: This function ensures sufficient bit width even on Win x64,
-where long is 32bit is size.*/
-int int64_ttoa(int64_t value, char *output);
-
-/* Reverse a run of bytes */
-void gpr_reverse_bytes(char *str, int len);
-
-/* Join a set of strings, returning the resulting string.
-   Total combined length (excluding null terminator) is returned in total_length
-   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;
-  size_t count;
-  size_t capacity;
-} gpr_strvec;
-
-/* Initialize/destroy */
-void gpr_strvec_init(gpr_strvec *strs);
-void gpr_strvec_destroy(gpr_strvec *strs);
-/* Add a string to a strvec, takes ownership of the string */
-void gpr_strvec_add(gpr_strvec *strs, char *add);
-/* Return a joined string with all added substrings, optionally setting
-   total_length as per gpr_strjoin */
-char *gpr_strvec_flatten(gpr_strvec *strs, size_t *total_length);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_STRING_H */
diff --git a/src/core/support/string_posix.c b/src/core/support/string_posix.c
deleted file mode 100644
index 25c333d..0000000
--- a/src/core/support/string_posix.c
+++ /dev/null
@@ -1,86 +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/support/port_platform.h>
-
-#ifdef GPR_POSIX_STRING
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-
-int gpr_asprintf(char **strp, const char *format, ...) {
-  va_list args;
-  int ret;
-  char buf[64];
-  size_t strp_buflen;
-
-  /* Use a constant-sized buffer to determine the length. */
-  va_start(args, format);
-  ret = vsnprintf(buf, sizeof(buf), format, args);
-  va_end(args);
-  if (ret < 0) {
-    *strp = NULL;
-    return -1;
-  }
-
-  /* Allocate a new buffer, with space for the NUL terminator. */
-  strp_buflen = (size_t)ret + 1;
-  if ((*strp = gpr_malloc(strp_buflen)) == NULL) {
-    /* This shouldn't happen, because gpr_malloc() calls abort(). */
-    return -1;
-  }
-
-  /* Return early if we have all the bytes. */
-  if (strp_buflen <= sizeof(buf)) {
-    memcpy(*strp, buf, strp_buflen);
-    return ret;
-  }
-
-  /* Try again using the larger buffer. */
-  va_start(args, format);
-  ret = vsnprintf(*strp, strp_buflen, format, args);
-  va_end(args);
-  if ((size_t)ret == strp_buflen - 1) {
-    return ret;
-  }
-
-  /* This should never happen. */
-  gpr_free(*strp);
-  *strp = NULL;
-  return -1;
-}
-
-#endif /* GPR_POSIX_STRING */
diff --git a/src/core/support/string_win32.c b/src/core/support/string_win32.c
deleted file mode 100644
index 3b1f702..0000000
--- a/src/core/support/string_win32.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* Posix code for gpr snprintf support. */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WIN32
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-
-#include "src/core/support/string.h"
-
-int gpr_asprintf(char **strp, const char *format, ...) {
-  va_list args;
-  int ret;
-  size_t strp_buflen;
-
-  /* Determine the length. */
-  va_start(args, format);
-  ret = _vscprintf(format, args);
-  va_end(args);
-  if (ret < 0) {
-    *strp = NULL;
-    return -1;
-  }
-
-  /* Allocate a new buffer, with space for the NUL terminator. */
-  strp_buflen = (size_t)ret + 1;
-  if ((*strp = gpr_malloc(strp_buflen)) == NULL) {
-    /* This shouldn't happen, because gpr_malloc() calls abort(). */
-    return -1;
-  }
-
-  /* Print to the buffer. */
-  va_start(args, format);
-  ret = vsnprintf_s(*strp, strp_buflen, _TRUNCATE, format, args);
-  va_end(args);
-  if ((size_t)ret == strp_buflen - 1) {
-    return ret;
-  }
-
-  /* This should never happen. */
-  gpr_free(*strp);
-  *strp = NULL;
-  return -1;
-}
-
-#if defined UNICODE || defined _UNICODE
-LPTSTR
-gpr_char_to_tchar(LPCSTR input) {
-  LPTSTR ret;
-  int needed = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
-  if (needed <= 0) return NULL;
-  ret = gpr_malloc((unsigned)needed * sizeof(TCHAR));
-  MultiByteToWideChar(CP_UTF8, 0, input, -1, ret, needed);
-  return ret;
-}
-
-LPSTR
-gpr_tchar_to_char(LPCTSTR input) {
-  LPSTR ret;
-  int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL);
-  if (needed <= 0) return NULL;
-  ret = gpr_malloc((unsigned)needed);
-  WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL);
-  return ret;
-}
-#else
-char *gpr_tchar_to_char(LPTSTR input) { return gpr_strdup(input); }
-
-char *gpr_char_to_tchar(LPTSTR input) { return gpr_strdup(input); }
-#endif
-
-#endif /* GPR_WIN32 */
diff --git a/src/core/support/string_win32.h b/src/core/support/string_win32.h
deleted file mode 100644
index e304365..0000000
--- a/src/core/support/string_win32.h
+++ /dev/null
@@ -1,47 +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_SUPPORT_STRING_WIN32_H
-#define GRPC_INTERNAL_CORE_SUPPORT_STRING_WIN32_H
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WIN32
-
-/* 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);
-
-#endif /* GPR_WIN32 */
-
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_STRING_WIN32_H */
diff --git a/src/core/support/subprocess_posix.c b/src/core/support/subprocess_posix.c
deleted file mode 100644
index 171054e..0000000
--- a/src/core/support/subprocess_posix.c
+++ /dev/null
@@ -1,112 +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/support/port_platform.h>
-
-#ifdef GPR_POSIX_SUBPROCESS
-
-#include <grpc/support/subprocess.h>
-
-#include <unistd.h>
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-struct gpr_subprocess {
-  int pid;
-  int joined;
-};
-
-const char *gpr_subprocess_binary_extension() { return ""; }
-
-gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) {
-  gpr_subprocess *r;
-  int pid;
-  char **exec_args;
-
-  pid = fork();
-  if (pid == -1) {
-    return NULL;
-  } else if (pid == 0) {
-    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 */
-    gpr_log(GPR_ERROR, "execv '%s' failed: %s", exec_args[0], strerror(errno));
-    _exit(1);
-    return NULL;
-  } else {
-    r = gpr_malloc(sizeof(gpr_subprocess));
-    memset(r, 0, sizeof(*r));
-    r->pid = pid;
-    return r;
-  }
-}
-
-void gpr_subprocess_destroy(gpr_subprocess *p) {
-  if (!p->joined) {
-    kill(p->pid, SIGKILL);
-    gpr_subprocess_join(p);
-  }
-  gpr_free(p);
-}
-
-int gpr_subprocess_join(gpr_subprocess *p) {
-  int status;
-retry:
-  if (waitpid(p->pid, &status, 0) == -1) {
-    if (errno == EINTR) {
-      goto retry;
-    }
-    gpr_log(GPR_ERROR, "waitpid failed: %s", strerror(errno));
-    return -1;
-  }
-  return status;
-}
-
-void gpr_subprocess_interrupt(gpr_subprocess *p) {
-  if (!p->joined) {
-    kill(p->pid, SIGINT);
-  }
-}
-
-#endif /* GPR_POSIX_SUBPROCESS */
diff --git a/src/core/support/subprocess_windows.c b/src/core/support/subprocess_windows.c
deleted file mode 100644
index 2b25ef0..0000000
--- a/src/core/support/subprocess_windows.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- *
- * Copyright 2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WINDOWS_SUBPROCESS
-
-#include <windows.h>
-#include <string.h>
-#include <tchar.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/subprocess.h>
-#include "src/core/support/string.h"
-#include "src/core/support/string_win32.h"
-
-struct gpr_subprocess {
-  PROCESS_INFORMATION pi;
-  int joined;
-  int interrupted;
-};
-
-const char *gpr_subprocess_binary_extension() { return ".exe"; }
-
-gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) {
-  gpr_subprocess *r;
-
-  STARTUPINFO si;
-  PROCESS_INFORMATION pi;
-
-  char *args = gpr_strjoin_sep(argv, (size_t)argc, " ", NULL);
-  TCHAR *args_tchar;
-
-  args_tchar = gpr_char_to_tchar(args);
-  gpr_free(args);
-
-  memset(&si, 0, sizeof(si));
-  si.cb = sizeof(si);
-  memset(&pi, 0, sizeof(pi));
-
-  if (!CreateProcess(NULL, args_tchar, NULL, NULL, FALSE,
-                     CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) {
-    gpr_free(args_tchar);
-    return NULL;
-  }
-  gpr_free(args_tchar);
-
-  r = gpr_malloc(sizeof(gpr_subprocess));
-  memset(r, 0, sizeof(*r));
-  r->pi = pi;
-  return r;
-}
-
-void gpr_subprocess_destroy(gpr_subprocess *p) {
-  if (p) {
-    if (!p->joined) {
-      gpr_subprocess_interrupt(p);
-      gpr_subprocess_join(p);
-    }
-    if (p->pi.hProcess) {
-      CloseHandle(p->pi.hProcess);
-    }
-    if (p->pi.hThread) {
-      CloseHandle(p->pi.hThread);
-    }
-    gpr_free(p);
-  }
-}
-
-int gpr_subprocess_join(gpr_subprocess *p) {
-  DWORD dwExitCode;
-  if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) {
-    if (dwExitCode == STILL_ACTIVE) {
-      if (WaitForSingleObject(p->pi.hProcess, INFINITE) == WAIT_OBJECT_0) {
-        p->joined = 1;
-        goto getExitCode;
-      }
-      return -1;  // failed to join
-    } else {
-      goto getExitCode;
-    }
-  } else {
-    return -1;  // failed to get exit code
-  }
-
-getExitCode:
-  if (p->interrupted) {
-    return 0;
-  }
-  if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) {
-    return (int)dwExitCode;
-  } else {
-    return -1;  // failed to get exit code
-  }
-}
-
-void gpr_subprocess_interrupt(gpr_subprocess *p) {
-  DWORD dwExitCode;
-  if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) {
-    if (dwExitCode == STILL_ACTIVE) {
-      gpr_log(GPR_INFO, "sending ctrl-break");
-      GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, p->pi.dwProcessId);
-      p->joined = 1;
-      p->interrupted = 1;
-    }
-  }
-  return;
-}
-
-#endif /* GPR_WINDOWS_SUBPROCESS */
diff --git a/src/core/support/sync.c b/src/core/support/sync.c
deleted file mode 100644
index 69e3e39..0000000
--- a/src/core/support/sync.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* Generic implementation of synchronization primitives. */
-
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/atm.h>
-
-/* Number of mutexes to allocate for events, to avoid lock contention.
-   Should be a prime. */
-enum { event_sync_partitions = 31 };
-
-/* Events are partitioned by address to avoid lock contention. */
-static struct sync_array_s {
-  gpr_mu mu;
-  gpr_cv cv;
-} sync_array[event_sync_partitions];
-
-/* This routine is executed once on first use, via event_once */
-static gpr_once event_once = GPR_ONCE_INIT;
-static void event_initialize(void) {
-  int i;
-  for (i = 0; i != event_sync_partitions; i++) {
-    gpr_mu_init(&sync_array[i].mu);
-    gpr_cv_init(&sync_array[i].cv);
-  }
-}
-
-/* Hash ev into an element of sync_array[]. */
-static struct sync_array_s *hash(gpr_event *ev) {
-  return &sync_array[((uintptr_t)ev) % event_sync_partitions];
-}
-
-void gpr_event_init(gpr_event *ev) {
-  gpr_once_init(&event_once, &event_initialize);
-  ev->state = 0;
-}
-
-void gpr_event_set(gpr_event *ev, void *value) {
-  struct sync_array_s *s = hash(ev);
-  gpr_mu_lock(&s->mu);
-  GPR_ASSERT(gpr_atm_acq_load(&ev->state) == 0);
-  gpr_atm_rel_store(&ev->state, (gpr_atm)value);
-  gpr_cv_broadcast(&s->cv);
-  gpr_mu_unlock(&s->mu);
-  GPR_ASSERT(value != NULL);
-}
-
-void *gpr_event_get(gpr_event *ev) {
-  return (void *)gpr_atm_acq_load(&ev->state);
-}
-
-void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline) {
-  void *result = (void *)gpr_atm_acq_load(&ev->state);
-  if (result == NULL) {
-    struct sync_array_s *s = hash(ev);
-    gpr_mu_lock(&s->mu);
-    do {
-      result = (void *)gpr_atm_acq_load(&ev->state);
-    } while (result == NULL && !gpr_cv_wait(&s->cv, &s->mu, abs_deadline));
-    gpr_mu_unlock(&s->mu);
-  }
-  return result;
-}
-
-void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); }
-
-void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); }
-
-void gpr_ref_non_zero(gpr_refcount *r) {
-  gpr_atm prior = gpr_atm_no_barrier_fetch_add(&r->count, 1);
-  GPR_ASSERT(prior > 0);
-}
-
-void gpr_refn(gpr_refcount *r, int n) {
-  gpr_atm_no_barrier_fetch_add(&r->count, n);
-}
-
-int gpr_unref(gpr_refcount *r) {
-  gpr_atm prior = gpr_atm_full_fetch_add(&r->count, -1);
-  GPR_ASSERT(prior > 0);
-  return prior == 1;
-}
-
-void gpr_stats_init(gpr_stats_counter *c, intptr_t n) {
-  gpr_atm_rel_store(&c->value, n);
-}
-
-void gpr_stats_inc(gpr_stats_counter *c, intptr_t inc) {
-  gpr_atm_no_barrier_fetch_add(&c->value, inc);
-}
-
-intptr_t gpr_stats_read(const gpr_stats_counter *c) {
-  /* don't need acquire-load, but we have no no-barrier load yet */
-  return gpr_atm_acq_load(&c->value);
-}
diff --git a/src/core/support/sync_posix.c b/src/core/support/sync_posix.c
deleted file mode 100644
index d3c483f..0000000
--- a/src/core/support/sync_posix.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SYNC
-
-#include <errno.h>
-#include <time.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/time.h>
-#include "src/core/profiling/timers.h"
-
-void gpr_mu_init(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_init(mu, NULL) == 0); }
-
-void gpr_mu_destroy(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_destroy(mu) == 0); }
-
-void gpr_mu_lock(gpr_mu* mu) {
-  GPR_TIMER_BEGIN("gpr_mu_lock", 0);
-  GPR_ASSERT(pthread_mutex_lock(mu) == 0);
-  GPR_TIMER_END("gpr_mu_lock", 0);
-}
-
-void gpr_mu_unlock(gpr_mu* mu) {
-  GPR_TIMER_BEGIN("gpr_mu_unlock", 0);
-  GPR_ASSERT(pthread_mutex_unlock(mu) == 0);
-  GPR_TIMER_END("gpr_mu_unlock", 0);
-}
-
-int gpr_mu_trylock(gpr_mu* mu) {
-  int err;
-  GPR_TIMER_BEGIN("gpr_mu_trylock", 0);
-  err = pthread_mutex_trylock(mu);
-  GPR_ASSERT(err == 0 || err == EBUSY);
-  GPR_TIMER_END("gpr_mu_trylock", 0);
-  return err == 0;
-}
-
-/*----------------------------------------*/
-
-void gpr_cv_init(gpr_cv* cv) { GPR_ASSERT(pthread_cond_init(cv, NULL) == 0); }
-
-void gpr_cv_destroy(gpr_cv* cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); }
-
-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(abs_deadline.clock_type)) ==
-      0) {
-    err = pthread_cond_wait(cv, mu);
-  } else {
-    struct timespec abs_deadline_ts;
-    abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME);
-    abs_deadline_ts.tv_sec = (time_t)abs_deadline.tv_sec;
-    abs_deadline_ts.tv_nsec = abs_deadline.tv_nsec;
-    err = pthread_cond_timedwait(cv, mu, &abs_deadline_ts);
-  }
-  GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN);
-  return err == ETIMEDOUT;
-}
-
-void gpr_cv_signal(gpr_cv* cv) { GPR_ASSERT(pthread_cond_signal(cv) == 0); }
-
-void gpr_cv_broadcast(gpr_cv* cv) {
-  GPR_ASSERT(pthread_cond_broadcast(cv) == 0);
-}
-
-/*----------------------------------------*/
-
-void gpr_once_init(gpr_once* once, void (*init_function)(void)) {
-  GPR_ASSERT(pthread_once(once, init_function) == 0);
-}
-
-#endif /* GRP_POSIX_SYNC */
diff --git a/src/core/support/thd.c b/src/core/support/thd.c
deleted file mode 100644
index 41daeb5..0000000
--- a/src/core/support/thd.c
+++ /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.
- *
- */
-
-/* Posix implementation for gpr threads. */
-
-#include <memory.h>
-
-#include <grpc/support/thd.h>
-
-enum { GPR_THD_JOINABLE = 1 };
-
-gpr_thd_options gpr_thd_options_default(void) {
-  gpr_thd_options options;
-  memset(&options, 0, sizeof(options));
-  return options;
-}
-
-void gpr_thd_options_set_detached(gpr_thd_options* options) {
-  options->flags &= ~GPR_THD_JOINABLE;
-}
-
-void gpr_thd_options_set_joinable(gpr_thd_options* options) {
-  options->flags |= GPR_THD_JOINABLE;
-}
-
-int gpr_thd_options_is_detached(const gpr_thd_options* options) {
-  if (!options) return 1;
-  return (options->flags & GPR_THD_JOINABLE) == 0;
-}
-
-int gpr_thd_options_is_joinable(const gpr_thd_options* options) {
-  if (!options) return 0;
-  return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE;
-}
diff --git a/src/core/support/thd_internal.h b/src/core/support/thd_internal.h
deleted file mode 100644
index 1508c46..0000000
--- a/src/core/support/thd_internal.h
+++ /dev/null
@@ -1,39 +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_SUPPORT_THD_INTERNAL_H
-#define GRPC_INTERNAL_CORE_SUPPORT_THD_INTERNAL_H
-
-/* Internal interfaces between modules within the gpr support library.  */
-
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_THD_INTERNAL_H */
diff --git a/src/core/support/thd_posix.c b/src/core/support/thd_posix.c
deleted file mode 100644
index 653a1c8..0000000
--- a/src/core/support/thd_posix.c
+++ /dev/null
@@ -1,94 +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.
- *
- */
-
-/* Posix implementation for gpr threads. */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SYNC
-
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
-
-struct thd_arg {
-  void (*body)(void *arg); /* body of a thread */
-  void *arg;               /* argument to a thread */
-};
-
-/* Body of every thread started via gpr_thd_new. */
-static void *thread_body(void *v) {
-  struct thd_arg a = *(struct thd_arg *)v;
-  free(v);
-  (*a.body)(a.arg);
-  return NULL;
-}
-
-int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
-                const gpr_thd_options *options) {
-  int thread_started;
-  pthread_attr_t attr;
-  pthread_t p;
-  /* don't use gpr_malloc as we may cause an infinite recursion with
-   * the profiling code */
-  struct thd_arg *a = malloc(sizeof(*a));
-  GPR_ASSERT(a != NULL);
-  a->body = thd_body;
-  a->arg = arg;
-
-  GPR_ASSERT(pthread_attr_init(&attr) == 0);
-  if (gpr_thd_options_is_detached(options)) {
-    GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) ==
-               0);
-  } else {
-    GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
-               0);
-  }
-  thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
-  GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
-  if (!thread_started) {
-    free(a);
-  }
-  *t = (gpr_thd_id)p;
-  return thread_started;
-}
-
-gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }
-
-void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, NULL); }
-
-#endif /* GPR_POSIX_SYNC */
diff --git a/src/core/support/thd_win32.c b/src/core/support/thd_win32.c
deleted file mode 100644
index a9db180..0000000
--- a/src/core/support/thd_win32.c
+++ /dev/null
@@ -1,117 +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.
- *
- */
-
-/* Windows implementation for gpr threads. */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WIN32
-
-#include <string.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/thd.h>
-
-#if defined(_MSC_VER)
-#define thread_local __declspec(thread)
-#elif defined(__GNUC__)
-#define thread_local __thread
-#else
-#error "Unknown compiler - please file a bug report"
-#endif
-
-struct thd_info {
-  void (*body)(void *arg); /* body of a thread */
-  void *arg;               /* argument to a thread */
-  HANDLE join_event;       /* if joinable, the join event */
-  int joinable;            /* true if not detached */
-};
-
-static thread_local struct thd_info *g_thd_info;
-
-/* Destroys a thread info */
-static void destroy_thread(struct thd_info *t) {
-  if (t->joinable) CloseHandle(t->join_event);
-  gpr_free(t);
-}
-
-/* Body of every thread started via gpr_thd_new. */
-static DWORD WINAPI thread_body(void *v) {
-  g_thd_info = (struct thd_info *)v;
-  g_thd_info->body(g_thd_info->arg);
-  if (g_thd_info->joinable) {
-    BOOL ret = SetEvent(g_thd_info->join_event);
-    GPR_ASSERT(ret);
-  } else {
-    destroy_thread(g_thd_info);
-  }
-  return 0;
-}
-
-int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
-                const gpr_thd_options *options) {
-  HANDLE handle;
-  struct thd_info *info = gpr_malloc(sizeof(*info));
-  info->body = thd_body;
-  info->arg = arg;
-  *t = 0;
-  if (gpr_thd_options_is_joinable(options)) {
-    info->joinable = 1;
-    info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (info->join_event == NULL) {
-      gpr_free(info);
-      return 0;
-    }
-  } else {
-    info->joinable = 0;
-  }
-  handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL);
-  if (handle == NULL) {
-    destroy_thread(info);
-  } else {
-    *t = (gpr_thd_id)info;
-    CloseHandle(handle);
-  }
-  return handle != NULL;
-}
-
-gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }
-
-void gpr_thd_join(gpr_thd_id t) {
-  struct thd_info *info = (struct thd_info *)t;
-  DWORD ret = WaitForSingleObject(info->join_event, INFINITE);
-  GPR_ASSERT(ret == WAIT_OBJECT_0);
-  destroy_thread(info);
-}
-
-#endif /* GPR_WIN32 */
diff --git a/src/core/support/time.c b/src/core/support/time.c
deleted file mode 100644
index 423d12f..0000000
--- a/src/core/support/time.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* Generic implementation of time calls. */
-
-#include <grpc/support/time.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <grpc/support/log.h>
-
-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);
-  }
-  return cmp;
-}
-
-gpr_timespec gpr_time_min(gpr_timespec a, gpr_timespec b) {
-  return gpr_time_cmp(a, b) < 0 ? a : b;
-}
-
-gpr_timespec gpr_time_max(gpr_timespec a, gpr_timespec b) {
-  return gpr_time_cmp(a, b) > 0 ? a : b;
-}
-
-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 = INT64_MAX;
-  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 = INT64_MIN;
-  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(int64_t ns, gpr_clock_type type) {
-  gpr_timespec result;
-  result.clock_type = type;
-  if (ns == INT64_MAX) {
-    result = gpr_inf_future(type);
-  } else if (ns == INT64_MIN) {
-    result = gpr_inf_past(type);
-  } else if (ns >= 0) {
-    result.tv_sec = ns / GPR_NS_PER_SEC;
-    result.tv_nsec = (int32_t)(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 = (int32_t)(ns - result.tv_sec * GPR_NS_PER_SEC);
-  }
-  return result;
-}
-
-gpr_timespec gpr_time_from_micros(int64_t us, gpr_clock_type type) {
-  gpr_timespec result;
-  result.clock_type = type;
-  if (us == INT64_MAX) {
-    result = gpr_inf_future(type);
-  } else if (us == INT64_MIN) {
-    result = gpr_inf_past(type);
-  } else if (us >= 0) {
-    result.tv_sec = us / 1000000;
-    result.tv_nsec = (int32_t)((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 = (int32_t)((us - result.tv_sec * 1000000) * 1000);
-  }
-  return result;
-}
-
-gpr_timespec gpr_time_from_millis(int64_t ms, gpr_clock_type type) {
-  gpr_timespec result;
-  result.clock_type = type;
-  if (ms == INT64_MAX) {
-    result = gpr_inf_future(type);
-  } else if (ms == INT64_MIN) {
-    result = gpr_inf_past(type);
-  } else if (ms >= 0) {
-    result.tv_sec = ms / 1000;
-    result.tv_nsec = (int32_t)((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 = (int32_t)((ms - result.tv_sec * 1000) * 1000000);
-  }
-  return result;
-}
-
-gpr_timespec gpr_time_from_seconds(int64_t s, gpr_clock_type type) {
-  gpr_timespec result;
-  result.clock_type = type;
-  if (s == INT64_MAX) {
-    result = gpr_inf_future(type);
-  } else if (s == INT64_MIN) {
-    result = gpr_inf_past(type);
-  } else {
-    result.tv_sec = s;
-    result.tv_nsec = 0;
-  }
-  return result;
-}
-
-gpr_timespec gpr_time_from_minutes(int64_t m, gpr_clock_type type) {
-  gpr_timespec result;
-  result.clock_type = type;
-  if (m >= INT64_MAX / 60) {
-    result = gpr_inf_future(type);
-  } else if (m <= INT64_MIN / 60) {
-    result = gpr_inf_past(type);
-  } else {
-    result.tv_sec = m * 60;
-    result.tv_nsec = 0;
-  }
-  return result;
-}
-
-gpr_timespec gpr_time_from_hours(int64_t h, gpr_clock_type type) {
-  gpr_timespec result;
-  result.clock_type = type;
-  if (h >= INT64_MAX / 3600) {
-    result = gpr_inf_future(type);
-  } else if (h <= INT64_MIN / 3600) {
-    result = gpr_inf_past(type);
-  } else {
-    result.tv_sec = h * 3600;
-    result.tv_nsec = 0;
-  }
-  return result;
-}
-
-gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
-  gpr_timespec sum;
-  int64_t 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;
-    inc++;
-  }
-  if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) {
-    sum = a;
-  } else if (b.tv_sec == INT64_MAX ||
-             (b.tv_sec >= 0 && a.tv_sec >= INT64_MAX - b.tv_sec)) {
-    sum = gpr_inf_future(sum.clock_type);
-  } else if (b.tv_sec == INT64_MIN ||
-             (b.tv_sec <= 0 && a.tv_sec <= INT64_MIN - b.tv_sec)) {
-    sum = gpr_inf_past(sum.clock_type);
-  } else {
-    sum.tv_sec = a.tv_sec + b.tv_sec;
-    if (inc != 0 && sum.tv_sec == INT64_MAX - 1) {
-      sum = gpr_inf_future(sum.clock_type);
-    } else {
-      sum.tv_sec += inc;
-    }
-  }
-  return sum;
-}
-
-gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) {
-  gpr_timespec diff;
-  int64_t 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;
-    dec++;
-  }
-  if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) {
-    diff = a;
-  } else if (b.tv_sec == INT64_MIN ||
-             (b.tv_sec <= 0 && a.tv_sec >= INT64_MAX + b.tv_sec)) {
-    diff = gpr_inf_future(GPR_CLOCK_REALTIME);
-  } else if (b.tv_sec == INT64_MAX ||
-             (b.tv_sec >= 0 && a.tv_sec <= INT64_MIN + b.tv_sec)) {
-    diff = gpr_inf_past(GPR_CLOCK_REALTIME);
-  } else {
-    diff.tv_sec = a.tv_sec - b.tv_sec;
-    if (dec != 0 && diff.tv_sec == INT64_MIN + 1) {
-      diff = gpr_inf_past(GPR_CLOCK_REALTIME);
-    } else {
-      diff.tv_sec -= dec;
-    }
-  }
-  return diff;
-}
-
-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) {
-    return gpr_time_cmp(gpr_time_sub(b, a), threshold) <= 0;
-  } else {
-    return gpr_time_cmp(gpr_time_sub(a, b), threshold) <= 0;
-  }
-}
-
-int32_t gpr_time_to_millis(gpr_timespec t) {
-  if (t.tv_sec >= 2147483) {
-    if (t.tv_sec == 2147483 && t.tv_nsec < 648 * GPR_NS_PER_MS) {
-      return 2147483 * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS;
-    }
-    return 2147483647;
-  } else if (t.tv_sec <= -2147483) {
-    /* TODO(ctiller): correct handling here (it's so far in the past do we
-       care?) */
-    return -2147483647;
-  } else {
-    return (int32_t)(t.tv_sec * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS);
-  }
-}
-
-double gpr_timespec_to_micros(gpr_timespec t) {
-  return (double)t.tv_sec * GPR_US_PER_SEC + t.tv_nsec * 1e-3;
-}
-
-gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) {
-  if (t.clock_type == clock_type) {
-    return t;
-  }
-
-  if (t.tv_nsec == 0) {
-    if (t.tv_sec == INT64_MAX) {
-      t.clock_type = clock_type;
-      return t;
-    }
-    if (t.tv_sec == INT64_MIN) {
-      t.clock_type = clock_type;
-      return t;
-    }
-  }
-
-  if (clock_type == GPR_TIMESPAN) {
-    return gpr_time_sub(t, gpr_now(t.clock_type));
-  }
-
-  if (t.clock_type == GPR_TIMESPAN) {
-    return gpr_time_add(gpr_now(clock_type), t);
-  }
-
-  return gpr_time_add(gpr_now(clock_type),
-                      gpr_time_sub(t, gpr_now(t.clock_type)));
-}
diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c
deleted file mode 100644
index 36d75e7..0000000
--- a/src/core/support/time_posix.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-#include <src/core/support/time_precise.h>
-
-#ifdef GPR_POSIX_TIME
-
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-#ifdef __linux__
-#include <sys/syscall.h>
-#endif
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
-#include "src/core/support/block_annotate.h"
-
-static struct timespec timespec_from_gpr(gpr_timespec gts) {
-  struct timespec rv;
-  if (sizeof(time_t) < sizeof(int64_t)) {
-    /* fine to assert, as this is only used in gpr_sleep_until */
-    GPR_ASSERT(gts.tv_sec <= INT32_MAX && gts.tv_sec >= INT32_MIN);
-  }
-  rv.tv_sec = (time_t)gts.tv_sec;
-  rv.tv_nsec = gts.tv_nsec;
-  return rv;
-}
-
-#if _POSIX_TIMERS > 0
-static gpr_timespec gpr_from_timespec(struct timespec ts,
-                                      gpr_clock_type clock_type) {
-  /*
-   * timespec.tv_sec can have smaller size than gpr_timespec.tv_sec,
-   * but we are only using this function to implement gpr_now
-   * so there's no need to handle "infinity" values.
-   */
-  gpr_timespec rv;
-  rv.tv_sec = ts.tv_sec;
-  rv.tv_nsec = (int32_t)ts.tv_nsec;
-  rv.clock_type = clock_type;
-  return rv;
-}
-
-/** maps gpr_clock_type --> clockid_t for clock_gettime */
-static const clockid_t clockid_for_gpr_clock[] = {CLOCK_MONOTONIC,
-                                                  CLOCK_REALTIME};
-
-void gpr_time_init(void) { gpr_precise_clock_init(); }
-
-gpr_timespec gpr_now(gpr_clock_type clock_type) {
-  struct timespec now;
-  GPR_ASSERT(clock_type != GPR_TIMESPAN);
-  if (clock_type == GPR_CLOCK_PRECISE) {
-    gpr_timespec ret;
-    gpr_precise_clock_now(&ret);
-    return ret;
-  } else {
-#if defined(GPR_BACKWARDS_COMPATIBILITY_MODE) && defined(__linux__)
-    /* avoid ABI problems by invoking syscalls directly */
-    syscall(SYS_clock_gettime, clockid_for_gpr_clock[clock_type], &now);
-#else
-    clock_gettime(clockid_for_gpr_clock[clock_type], &now);
-#endif
-    return gpr_from_timespec(now, clock_type);
-  }
-}
-#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>
-
-static double g_time_scale;
-static uint64_t g_time_start;
-
-void gpr_time_init(void) {
-  mach_timebase_info_data_t tb = {0, 1};
-  gpr_precise_clock_init();
-  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;
-  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 = (int64_t)(now_dbl * 1e-9);
-      now.tv_nsec = (int32_t)(now_dbl - ((double)now.tv_sec) * 1e9);
-      break;
-    case GPR_CLOCK_PRECISE:
-      gpr_precise_clock_now(&now);
-      break;
-    case GPR_TIMESPAN:
-      abort();
-  }
-
-  return now;
-}
-#endif
-
-void gpr_sleep_until(gpr_timespec until) {
-  gpr_timespec now;
-  gpr_timespec delta;
-  struct timespec delta_ts;
-  int ns_result;
-
-  for (;;) {
-    /* We could simplify by using clock_nanosleep instead, but it might be
-     * slightly less portable. */
-    now = gpr_now(until.clock_type);
-    if (gpr_time_cmp(until, now) <= 0) {
-      return;
-    }
-
-    delta = gpr_time_sub(until, now);
-    delta_ts = timespec_from_gpr(delta);
-    GRPC_SCHEDULING_START_BLOCKING_REGION;
-    ns_result = nanosleep(&delta_ts, NULL);
-    GRPC_SCHEDULING_END_BLOCKING_REGION;
-    if (ns_result == 0) {
-      break;
-    }
-  }
-}
-
-#endif /* GPR_POSIX_TIME */
diff --git a/src/core/support/time_precise.c b/src/core/support/time_precise.c
deleted file mode 100644
index a2cf74b..0000000
--- a/src/core/support/time_precise.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 <grpc/support/log.h>
-#include <grpc/support/time.h>
-#include <stdio.h>
-
-#ifdef GRPC_TIMERS_RDTSC
-#if defined(__i386__)
-static void gpr_get_cycle_counter(long long int *clk) {
-  long long int ret;
-  __asm__ volatile("rdtsc" : "=A"(ret));
-  *clk = ret;
-}
-
-// ----------------------------------------------------------------
-#elif defined(__x86_64__) || defined(__amd64__)
-static void gpr_get_cycle_counter(long long int *clk) {
-  unsigned long long low, high;
-  __asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
-  *clk = (long long)(high << 32) | (long long)low;
-}
-#endif
-
-static double cycles_per_second = 0;
-static long long int start_cycle;
-void gpr_precise_clock_init(void) {
-  time_t start;
-  long long end_cycle;
-  gpr_log(GPR_DEBUG, "Calibrating timers");
-  start = time(NULL);
-  while (time(NULL) == start)
-    ;
-  gpr_get_cycle_counter(&start_cycle);
-  while (time(NULL) <= start + 10)
-    ;
-  gpr_get_cycle_counter(&end_cycle);
-  cycles_per_second = (double)(end_cycle - start_cycle) / 10.0;
-  gpr_log(GPR_DEBUG, "... cycles_per_second = %f\n", cycles_per_second);
-}
-
-void gpr_precise_clock_now(gpr_timespec *clk) {
-  long long int counter;
-  double secs;
-  gpr_get_cycle_counter(&counter);
-  secs = (double)(counter - start_cycle) / cycles_per_second;
-  clk->clock_type = GPR_CLOCK_PRECISE;
-  clk->tv_sec = (int64_t)secs;
-  clk->tv_nsec = (int32_t)(1e9 * (secs - (double)clk->tv_sec));
-}
-
-#else  /* GRPC_TIMERS_RDTSC */
-void gpr_precise_clock_init(void) {}
-
-void gpr_precise_clock_now(gpr_timespec *clk) {
-  *clk = gpr_now(GPR_CLOCK_REALTIME);
-  clk->clock_type = GPR_CLOCK_PRECISE;
-}
-#endif /* GRPC_TIMERS_RDTSC */
diff --git a/src/core/support/time_precise.h b/src/core/support/time_precise.h
deleted file mode 100644
index 80c5000..0000000
--- a/src/core/support/time_precise.h
+++ /dev/null
@@ -1,42 +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_CORE_SUPPORT_TIME_PRECISE_H_
-#define GRPC_CORE_SUPPORT_TIME_PRECISE_H_
-
-#include <grpc/support/time.h>
-
-void gpr_precise_clock_init(void);
-void gpr_precise_clock_now(gpr_timespec *clk);
-
-#endif /* GRPC_CORE_SUPPORT_TIME_PRECISE_ */
diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c
deleted file mode 100644
index 8af957e..0000000
--- a/src/core/support/time_win32.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* Win32 code for gpr time support. */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WIN32
-
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
-#include <src/core/support/time_precise.h>
-#include <sys/timeb.h>
-#include <process.h>
-#include <limits.h>
-
-#include "src/core/support/block_annotate.h"
-
-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 / (double)frequency.QuadPart;
-}
-
-gpr_timespec gpr_now(gpr_clock_type clock) {
-  gpr_timespec now_tv;
-  LONGLONG diff;
-  struct _timeb now_tb;
-  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 = (int64_t)now_tb.time;
-      now_tv.tv_nsec = now_tb.millitm * 1000000;
-      break;
-    case GPR_CLOCK_MONOTONIC:
-    case GPR_CLOCK_PRECISE:
-      QueryPerformanceCounter(&timestamp);
-      diff = timestamp.QuadPart - g_start_time.QuadPart;
-      now_dbl = (double)diff * g_time_scale;
-      now_tv.tv_sec = (int64_t)now_dbl;
-      now_tv.tv_nsec = (int32_t)((now_dbl - (double)now_tv.tv_sec) * 1e9);
-      break;
-    case GPR_TIMESPAN:
-      abort();
-      break;
-  }
-  return now_tv;
-}
-
-void gpr_sleep_until(gpr_timespec until) {
-  gpr_timespec now;
-  gpr_timespec delta;
-  int64_t sleep_millis;
-
-  for (;;) {
-    /* We could simplify by using clock_nanosleep instead, but it might be
-     * slightly less portable. */
-    now = gpr_now(until.clock_type);
-    if (gpr_time_cmp(until, now) <= 0) {
-      return;
-    }
-
-    delta = gpr_time_sub(until, now);
-    sleep_millis =
-        delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
-    GPR_ASSERT((sleep_millis >= 0) && (sleep_millis <= INT_MAX));
-    GRPC_SCHEDULING_START_BLOCKING_REGION;
-    Sleep((DWORD)sleep_millis);
-    GRPC_SCHEDULING_END_BLOCKING_REGION;
-  }
-}
-
-#endif /* GPR_WIN32 */
diff --git a/src/core/support/tls_pthread.c b/src/core/support/tls_pthread.c
deleted file mode 100644
index 9683a6e..0000000
--- a/src/core/support/tls_pthread.c
+++ /dev/null
@@ -1,45 +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/support/port_platform.h>
-
-#ifdef GPR_PTHREAD_TLS
-
-#include <grpc/support/tls.h>
-
-intptr_t gpr_tls_set(struct gpr_pthread_thread_local *tls, intptr_t value) {
-  GPR_ASSERT(0 == pthread_setspecific(tls->key, (void *)value));
-  return value;
-}
-
-#endif /* GPR_PTHREAD_TLS */
diff --git a/src/core/support/tmpfile.h b/src/core/support/tmpfile.h
deleted file mode 100644
index cecc71e..0000000
--- a/src/core/support/tmpfile.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_SUPPORT_TMPFILE_H
-#define GRPC_INTERNAL_CORE_SUPPORT_TMPFILE_H
-
-#include <stdio.h>
-
-#include <grpc/support/slice.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Creates a temporary file from a prefix.
-   If tmp_filename is not NULL, *tmp_filename is assigned the name of the
-   created file and it is the responsibility of the caller to gpr_free it
-   unless an error occurs in which case it will be set to NULL. */
-FILE *gpr_tmpfile(const char *prefix, char **tmp_filename);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_SUPPORT_TMPFILE_H */
diff --git a/src/core/support/tmpfile_posix.c b/src/core/support/tmpfile_posix.c
deleted file mode 100644
index b16eeac..0000000
--- a/src/core/support/tmpfile_posix.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_FILE
-
-#include "src/core/support/tmpfile.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/support/string.h"
-
-FILE *gpr_tmpfile(const char *prefix, char **tmp_filename) {
-  FILE *result = NULL;
-  char *template;
-  int fd;
-
-  if (tmp_filename != NULL) *tmp_filename = NULL;
-
-  gpr_asprintf(&template, "/tmp/%s_XXXXXX", prefix);
-  GPR_ASSERT(template != NULL);
-
-  fd = mkstemp(template);
-  if (fd == -1) {
-    gpr_log(GPR_ERROR, "mkstemp failed for template %s with error %s.",
-            template, strerror(errno));
-    goto end;
-  }
-  result = fdopen(fd, "w+");
-  if (result == NULL) {
-    gpr_log(GPR_ERROR, "Could not open file %s from fd %d (error = %s).",
-            template, fd, strerror(errno));
-    unlink(template);
-    close(fd);
-    goto end;
-  }
-
-end:
-  if (result != NULL && tmp_filename != NULL) {
-    *tmp_filename = template;
-  } else {
-    gpr_free(template);
-  }
-  return result;
-}
-
-#endif /* GPR_POSIX_FILE */
diff --git a/src/core/support/tmpfile_win32.c b/src/core/support/tmpfile_win32.c
deleted file mode 100644
index 3000f00..0000000
--- a/src/core/support/tmpfile_win32.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WIN32
-
-#include <io.h>
-#include <stdio.h>
-#include <string.h>
-#include <tchar.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/support/string_win32.h"
-#include "src/core/support/tmpfile.h"
-
-FILE *gpr_tmpfile(const char *prefix, char **tmp_filename_out) {
-  FILE *result = NULL;
-  LPTSTR template_string = NULL;
-  TCHAR tmp_path[MAX_PATH];
-  TCHAR tmp_filename[MAX_PATH];
-  DWORD status;
-  UINT success;
-
-  if (tmp_filename_out != NULL) *tmp_filename_out = NULL;
-
-  /* Convert our prefix to TCHAR. */
-  template_string = gpr_char_to_tchar(prefix);
-  GPR_ASSERT(template_string);
-
-  /* Get the path to the best temporary folder available. */
-  status = GetTempPath(MAX_PATH, tmp_path);
-  if (status == 0 || status > MAX_PATH) goto end;
-
-  /* Generate a unique filename with our template + temporary path. */
-  success = GetTempFileName(tmp_path, template_string, 0, tmp_filename);
-  if (!success) goto end;
-
-  /* Open a file there. */
-  if (_tfopen_s(&result, tmp_filename, TEXT("wb+")) != 0) goto end;
-
-end:
-  if (result && tmp_filename_out) {
-    *tmp_filename_out = gpr_tchar_to_char(tmp_filename);
-  }
-
-  gpr_free(template_string);
-  return result;
-}
-
-#endif /* GPR_WIN32 */
diff --git a/src/core/surface/alarm.c b/src/core/surface/alarm.c
deleted file mode 100644
index 8169ede..0000000
--- a/src/core/surface/alarm.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/iomgr/timer.h"
-#include "src/core/surface/completion_queue.h"
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-
-struct grpc_alarm {
-  grpc_timer alarm;
-  grpc_cq_completion completion;
-  /** completion queue where events about this alarm will be posted */
-  grpc_completion_queue *cq;
-  /** user supplied tag */
-  void *tag;
-};
-
-static void do_nothing_end_completion(grpc_exec_ctx *exec_ctx, void *arg,
-                                      grpc_cq_completion *c) {}
-
-static void alarm_cb(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  grpc_alarm *alarm = arg;
-  grpc_cq_end_op(exec_ctx, alarm->cq, alarm->tag, success,
-                 do_nothing_end_completion, NULL, &alarm->completion);
-}
-
-grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq, gpr_timespec deadline,
-                              void *tag) {
-  grpc_alarm *alarm = gpr_malloc(sizeof(grpc_alarm));
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  GRPC_CQ_INTERNAL_REF(cq, "alarm");
-  alarm->cq = cq;
-  alarm->tag = tag;
-
-  grpc_cq_begin_op(cq, tag);
-  grpc_timer_init(&exec_ctx, &alarm->alarm,
-                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  alarm_cb, alarm, gpr_now(GPR_CLOCK_MONOTONIC));
-  grpc_exec_ctx_finish(&exec_ctx);
-  return alarm;
-}
-
-void grpc_alarm_cancel(grpc_alarm *alarm) {
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_timer_cancel(&exec_ctx, &alarm->alarm);
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-void grpc_alarm_destroy(grpc_alarm *alarm) {
-  grpc_alarm_cancel(alarm);
-  GRPC_CQ_INTERNAL_UNREF(alarm->cq, "alarm");
-  gpr_free(alarm);
-}
diff --git a/src/core/surface/api_trace.c b/src/core/surface/api_trace.c
deleted file mode 100644
index 9f0b900..0000000
--- a/src/core/surface/api_trace.c
+++ /dev/null
@@ -1,36 +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/api_trace.h"
-
-int grpc_api_trace = 0;
diff --git a/src/core/surface/api_trace.h b/src/core/surface/api_trace.h
deleted file mode 100644
index 82bbf3b..0000000
--- a/src/core/surface/api_trace.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_SURFACE_API_TRACE_H
-#define GRPC_INTERNAL_CORE_SURFACE_API_TRACE_H
-
-#include "src/core/debug/trace.h"
-#include <grpc/support/log.h>
-
-extern int grpc_api_trace;
-
-/* Provide unwrapping macros because we're in C89 and variadic macros weren't
-   introduced until C99... */
-#define GRPC_API_TRACE_UNWRAP0()
-#define GRPC_API_TRACE_UNWRAP1(a) , a
-#define GRPC_API_TRACE_UNWRAP2(a, b) , a, b
-#define GRPC_API_TRACE_UNWRAP3(a, b, c) , a, b, c
-#define GRPC_API_TRACE_UNWRAP4(a, b, c, d) , a, b, c, d
-#define GRPC_API_TRACE_UNWRAP5(a, b, c, d, e) , a, b, c, d, e
-#define GRPC_API_TRACE_UNWRAP6(a, b, c, d, e, f) , a, b, c, d, e, f
-#define GRPC_API_TRACE_UNWRAP7(a, b, c, d, e, f, g) , a, b, c, d, e, f, g
-#define GRPC_API_TRACE_UNWRAP8(a, b, c, d, e, f, g, h) , a, b, c, d, e, f, g, h
-#define GRPC_API_TRACE_UNWRAP9(a, b, c, d, e, f, g, h, i) \
-  , a, b, c, d, e, f, g, h, i
-#define GRPC_API_TRACE_UNWRAP10(a, b, c, d, e, f, g, h, i, j) \
-  , a, b, c, d, e, f, g, h, i, j
-
-/* Due to the limitations of C89's preprocessor, the arity of the var-arg list
-   'nargs' must be specified. */
-#define GRPC_API_TRACE(fmt, nargs, args)                      \
-  if (grpc_api_trace) {                                       \
-    gpr_log(GPR_INFO, fmt GRPC_API_TRACE_UNWRAP##nargs args); \
-  }
-
-#endif /* GRPC_INTERNAL_CORE_SURFACE_API_TRACE_H */
diff --git a/src/core/surface/byte_buffer.c b/src/core/surface/byte_buffer.c
deleted file mode 100644
index fb39c45..0000000
--- a/src/core/surface/byte_buffer.c
+++ /dev/null
@@ -1,97 +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/byte_buffer.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-grpc_byte_buffer *grpc_raw_byte_buffer_create(gpr_slice *slices,
-                                              size_t nslices) {
-  return grpc_raw_compressed_byte_buffer_create(slices, nslices,
-                                                GRPC_COMPRESS_NONE);
-}
-
-grpc_byte_buffer *grpc_raw_compressed_byte_buffer_create(
-    gpr_slice *slices, size_t nslices, grpc_compression_algorithm compression) {
-  size_t i;
-  grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer));
-  bb->type = GRPC_BB_RAW;
-  bb->data.raw.compression = compression;
-  gpr_slice_buffer_init(&bb->data.raw.slice_buffer);
-  for (i = 0; i < nslices; i++) {
-    gpr_slice_ref(slices[i]);
-    gpr_slice_buffer_add(&bb->data.raw.slice_buffer, slices[i]);
-  }
-  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:
-      return grpc_raw_byte_buffer_create(bb->data.raw.slice_buffer.slices,
-                                         bb->data.raw.slice_buffer.count);
-  }
-  GPR_UNREACHABLE_CODE(return NULL);
-}
-
-void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) {
-  if (!bb) return;
-  switch (bb->type) {
-    case GRPC_BB_RAW:
-      gpr_slice_buffer_destroy(&bb->data.raw.slice_buffer);
-      break;
-  }
-  free(bb);
-}
-
-size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) {
-  switch (bb->type) {
-    case GRPC_BB_RAW:
-      return bb->data.raw.slice_buffer.length;
-  }
-  GPR_UNREACHABLE_CODE(return 0);
-}
diff --git a/src/core/surface/byte_buffer_reader.c b/src/core/surface/byte_buffer_reader.c
deleted file mode 100644
index 4679854..0000000
--- a/src/core/surface/byte_buffer_reader.c
+++ /dev/null
@@ -1,123 +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 <string.h>
-#include <grpc/byte_buffer_reader.h>
-
-#include <grpc/compression.h>
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
-#include <grpc/byte_buffer.h>
-
-#include "src/core/compression/message_compress.h"
-
-static int is_compressed(grpc_byte_buffer *buffer) {
-  switch (buffer->type) {
-    case GRPC_BB_RAW:
-      if (buffer->data.raw.compression == GRPC_COMPRESS_NONE) {
-        return 0 /* GPR_FALSE */;
-      }
-      break;
-  }
-  return 1 /* GPR_TRUE */;
-}
-
-void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
-                                  grpc_byte_buffer *buffer) {
-  gpr_slice_buffer decompressed_slices_buffer;
-  reader->buffer_in = buffer;
-  switch (reader->buffer_in->type) {
-    case GRPC_BB_RAW:
-      gpr_slice_buffer_init(&decompressed_slices_buffer);
-      if (is_compressed(reader->buffer_in)) {
-        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);
-        gpr_slice_buffer_destroy(&decompressed_slices_buffer);
-      } else { /* not compressed, use the input buffer as output */
-        reader->buffer_out = reader->buffer_in;
-      }
-      reader->current.index = 0;
-      break;
-  }
-}
-
-void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) {
-  switch (reader->buffer_in->type) {
-    case GRPC_BB_RAW:
-      /* keeping the same if-else structure as in the init function */
-      if (is_compressed(reader->buffer_in)) {
-        grpc_byte_buffer_destroy(reader->buffer_out);
-      }
-      break;
-  }
-}
-
-int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
-                                 gpr_slice *slice) {
-  switch (reader->buffer_in->type) {
-    case GRPC_BB_RAW: {
-      gpr_slice_buffer *slice_buffer;
-      slice_buffer = &reader->buffer_out->data.raw.slice_buffer;
-      if (reader->current.index < slice_buffer->count) {
-        *slice = gpr_slice_ref(slice_buffer->slices[reader->current.index]);
-        reader->current.index += 1;
-        return 1;
-      }
-      break;
-    }
-  }
-  return 0;
-}
-
-gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) {
-  gpr_slice in_slice;
-  size_t bytes_read = 0;
-  const size_t input_size = grpc_byte_buffer_length(reader->buffer_out);
-  gpr_slice out_slice = gpr_slice_malloc(input_size);
-  uint8_t *const outbuf = GPR_SLICE_START_PTR(out_slice); /* just an alias */
-
-  while (grpc_byte_buffer_reader_next(reader, &in_slice) != 0) {
-    const size_t slice_length = GPR_SLICE_LENGTH(in_slice);
-    memcpy(&(outbuf[bytes_read]), GPR_SLICE_START_PTR(in_slice), slice_length);
-    bytes_read += slice_length;
-    gpr_slice_unref(in_slice);
-    GPR_ASSERT(bytes_read <= input_size);
-  }
-  return out_slice;
-}
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
deleted file mode 100644
index 1b117aa..0000000
--- a/src/core/surface/call.c
+++ /dev/null
@@ -1,1483 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-#include <assert.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <grpc/compression.h>
-#include <grpc/grpc.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/channel_stack.h"
-#include "src/core/compression/algorithm_metadata.h"
-#include "src/core/iomgr/timer.h"
-#include "src/core/profiling/timers.h"
-#include "src/core/support/string.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/call.h"
-#include "src/core/surface/channel.h"
-#include "src/core/surface/completion_queue.h"
-#include "src/core/transport/static_metadata.h"
-
-/** The maximum number of concurrent batches 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_BATCHES 6
-
-typedef struct {
-  grpc_ioreq_completion_func on_complete;
-  void *user_data;
-  int success;
-} completed_request;
-
-#define MAX_SEND_EXTRA_METADATA_COUNT 3
-
-/* Status data for a request can come from several sources; this
-   enumerates them all, and acts as a priority sorting for which
-   status to return to the application - earlier entries override
-   later ones */
-typedef enum {
-  /* Status came from the application layer overriding whatever
-     the wire says */
-  STATUS_FROM_API_OVERRIDE = 0,
-  /* Status was created by some internal channel stack operation */
-  STATUS_FROM_CORE,
-  /* 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;
-
-typedef struct {
-  uint8_t is_set;
-  grpc_status_code code;
-  grpc_mdstr *details;
-} received_status;
-
-/* How far through the GRPC stream have we read? */
-typedef enum {
-  /* We are still waiting for initial metadata to complete */
-  READ_STATE_INITIAL = 0,
-  /* We have gotten initial metadata, and are reading either
-     messages or trailing metadata */
-  READ_STATE_GOT_INITIAL_METADATA,
-  /* The stream is closed for reading */
-  READ_STATE_READ_CLOSED,
-  /* The stream is closed for reading & writing */
-  READ_STATE_STREAM_CLOSED
-} read_state;
-
-typedef enum {
-  WRITE_STATE_INITIAL = 0,
-  WRITE_STATE_STARTED,
-  WRITE_STATE_WRITE_CLOSED
-} write_state;
-
-typedef struct batch_control {
-  grpc_call *call;
-  grpc_cq_completion cq_completion;
-  grpc_closure finish_batch;
-  void *notify_tag;
-  gpr_refcount steps_to_complete;
-
-  uint8_t send_initial_metadata;
-  uint8_t send_message;
-  uint8_t send_final_op;
-  uint8_t recv_initial_metadata;
-  uint8_t recv_message;
-  uint8_t recv_final_op;
-  uint8_t is_notify_tag_closure;
-  uint8_t success;
-} batch_control;
-
-struct grpc_call {
-  grpc_completion_queue *cq;
-  grpc_channel *channel;
-  grpc_call *parent;
-  grpc_call *first_child;
-  /* TODO(ctiller): share with cq if possible? */
-  gpr_mu mu;
-
-  /* client or server call */
-  uint8_t is_client;
-  /* is the alarm set */
-  uint8_t have_alarm;
-  /** has grpc_call_destroy been called */
-  uint8_t destroy_called;
-  /** flag indicating that cancellation is inherited */
-  uint8_t cancellation_is_inherited;
-  /** bitmask of live batches */
-  uint8_t used_batches;
-  /** which ops are in-flight */
-  uint8_t sent_initial_metadata;
-  uint8_t sending_message;
-  uint8_t sent_final_op;
-  uint8_t received_initial_metadata;
-  uint8_t receiving_message;
-  uint8_t received_final_op;
-
-  /* have we received initial metadata */
-  bool has_initial_md_been_received;
-
-  batch_control active_batches[MAX_CONCURRENT_BATCHES];
-
-  /* first idx: is_receiving, second idx: is_trailing */
-  grpc_metadata_batch metadata_batch[2][2];
-
-  /* Buffered read metadata waiting to be returned to the application.
-     Element 0 is initial metadata, element 1 is trailing metadata. */
-  grpc_metadata_array *buffered_metadata[2];
-
-  /* Received call statuses from various sources */
-  received_status status[STATUS_SOURCE_COUNT];
-
-  /* Compression algorithm for the call */
-  grpc_compression_algorithm compression_algorithm;
-  /* Supported encodings (compression algorithms), a bitset */
-  uint32_t encodings_accepted_by_peer;
-
-  /* Contexts for various subsystems (security, tracing, ...). */
-  grpc_call_context_element context[GRPC_CONTEXT_COUNT];
-
-  /* Deadline alarm - if have_alarm is non-zero */
-  grpc_timer alarm;
-
-  /* for the client, extra metadata is initial metadata; for the
-     server, it's trailing metadata */
-  grpc_linked_mdelem send_extra_metadata[MAX_SEND_EXTRA_METADATA_COUNT];
-  int send_extra_metadata_count;
-  gpr_timespec send_deadline;
-
-  /** siblings: children of the same parent form a list, and this list is
-     protected under
-      parent->mu */
-  grpc_call *sibling_next;
-  grpc_call *sibling_prev;
-
-  grpc_slice_buffer_stream sending_stream;
-  grpc_byte_stream *receiving_stream;
-  grpc_byte_buffer **receiving_buffer;
-  gpr_slice receiving_slice;
-  grpc_closure receiving_slice_ready;
-  grpc_closure receiving_stream_ready;
-  grpc_closure receiving_initial_metadata_ready;
-  uint32_t test_only_last_message_flags;
-
-  union {
-    struct {
-      grpc_status_code *status;
-      char **status_details;
-      size_t *status_details_capacity;
-    } client;
-    struct {
-      int *cancelled;
-    } server;
-  } final_op;
-
-  struct {
-    void *bctlp;
-    bool success;
-  } saved_receiving_stream_ready_ctx;
-};
-
-#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
-#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1)
-#define CALL_ELEM_FROM_CALL(call, idx) \
-  grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx)
-#define CALL_FROM_TOP_ELEM(top_elem) \
-  CALL_FROM_CALL_STACK(grpc_call_stack_from_top_element(top_elem))
-
-static void set_deadline_alarm(grpc_exec_ctx *exec_ctx, grpc_call *call,
-                               gpr_timespec deadline);
-static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
-                       grpc_transport_stream_op *op);
-static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
-                                          grpc_status_code status,
-                                          const char *description);
-static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack,
-                         bool success);
-static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
-                                  bool success);
-
-grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
-                            uint32_t propagation_mask,
-                            grpc_completion_queue *cq,
-                            const void *server_transport_data,
-                            grpc_mdelem **add_initial_metadata,
-                            size_t add_initial_metadata_count,
-                            gpr_timespec send_deadline) {
-  size_t i, j;
-  grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel);
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_call *call;
-  GPR_TIMER_BEGIN("grpc_call_create", 0);
-  call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
-  memset(call, 0, sizeof(grpc_call));
-  gpr_mu_init(&call->mu);
-  call->channel = channel;
-  call->cq = cq;
-  call->parent = parent_call;
-  call->is_client = server_transport_data == NULL;
-  if (call->is_client) {
-    GPR_ASSERT(add_initial_metadata_count < MAX_SEND_EXTRA_METADATA_COUNT);
-    for (i = 0; i < add_initial_metadata_count; i++) {
-      call->send_extra_metadata[i].md = add_initial_metadata[i];
-    }
-    call->send_extra_metadata_count = (int)add_initial_metadata_count;
-  } else {
-    GPR_ASSERT(add_initial_metadata_count == 0);
-    call->send_extra_metadata_count = 0;
-  }
-  for (i = 0; i < 2; i++) {
-    for (j = 0; j < 2; j++) {
-      call->metadata_batch[i][j].deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
-    }
-  }
-  call->send_deadline = send_deadline;
-  GRPC_CHANNEL_INTERNAL_REF(channel, "call");
-  /* initial refcount dropped by grpc_call_destroy */
-  grpc_call_stack_init(&exec_ctx, channel_stack, 1, destroy_call, call,
-                       call->context, server_transport_data,
-                       CALL_STACK_FROM_CALL(call));
-  if (cq != NULL) {
-    GRPC_CQ_INTERNAL_REF(cq, "bind");
-    grpc_call_stack_set_pollset(&exec_ctx, CALL_STACK_FROM_CALL(call),
-                                grpc_cq_pollset(cq));
-  }
-  if (parent_call != NULL) {
-    GRPC_CALL_INTERNAL_REF(parent_call, "child");
-    GPR_ASSERT(call->is_client);
-    GPR_ASSERT(!parent_call->is_client);
-
-    gpr_mu_lock(&parent_call->mu);
-
-    if (propagation_mask & GRPC_PROPAGATE_DEADLINE) {
-      send_deadline = gpr_time_min(
-          gpr_convert_clock_type(send_deadline,
-                                 parent_call->send_deadline.clock_type),
-          parent_call->send_deadline);
-    }
-    /* for now GRPC_PROPAGATE_TRACING_CONTEXT *MUST* be passed with
-     * GRPC_PROPAGATE_STATS_CONTEXT */
-    /* TODO(ctiller): This should change to use the appropriate census start_op
-     * call. */
-    if (propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) {
-      GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
-      grpc_call_context_set(call, GRPC_CONTEXT_TRACING,
-                            parent_call->context[GRPC_CONTEXT_TRACING].value,
-                            NULL);
-    } else {
-      GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
-    }
-    if (propagation_mask & GRPC_PROPAGATE_CANCELLATION) {
-      call->cancellation_is_inherited = 1;
-    }
-
-    if (parent_call->first_child == NULL) {
-      parent_call->first_child = call;
-      call->sibling_next = call->sibling_prev = call;
-    } else {
-      call->sibling_next = parent_call->first_child;
-      call->sibling_prev = parent_call->first_child->sibling_prev;
-      call->sibling_next->sibling_prev = call->sibling_prev->sibling_next =
-          call;
-    }
-
-    gpr_mu_unlock(&parent_call->mu);
-  }
-  if (gpr_time_cmp(send_deadline, gpr_inf_future(send_deadline.clock_type)) !=
-      0) {
-    set_deadline_alarm(&exec_ctx, call, send_deadline);
-  }
-  grpc_exec_ctx_finish(&exec_ctx);
-  GPR_TIMER_END("grpc_call_create", 0);
-  return call;
-}
-
-void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call,
-                                    grpc_completion_queue *cq) {
-  GPR_ASSERT(cq);
-  call->cq = cq;
-  GRPC_CQ_INTERNAL_REF(cq, "bind");
-  grpc_call_stack_set_pollset(exec_ctx, CALL_STACK_FROM_CALL(call),
-                              grpc_cq_pollset(cq));
-}
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-#define REF_REASON reason
-#define REF_ARG , const char *reason
-#else
-#define REF_REASON ""
-#define REF_ARG
-#endif
-void grpc_call_internal_ref(grpc_call *c REF_ARG) {
-  GRPC_CALL_STACK_REF(CALL_STACK_FROM_CALL(c), REF_REASON);
-}
-void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c REF_ARG) {
-  GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON);
-}
-
-static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, bool success) {
-  size_t i;
-  int ii;
-  grpc_call *c = call;
-  GPR_TIMER_BEGIN("destroy_call", 0);
-  for (i = 0; i < 2; i++) {
-    grpc_metadata_batch_destroy(
-        &c->metadata_batch[1 /* is_receiving */][i /* is_initial */]);
-  }
-  if (c->receiving_stream != NULL) {
-    grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
-  }
-  grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c));
-  GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->channel, "call");
-  gpr_mu_destroy(&c->mu);
-  for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
-    if (c->status[i].details) {
-      GRPC_MDSTR_UNREF(c->status[i].details);
-    }
-  }
-  for (ii = 0; ii < c->send_extra_metadata_count; ii++) {
-    GRPC_MDELEM_UNREF(c->send_extra_metadata[ii].md);
-  }
-  for (i = 0; i < GRPC_CONTEXT_COUNT; i++) {
-    if (c->context[i].destroy) {
-      c->context[i].destroy(c->context[i].value);
-    }
-  }
-  if (c->cq) {
-    GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
-  }
-  gpr_free(c);
-  GPR_TIMER_END("destroy_call", 0);
-}
-
-static void set_status_code(grpc_call *call, status_source source,
-                            uint32_t status) {
-  if (call->status[source].is_set) return;
-
-  call->status[source].is_set = 1;
-  call->status[source].code = (grpc_status_code)status;
-
-  /* TODO(ctiller): what to do about the flush that was previously here */
-}
-
-static void set_compression_algorithm(grpc_call *call,
-                                      grpc_compression_algorithm algo) {
-  call->compression_algorithm = algo;
-}
-
-grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm(
-    grpc_call *call) {
-  grpc_compression_algorithm algorithm;
-  gpr_mu_lock(&call->mu);
-  algorithm = call->compression_algorithm;
-  gpr_mu_unlock(&call->mu);
-  return algorithm;
-}
-
-uint32_t grpc_call_test_only_get_message_flags(grpc_call *call) {
-  uint32_t flags;
-  gpr_mu_lock(&call->mu);
-  flags = call->test_only_last_message_flags;
-  gpr_mu_unlock(&call->mu);
-  return flags;
-}
-
-static void destroy_encodings_accepted_by_peer(void *p) { return; }
-
-static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) {
-  size_t i;
-  grpc_compression_algorithm algorithm;
-  gpr_slice_buffer accept_encoding_parts;
-  gpr_slice accept_encoding_slice;
-  void *accepted_user_data;
-
-  accepted_user_data =
-      grpc_mdelem_get_user_data(mdel, destroy_encodings_accepted_by_peer);
-  if (accepted_user_data != NULL) {
-    call->encodings_accepted_by_peer =
-        (uint32_t)(((uintptr_t)accepted_user_data) - 1);
-    return;
-  }
-
-  accept_encoding_slice = mdel->value->slice;
-  gpr_slice_buffer_init(&accept_encoding_parts);
-  gpr_slice_split(accept_encoding_slice, ",", &accept_encoding_parts);
-
-  /* No need to zero call->encodings_accepted_by_peer: grpc_call_create already
-   * zeroes the whole grpc_call */
-  /* Always support no compression */
-  GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
-  for (i = 0; i < accept_encoding_parts.count; i++) {
-    const gpr_slice *accept_encoding_entry_slice =
-        &accept_encoding_parts.slices[i];
-    if (grpc_compression_algorithm_parse(
-            (const char *)GPR_SLICE_START_PTR(*accept_encoding_entry_slice),
-            GPR_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) {
-      GPR_BITSET(&call->encodings_accepted_by_peer, algorithm);
-    } else {
-      char *accept_encoding_entry_str =
-          gpr_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII);
-      gpr_log(GPR_ERROR,
-              "Invalid entry in accept encoding metadata: '%s'. Ignoring.",
-              accept_encoding_entry_str);
-      gpr_free(accept_encoding_entry_str);
-    }
-  }
-
-  gpr_slice_buffer_destroy(&accept_encoding_parts);
-
-  grpc_mdelem_set_user_data(
-      mdel, destroy_encodings_accepted_by_peer,
-      (void *)(((uintptr_t)call->encodings_accepted_by_peer) + 1));
-}
-
-uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) {
-  uint32_t encodings_accepted_by_peer;
-  gpr_mu_lock(&call->mu);
-  encodings_accepted_by_peer = call->encodings_accepted_by_peer;
-  gpr_mu_unlock(&call->mu);
-  return encodings_accepted_by_peer;
-}
-
-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);
-  }
-  call->status[source].details = status;
-}
-
-static void get_final_status(grpc_call *call,
-                             void (*set_value)(grpc_status_code code,
-                                               void *user_data),
-                             void *set_value_user_data) {
-  int i;
-  for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
-    if (call->status[i].is_set) {
-      set_value(call->status[i].code, set_value_user_data);
-      return;
-    }
-  }
-  if (call->is_client) {
-    set_value(GRPC_STATUS_UNKNOWN, set_value_user_data);
-  } else {
-    set_value(GRPC_STATUS_OK, set_value_user_data);
-  }
-}
-
-static void get_final_details(grpc_call *call, char **out_details,
-                              size_t *out_details_capacity) {
-  int i;
-  for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
-    if (call->status[i].is_set) {
-      if (call->status[i].details) {
-        gpr_slice details = call->status[i].details->slice;
-        size_t len = GPR_SLICE_LENGTH(details);
-        if (len + 1 > *out_details_capacity) {
-          *out_details_capacity =
-              GPR_MAX(len + 1, *out_details_capacity * 3 / 2);
-          *out_details = gpr_realloc(*out_details, *out_details_capacity);
-        }
-        memcpy(*out_details, GPR_SLICE_START_PTR(details), len);
-        (*out_details)[len] = 0;
-      } else {
-        goto no_details;
-      }
-      return;
-    }
-  }
-
-no_details:
-  if (0 == *out_details_capacity) {
-    *out_details_capacity = 8;
-    *out_details = gpr_malloc(*out_details_capacity);
-  }
-  **out_details = 0;
-}
-
-static grpc_linked_mdelem *linked_from_md(grpc_metadata *md) {
-  return (grpc_linked_mdelem *)&md->internal_data;
-}
-
-static int prepare_application_metadata(grpc_call *call, int count,
-                                        grpc_metadata *metadata,
-                                        int is_trailing,
-                                        int prepend_extra_metadata) {
-  int i;
-  grpc_metadata_batch *batch =
-      &call->metadata_batch[0 /* is_receiving */][is_trailing];
-  if (prepend_extra_metadata) {
-    if (call->send_extra_metadata_count == 0) {
-      prepend_extra_metadata = 0;
-    } else {
-      for (i = 0; i < call->send_extra_metadata_count; i++) {
-        GRPC_MDELEM_REF(call->send_extra_metadata[i].md);
-      }
-      for (i = 1; i < call->send_extra_metadata_count; i++) {
-        call->send_extra_metadata[i].prev = &call->send_extra_metadata[i - 1];
-      }
-      for (i = 0; i < call->send_extra_metadata_count - 1; i++) {
-        call->send_extra_metadata[i].next = &call->send_extra_metadata[i + 1];
-      }
-    }
-  }
-  for (i = 0; i < count; i++) {
-    grpc_metadata *md = &metadata[i];
-    grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
-    GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
-    l->md = grpc_mdelem_from_string_and_buffer(
-        md->key, (const uint8_t *)md->value, md->value_length);
-    if (!grpc_header_key_is_legal(grpc_mdstr_as_c_string(l->md->key),
-                                  GRPC_MDSTR_LENGTH(l->md->key))) {
-      gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s",
-              grpc_mdstr_as_c_string(l->md->key));
-      return 0;
-    } else if (!grpc_is_binary_header(grpc_mdstr_as_c_string(l->md->key),
-                                      GRPC_MDSTR_LENGTH(l->md->key)) &&
-               !grpc_header_nonbin_value_is_legal(
-                   grpc_mdstr_as_c_string(l->md->value),
-                   GRPC_MDSTR_LENGTH(l->md->value))) {
-      gpr_log(GPR_ERROR, "attempt to send invalid metadata value");
-      return 0;
-    }
-  }
-  for (i = 1; i < count; i++) {
-    linked_from_md(&metadata[i])->prev = linked_from_md(&metadata[i - 1]);
-  }
-  for (i = 0; i < count - 1; i++) {
-    linked_from_md(&metadata[i])->next = linked_from_md(&metadata[i + 1]);
-  }
-  switch (prepend_extra_metadata * 2 + (count != 0)) {
-    case 0:
-      /* no prepend, no metadata => nothing to do */
-      batch->list.head = batch->list.tail = NULL;
-      break;
-    case 1:
-      /* metadata, but no prepend */
-      batch->list.head = linked_from_md(&metadata[0]);
-      batch->list.tail = linked_from_md(&metadata[count - 1]);
-      batch->list.head->prev = NULL;
-      batch->list.tail->next = NULL;
-      break;
-    case 2:
-      /* prepend, but no md */
-      batch->list.head = &call->send_extra_metadata[0];
-      batch->list.tail =
-          &call->send_extra_metadata[call->send_extra_metadata_count - 1];
-      batch->list.head->prev = NULL;
-      batch->list.tail->next = NULL;
-      break;
-    case 3:
-      /* prepend AND md */
-      batch->list.head = &call->send_extra_metadata[0];
-      call->send_extra_metadata[call->send_extra_metadata_count - 1].next =
-          linked_from_md(&metadata[0]);
-      linked_from_md(&metadata[0])->prev =
-          &call->send_extra_metadata[call->send_extra_metadata_count - 1];
-      batch->list.tail = linked_from_md(&metadata[count - 1]);
-      batch->list.head->prev = NULL;
-      batch->list.tail->next = NULL;
-      break;
-    default:
-      GPR_UNREACHABLE_CODE(return 0);
-  }
-
-  return 1;
-}
-
-void grpc_call_destroy(grpc_call *c) {
-  int cancel;
-  grpc_call *parent = c->parent;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  GPR_TIMER_BEGIN("grpc_call_destroy", 0);
-  GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c));
-
-  if (parent) {
-    gpr_mu_lock(&parent->mu);
-    if (c == parent->first_child) {
-      parent->first_child = c->sibling_next;
-      if (c == parent->first_child) {
-        parent->first_child = NULL;
-      }
-      c->sibling_prev->sibling_next = c->sibling_next;
-      c->sibling_next->sibling_prev = c->sibling_prev;
-    }
-    gpr_mu_unlock(&parent->mu);
-    GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
-  }
-
-  gpr_mu_lock(&c->mu);
-  GPR_ASSERT(!c->destroy_called);
-  c->destroy_called = 1;
-  if (c->have_alarm) {
-    grpc_timer_cancel(&exec_ctx, &c->alarm);
-  }
-  cancel = !c->received_final_op;
-  gpr_mu_unlock(&c->mu);
-  if (cancel) grpc_call_cancel(c, NULL);
-  GRPC_CALL_INTERNAL_UNREF(&exec_ctx, c, "destroy");
-  grpc_exec_ctx_finish(&exec_ctx);
-  GPR_TIMER_END("grpc_call_destroy", 0);
-}
-
-grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) {
-  GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved));
-  GPR_ASSERT(!reserved);
-  return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled",
-                                      NULL);
-}
-
-grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
-                                             grpc_status_code status,
-                                             const char *description,
-                                             void *reserved) {
-  grpc_call_error r;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  GRPC_API_TRACE(
-      "grpc_call_cancel_with_status("
-      "c=%p, status=%d, description=%s, reserved=%p)",
-      4, (c, (int)status, description, reserved));
-  GPR_ASSERT(reserved == NULL);
-  gpr_mu_lock(&c->mu);
-  r = cancel_with_status(&exec_ctx, c, status, description);
-  gpr_mu_unlock(&c->mu);
-  grpc_exec_ctx_finish(&exec_ctx);
-  return r;
-}
-
-typedef struct cancel_closure {
-  grpc_closure closure;
-  grpc_call *call;
-  grpc_status_code status;
-} cancel_closure;
-
-static void done_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) {
-  cancel_closure *cc = ccp;
-  GRPC_CALL_INTERNAL_UNREF(exec_ctx, cc->call, "cancel");
-  gpr_free(cc);
-}
-
-static void send_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) {
-  grpc_transport_stream_op op;
-  cancel_closure *cc = ccp;
-  memset(&op, 0, sizeof(op));
-  op.cancel_with_status = cc->status;
-  /* reuse closure to catch completion */
-  grpc_closure_init(&cc->closure, done_cancel, cc);
-  op.on_complete = &cc->closure;
-  execute_op(exec_ctx, cc->call, &op);
-}
-
-static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
-                                          grpc_status_code status,
-                                          const char *description) {
-  grpc_mdstr *details =
-      description ? grpc_mdstr_from_string(description) : NULL;
-  cancel_closure *cc = gpr_malloc(sizeof(*cc));
-
-  GPR_ASSERT(status != GRPC_STATUS_OK);
-
-  set_status_code(c, STATUS_FROM_API_OVERRIDE, (uint32_t)status);
-  set_status_details(c, STATUS_FROM_API_OVERRIDE, details);
-
-  grpc_closure_init(&cc->closure, send_cancel, cc);
-  cc->call = c;
-  cc->status = status;
-  GRPC_CALL_INTERNAL_REF(c, "cancel");
-  grpc_exec_ctx_enqueue(exec_ctx, &cc->closure, true, NULL);
-
-  return GRPC_CALL_OK;
-}
-
-static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
-                       grpc_transport_stream_op *op) {
-  grpc_call_element *elem;
-
-  GPR_TIMER_BEGIN("execute_op", 0);
-  elem = CALL_ELEM_FROM_CALL(call, 0);
-  op->context = call->context;
-  elem->filter->start_transport_stream_op(exec_ctx, elem, op);
-  GPR_TIMER_END("execute_op", 0);
-}
-
-char *grpc_call_get_peer(grpc_call *call) {
-  grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0);
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  char *result;
-  GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call));
-  result = elem->filter->get_peer(&exec_ctx, elem);
-  if (result == NULL) {
-    result = grpc_channel_get_target(call->channel);
-  }
-  if (result == NULL) {
-    result = gpr_strdup("unknown");
-  }
-  grpc_exec_ctx_finish(&exec_ctx);
-  return result;
-}
-
-grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
-  return CALL_FROM_TOP_ELEM(elem);
-}
-
-static void call_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  grpc_call *call = arg;
-  gpr_mu_lock(&call->mu);
-  call->have_alarm = 0;
-  if (success) {
-    cancel_with_status(exec_ctx, call, GRPC_STATUS_DEADLINE_EXCEEDED,
-                       "Deadline Exceeded");
-  }
-  gpr_mu_unlock(&call->mu);
-  GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "alarm");
-}
-
-static void set_deadline_alarm(grpc_exec_ctx *exec_ctx, grpc_call *call,
-                               gpr_timespec deadline) {
-  if (call->have_alarm) {
-    gpr_log(GPR_ERROR, "Attempt to set deadline alarm twice");
-    assert(0);
-    return;
-  }
-  GRPC_CALL_INTERNAL_REF(call, "alarm");
-  call->have_alarm = 1;
-  call->send_deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
-  grpc_timer_init(exec_ctx, &call->alarm, call->send_deadline, call_alarm, call,
-                  gpr_now(GPR_CLOCK_MONOTONIC));
-}
-
-/* we offset status by a small amount when storing it into transport metadata
-   as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
-   */
-#define STATUS_OFFSET 1
-static void destroy_status(void *ignored) {}
-
-static uint32_t decode_status(grpc_mdelem *md) {
-  uint32_t status;
-  void *user_data;
-  if (md == GRPC_MDELEM_GRPC_STATUS_0) return 0;
-  if (md == GRPC_MDELEM_GRPC_STATUS_1) return 1;
-  if (md == GRPC_MDELEM_GRPC_STATUS_2) return 2;
-  user_data = grpc_mdelem_get_user_data(md, destroy_status);
-  if (user_data != NULL) {
-    status = ((uint32_t)(intptr_t)user_data) - STATUS_OFFSET;
-  } else {
-    if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
-                                   GPR_SLICE_LENGTH(md->value->slice),
-                                   &status)) {
-      status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
-    }
-    grpc_mdelem_set_user_data(md, destroy_status,
-                              (void *)(intptr_t)(status + STATUS_OFFSET));
-  }
-  return status;
-}
-
-static uint32_t decode_compression(grpc_mdelem *md) {
-  grpc_compression_algorithm algorithm =
-      grpc_compression_algorithm_from_mdstr(md->value);
-  if (algorithm == GRPC_COMPRESS_ALGORITHMS_COUNT) {
-    const char *md_c_str = grpc_mdstr_as_c_string(md->value);
-    gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'", md_c_str);
-  }
-  return algorithm;
-}
-
-static grpc_mdelem *recv_common_filter(grpc_call *call, grpc_mdelem *elem) {
-  if (elem->key == GRPC_MDSTR_GRPC_STATUS) {
-    GPR_TIMER_BEGIN("status", 0);
-    set_status_code(call, STATUS_FROM_WIRE, decode_status(elem));
-    GPR_TIMER_END("status", 0);
-    return NULL;
-  } else if (elem->key == GRPC_MDSTR_GRPC_MESSAGE) {
-    GPR_TIMER_BEGIN("status-details", 0);
-    set_status_details(call, STATUS_FROM_WIRE, GRPC_MDSTR_REF(elem->value));
-    GPR_TIMER_END("status-details", 0);
-    return NULL;
-  }
-  return elem;
-}
-
-static grpc_mdelem *publish_app_metadata(grpc_call *call, grpc_mdelem *elem,
-                                         int is_trailing) {
-  grpc_metadata_array *dest;
-  grpc_metadata *mdusr;
-  GPR_TIMER_BEGIN("publish_app_metadata", 0);
-  dest = call->buffered_metadata[is_trailing];
-  if (dest->count == dest->capacity) {
-    dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2);
-    dest->metadata =
-        gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity);
-  }
-  mdusr = &dest->metadata[dest->count++];
-  mdusr->key = grpc_mdstr_as_c_string(elem->key);
-  mdusr->value = grpc_mdstr_as_c_string(elem->value);
-  mdusr->value_length = GPR_SLICE_LENGTH(elem->value->slice);
-  GPR_TIMER_END("publish_app_metadata", 0);
-  return elem;
-}
-
-static grpc_mdelem *recv_initial_filter(void *callp, grpc_mdelem *elem) {
-  grpc_call *call = callp;
-  elem = recv_common_filter(call, elem);
-  if (elem == NULL) {
-    return NULL;
-  } else if (elem->key == GRPC_MDSTR_GRPC_ENCODING) {
-    GPR_TIMER_BEGIN("compression_algorithm", 0);
-    set_compression_algorithm(call, decode_compression(elem));
-    GPR_TIMER_END("compression_algorithm", 0);
-    return NULL;
-  } else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) {
-    GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0);
-    set_encodings_accepted_by_peer(call, elem);
-    GPR_TIMER_END("encodings_accepted_by_peer", 0);
-    return NULL;
-  } else {
-    return publish_app_metadata(call, elem, 0);
-  }
-}
-
-static grpc_mdelem *recv_trailing_filter(void *callp, grpc_mdelem *elem) {
-  grpc_call *call = callp;
-  elem = recv_common_filter(call, elem);
-  if (elem == NULL) {
-    return NULL;
-  } else {
-    return publish_app_metadata(call, elem, 1);
-  }
-}
-
-grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) {
-  return CALL_STACK_FROM_CALL(call);
-}
-
-/*
- * BATCH API IMPLEMENTATION
- */
-
-static void set_status_value_directly(grpc_status_code status, void *dest) {
-  *(grpc_status_code *)dest = status;
-}
-
-static void set_cancelled_value(grpc_status_code status, void *dest) {
-  *(int *)dest = (status != GRPC_STATUS_OK);
-}
-
-static int are_write_flags_valid(uint32_t flags) {
-  /* check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set */
-  const uint32_t allowed_write_positions =
-      (GRPC_WRITE_USED_MASK | GRPC_WRITE_INTERNAL_USED_MASK);
-  const uint32_t invalid_positions = ~allowed_write_positions;
-  return !(flags & invalid_positions);
-}
-
-static batch_control *allocate_batch_control(grpc_call *call) {
-  size_t i;
-  for (i = 0; i < MAX_CONCURRENT_BATCHES; i++) {
-    if ((call->used_batches & (1 << i)) == 0) {
-      call->used_batches = (uint8_t)(call->used_batches | (uint8_t)(1 << i));
-      return &call->active_batches[i];
-    }
-  }
-  return NULL;
-}
-
-static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data,
-                                    grpc_cq_completion *storage) {
-  batch_control *bctl = user_data;
-  grpc_call *call = bctl->call;
-  gpr_mu_lock(&call->mu);
-  call->used_batches = (uint8_t)(
-      call->used_batches & ~(uint8_t)(1 << (bctl - call->active_batches)));
-  gpr_mu_unlock(&call->mu);
-  GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
-}
-
-static void post_batch_completion(grpc_exec_ctx *exec_ctx,
-                                  batch_control *bctl) {
-  grpc_call *call = bctl->call;
-  if (bctl->is_notify_tag_closure) {
-    grpc_exec_ctx_enqueue(exec_ctx, bctl->notify_tag, bctl->success, NULL);
-    gpr_mu_lock(&call->mu);
-    bctl->call->used_batches =
-        (uint8_t)(bctl->call->used_batches &
-                  ~(uint8_t)(1 << (bctl - bctl->call->active_batches)));
-    gpr_mu_unlock(&call->mu);
-    GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
-  } else {
-    grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, bctl->success,
-                   finish_batch_completion, bctl, &bctl->cq_completion);
-  }
-}
-
-static void continue_receiving_slices(grpc_exec_ctx *exec_ctx,
-                                      batch_control *bctl) {
-  grpc_call *call = bctl->call;
-  for (;;) {
-    size_t remaining = call->receiving_stream->length -
-                       (*call->receiving_buffer)->data.raw.slice_buffer.length;
-    if (remaining == 0) {
-      call->receiving_message = 0;
-      grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
-      call->receiving_stream = NULL;
-      if (gpr_unref(&bctl->steps_to_complete)) {
-        post_batch_completion(exec_ctx, bctl);
-      }
-      return;
-    }
-    if (grpc_byte_stream_next(exec_ctx, call->receiving_stream,
-                              &call->receiving_slice, remaining,
-                              &call->receiving_slice_ready)) {
-      gpr_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
-                           call->receiving_slice);
-    } else {
-      return;
-    }
-  }
-}
-
-static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
-                                  bool success) {
-  batch_control *bctl = bctlp;
-  grpc_call *call = bctl->call;
-
-  if (success) {
-    gpr_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
-                         call->receiving_slice);
-    continue_receiving_slices(exec_ctx, bctl);
-  } else {
-    grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
-    call->receiving_stream = NULL;
-    grpc_byte_buffer_destroy(*call->receiving_buffer);
-    *call->receiving_buffer = NULL;
-    if (gpr_unref(&bctl->steps_to_complete)) {
-      post_batch_completion(exec_ctx, bctl);
-    }
-  }
-}
-
-static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl,
-                                  bool success) {
-  grpc_call *call = bctl->call;
-  if (call->receiving_stream == NULL) {
-    *call->receiving_buffer = NULL;
-    call->receiving_message = 0;
-    if (gpr_unref(&bctl->steps_to_complete)) {
-      post_batch_completion(exec_ctx, bctl);
-    }
-  } else if (call->receiving_stream->length >
-             grpc_channel_get_max_message_length(call->channel)) {
-    cancel_with_status(exec_ctx, call, GRPC_STATUS_INTERNAL,
-                       "Max message size exceeded");
-    grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
-    call->receiving_stream = NULL;
-    *call->receiving_buffer = NULL;
-    call->receiving_message = 0;
-    if (gpr_unref(&bctl->steps_to_complete)) {
-      post_batch_completion(exec_ctx, bctl);
-    }
-  } else {
-    call->test_only_last_message_flags = call->receiving_stream->flags;
-    if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
-        (call->compression_algorithm > GRPC_COMPRESS_NONE)) {
-      *call->receiving_buffer = grpc_raw_compressed_byte_buffer_create(
-          NULL, 0, call->compression_algorithm);
-    } else {
-      *call->receiving_buffer = grpc_raw_byte_buffer_create(NULL, 0);
-    }
-    grpc_closure_init(&call->receiving_slice_ready, receiving_slice_ready,
-                      bctl);
-    continue_receiving_slices(exec_ctx, bctl);
-    /* early out */
-    return;
-  }
-}
-
-static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
-                                   bool success) {
-  batch_control *bctl = bctlp;
-  grpc_call *call = bctl->call;
-
-  gpr_mu_lock(&bctl->call->mu);
-  if (bctl->call->has_initial_md_been_received) {
-    gpr_mu_unlock(&bctl->call->mu);
-    process_data_after_md(exec_ctx, bctlp, success);
-  } else {
-    call->saved_receiving_stream_ready_ctx.bctlp = bctlp;
-    call->saved_receiving_stream_ready_ctx.success = success;
-    gpr_mu_unlock(&bctl->call->mu);
-  }
-}
-
-static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
-                                             void *bctlp, bool success) {
-  batch_control *bctl = bctlp;
-  grpc_call *call = bctl->call;
-
-  gpr_mu_lock(&call->mu);
-
-  grpc_metadata_batch *md =
-      &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
-  grpc_metadata_batch_filter(md, recv_initial_filter, call);
-  call->has_initial_md_been_received = true;
-
-  if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) !=
-          0 &&
-      !call->is_client) {
-    GPR_TIMER_BEGIN("set_deadline_alarm", 0);
-    set_deadline_alarm(exec_ctx, call, md->deadline);
-    GPR_TIMER_END("set_deadline_alarm", 0);
-  }
-
-  if (call->saved_receiving_stream_ready_ctx.bctlp != NULL) {
-    grpc_closure *saved_rsr_closure = grpc_closure_create(
-        receiving_stream_ready, call->saved_receiving_stream_ready_ctx.bctlp);
-    grpc_exec_ctx_enqueue(exec_ctx, saved_rsr_closure,
-                          call->saved_receiving_stream_ready_ctx.success, NULL);
-    call->saved_receiving_stream_ready_ctx.bctlp = NULL;
-  }
-
-  gpr_mu_unlock(&call->mu);
-
-  if (gpr_unref(&bctl->steps_to_complete)) {
-    post_batch_completion(exec_ctx, bctl);
-  }
-}
-
-static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp, bool success) {
-  batch_control *bctl = bctlp;
-  grpc_call *call = bctl->call;
-  grpc_call *child_call;
-  grpc_call *next_child_call;
-
-  gpr_mu_lock(&call->mu);
-  if (bctl->send_initial_metadata) {
-    grpc_metadata_batch_destroy(
-        &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]);
-  }
-  if (bctl->send_message) {
-    call->sending_message = 0;
-  }
-  if (bctl->send_final_op) {
-    grpc_metadata_batch_destroy(
-        &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]);
-  }
-  if (bctl->recv_final_op) {
-    grpc_metadata_batch *md =
-        &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
-    grpc_metadata_batch_filter(md, recv_trailing_filter, call);
-
-    if (call->have_alarm) {
-      grpc_timer_cancel(exec_ctx, &call->alarm);
-    }
-    /* propagate cancellation to any interested children */
-    child_call = call->first_child;
-    if (child_call != NULL) {
-      do {
-        next_child_call = child_call->sibling_next;
-        if (child_call->cancellation_is_inherited) {
-          GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
-          grpc_call_cancel(child_call, NULL);
-          GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel");
-        }
-        child_call = next_child_call;
-      } while (child_call != call->first_child);
-    }
-
-    if (call->is_client) {
-      get_final_status(call, set_status_value_directly,
-                       call->final_op.client.status);
-      get_final_details(call, call->final_op.client.status_details,
-                        call->final_op.client.status_details_capacity);
-    } else {
-      get_final_status(call, set_cancelled_value,
-                       call->final_op.server.cancelled);
-    }
-
-    success = 1;
-  }
-  bctl->success = success != 0;
-  gpr_mu_unlock(&call->mu);
-  if (gpr_unref(&bctl->steps_to_complete)) {
-    post_batch_completion(exec_ctx, bctl);
-  }
-}
-
-static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
-                                        grpc_call *call, const grpc_op *ops,
-                                        size_t nops, void *notify_tag,
-                                        int is_notify_tag_closure) {
-  grpc_transport_stream_op stream_op;
-  size_t i;
-  const grpc_op *op;
-  batch_control *bctl;
-  int num_completion_callbacks_needed = 1;
-  grpc_call_error error = GRPC_CALL_OK;
-
-  GPR_TIMER_BEGIN("grpc_call_start_batch", 0);
-
-  GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, notify_tag);
-
-  memset(&stream_op, 0, sizeof(stream_op));
-
-  /* TODO(ctiller): this feels like it could be made lock-free */
-  gpr_mu_lock(&call->mu);
-  bctl = allocate_batch_control(call);
-  memset(bctl, 0, sizeof(*bctl));
-  bctl->call = call;
-  bctl->notify_tag = notify_tag;
-  bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0);
-
-  if (nops == 0) {
-    GRPC_CALL_INTERNAL_REF(call, "completion");
-    bctl->success = 1;
-    if (!is_notify_tag_closure) {
-      grpc_cq_begin_op(call->cq, notify_tag);
-    }
-    gpr_mu_unlock(&call->mu);
-    post_batch_completion(exec_ctx, bctl);
-    error = GRPC_CALL_OK;
-    goto done;
-  }
-
-  /* rewrite batch ops into a transport op */
-  for (i = 0; i < nops; i++) {
-    op = &ops[i];
-    if (op->reserved != NULL) {
-      error = GRPC_CALL_ERROR;
-      goto done_with_error;
-    }
-    switch (op->op) {
-      case GRPC_OP_SEND_INITIAL_METADATA:
-        /* Flag validation: currently allow no flags */
-        if (op->flags != 0) {
-          error = GRPC_CALL_ERROR_INVALID_FLAGS;
-          goto done_with_error;
-        }
-        if (call->sent_initial_metadata) {
-          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
-          goto done_with_error;
-        }
-        if (op->data.send_initial_metadata.count > INT_MAX) {
-          error = GRPC_CALL_ERROR_INVALID_METADATA;
-          goto done_with_error;
-        }
-        bctl->send_initial_metadata = 1;
-        call->sent_initial_metadata = 1;
-        if (!prepare_application_metadata(
-                call, (int)op->data.send_initial_metadata.count,
-                op->data.send_initial_metadata.metadata, 0, call->is_client)) {
-          error = GRPC_CALL_ERROR_INVALID_METADATA;
-          goto done_with_error;
-        }
-        /* TODO(ctiller): just make these the same variable? */
-        call->metadata_batch[0][0].deadline = call->send_deadline;
-        stream_op.send_initial_metadata =
-            &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */];
-        break;
-      case GRPC_OP_SEND_MESSAGE:
-        if (!are_write_flags_valid(op->flags)) {
-          error = GRPC_CALL_ERROR_INVALID_FLAGS;
-          goto done_with_error;
-        }
-        if (op->data.send_message == NULL) {
-          error = GRPC_CALL_ERROR_INVALID_MESSAGE;
-          goto done_with_error;
-        }
-        if (call->sending_message) {
-          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
-          goto done_with_error;
-        }
-        bctl->send_message = 1;
-        call->sending_message = 1;
-        grpc_slice_buffer_stream_init(
-            &call->sending_stream,
-            &op->data.send_message->data.raw.slice_buffer, op->flags);
-        stream_op.send_message = &call->sending_stream.base;
-        break;
-      case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
-        /* Flag validation: currently allow no flags */
-        if (op->flags != 0) {
-          error = GRPC_CALL_ERROR_INVALID_FLAGS;
-          goto done_with_error;
-        }
-        if (!call->is_client) {
-          error = GRPC_CALL_ERROR_NOT_ON_SERVER;
-          goto done_with_error;
-        }
-        if (call->sent_final_op) {
-          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
-          goto done_with_error;
-        }
-        bctl->send_final_op = 1;
-        call->sent_final_op = 1;
-        stream_op.send_trailing_metadata =
-            &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
-        break;
-      case GRPC_OP_SEND_STATUS_FROM_SERVER:
-        /* Flag validation: currently allow no flags */
-        if (op->flags != 0) {
-          error = GRPC_CALL_ERROR_INVALID_FLAGS;
-          goto done_with_error;
-        }
-        if (call->is_client) {
-          error = GRPC_CALL_ERROR_NOT_ON_CLIENT;
-          goto done_with_error;
-        }
-        if (call->sent_final_op) {
-          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
-          goto done_with_error;
-        }
-        if (op->data.send_status_from_server.trailing_metadata_count >
-            INT_MAX) {
-          error = GRPC_CALL_ERROR_INVALID_METADATA;
-          goto done_with_error;
-        }
-        bctl->send_final_op = 1;
-        call->sent_final_op = 1;
-        call->send_extra_metadata_count = 1;
-        call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem(
-            call->channel, op->data.send_status_from_server.status);
-        if (op->data.send_status_from_server.status_details != NULL) {
-          call->send_extra_metadata[1].md = grpc_mdelem_from_metadata_strings(
-              GRPC_MDSTR_GRPC_MESSAGE,
-              grpc_mdstr_from_string(
-                  op->data.send_status_from_server.status_details));
-          call->send_extra_metadata_count++;
-          set_status_details(
-              call, STATUS_FROM_API_OVERRIDE,
-              GRPC_MDSTR_REF(call->send_extra_metadata[1].md->value));
-        }
-        set_status_code(call, STATUS_FROM_API_OVERRIDE,
-                        (uint32_t)op->data.send_status_from_server.status);
-        if (!prepare_application_metadata(
-                call,
-                (int)op->data.send_status_from_server.trailing_metadata_count,
-                op->data.send_status_from_server.trailing_metadata, 1, 1)) {
-          error = GRPC_CALL_ERROR_INVALID_METADATA;
-          goto done_with_error;
-        }
-        stream_op.send_trailing_metadata =
-            &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
-        break;
-      case GRPC_OP_RECV_INITIAL_METADATA:
-        /* Flag validation: currently allow no flags */
-        if (op->flags != 0) {
-          error = GRPC_CALL_ERROR_INVALID_FLAGS;
-          goto done_with_error;
-        }
-        if (call->received_initial_metadata) {
-          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
-          goto done_with_error;
-        }
-        call->received_initial_metadata = 1;
-        call->buffered_metadata[0] = op->data.recv_initial_metadata;
-        grpc_closure_init(&call->receiving_initial_metadata_ready,
-                          receiving_initial_metadata_ready, bctl);
-        bctl->recv_initial_metadata = 1;
-        stream_op.recv_initial_metadata =
-            &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
-        stream_op.recv_initial_metadata_ready =
-            &call->receiving_initial_metadata_ready;
-        num_completion_callbacks_needed++;
-        break;
-      case GRPC_OP_RECV_MESSAGE:
-        /* Flag validation: currently allow no flags */
-        if (op->flags != 0) {
-          error = GRPC_CALL_ERROR_INVALID_FLAGS;
-          goto done_with_error;
-        }
-        if (call->receiving_message) {
-          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
-          goto done_with_error;
-        }
-        call->receiving_message = 1;
-        bctl->recv_message = 1;
-        call->receiving_buffer = op->data.recv_message;
-        stream_op.recv_message = &call->receiving_stream;
-        grpc_closure_init(&call->receiving_stream_ready, receiving_stream_ready,
-                          bctl);
-        stream_op.recv_message_ready = &call->receiving_stream_ready;
-        num_completion_callbacks_needed++;
-        break;
-      case GRPC_OP_RECV_STATUS_ON_CLIENT:
-        /* Flag validation: currently allow no flags */
-        if (op->flags != 0) {
-          error = GRPC_CALL_ERROR_INVALID_FLAGS;
-          goto done_with_error;
-        }
-        if (!call->is_client) {
-          error = GRPC_CALL_ERROR_NOT_ON_SERVER;
-          goto done_with_error;
-        }
-        if (call->received_final_op) {
-          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
-          goto done_with_error;
-        }
-        call->received_final_op = 1;
-        call->buffered_metadata[1] =
-            op->data.recv_status_on_client.trailing_metadata;
-        call->final_op.client.status = op->data.recv_status_on_client.status;
-        call->final_op.client.status_details =
-            op->data.recv_status_on_client.status_details;
-        call->final_op.client.status_details_capacity =
-            op->data.recv_status_on_client.status_details_capacity;
-        bctl->recv_final_op = 1;
-        stream_op.recv_trailing_metadata =
-            &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
-        break;
-      case GRPC_OP_RECV_CLOSE_ON_SERVER:
-        /* Flag validation: currently allow no flags */
-        if (op->flags != 0) {
-          error = GRPC_CALL_ERROR_INVALID_FLAGS;
-          goto done_with_error;
-        }
-        if (call->is_client) {
-          error = GRPC_CALL_ERROR_NOT_ON_CLIENT;
-          goto done_with_error;
-        }
-        if (call->received_final_op) {
-          error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
-          goto done_with_error;
-        }
-        call->received_final_op = 1;
-        call->final_op.server.cancelled =
-            op->data.recv_close_on_server.cancelled;
-        bctl->recv_final_op = 1;
-        stream_op.recv_trailing_metadata =
-            &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
-        break;
-    }
-  }
-
-  GRPC_CALL_INTERNAL_REF(call, "completion");
-  if (!is_notify_tag_closure) {
-    grpc_cq_begin_op(call->cq, notify_tag);
-  }
-  gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed);
-
-  stream_op.context = call->context;
-  grpc_closure_init(&bctl->finish_batch, finish_batch, bctl);
-  stream_op.on_complete = &bctl->finish_batch;
-  gpr_mu_unlock(&call->mu);
-
-  execute_op(exec_ctx, call, &stream_op);
-
-done:
-  GPR_TIMER_END("grpc_call_start_batch", 0);
-  return error;
-
-done_with_error:
-  /* reverse any mutations that occured */
-  if (bctl->send_initial_metadata) {
-    call->sent_initial_metadata = 0;
-    grpc_metadata_batch_clear(&call->metadata_batch[0][0]);
-  }
-  if (bctl->send_message) {
-    call->sending_message = 0;
-    grpc_byte_stream_destroy(exec_ctx, &call->sending_stream.base);
-  }
-  if (bctl->send_final_op) {
-    call->sent_final_op = 0;
-    grpc_metadata_batch_clear(&call->metadata_batch[0][1]);
-  }
-  if (bctl->recv_initial_metadata) {
-    call->received_initial_metadata = 0;
-  }
-  if (bctl->recv_message) {
-    call->receiving_message = 0;
-  }
-  if (bctl->recv_final_op) {
-    call->received_final_op = 0;
-  }
-  gpr_mu_unlock(&call->mu);
-  goto done;
-}
-
-grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
-                                      size_t nops, void *tag, void *reserved) {
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_call_error err;
-
-  GRPC_API_TRACE(
-      "grpc_call_start_batch(call=%p, ops=%p, nops=%lu, tag=%p, reserved=%p)",
-      5, (call, ops, (unsigned long)nops, tag, reserved));
-
-  if (reserved != NULL) {
-    err = GRPC_CALL_ERROR;
-  } else {
-    err = call_start_batch(&exec_ctx, call, ops, nops, tag, 0);
-  }
-
-  grpc_exec_ctx_finish(&exec_ctx);
-  return err;
-}
-
-grpc_call_error grpc_call_start_batch_and_execute(grpc_exec_ctx *exec_ctx,
-                                                  grpc_call *call,
-                                                  const grpc_op *ops,
-                                                  size_t nops,
-                                                  grpc_closure *closure) {
-  return call_start_batch(exec_ctx, call, ops, nops, closure, 1);
-}
-
-void grpc_call_context_set(grpc_call *call, grpc_context_index elem,
-                           void *value, void (*destroy)(void *value)) {
-  if (call->context[elem].destroy) {
-    call->context[elem].destroy(call->context[elem].value);
-  }
-  call->context[elem].value = value;
-  call->context[elem].destroy = destroy;
-}
-
-void *grpc_call_context_get(grpc_call *call, grpc_context_index elem) {
-  return call->context[elem].value;
-}
-
-uint8_t grpc_call_is_client(grpc_call *call) { return call->is_client; }
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
deleted file mode 100644
index 0bbffb9..0000000
--- a/src/core/surface/call.h
+++ /dev/null
@@ -1,109 +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_SURFACE_CALL_H
-#define GRPC_INTERNAL_CORE_SURFACE_CALL_H
-
-#include "src/core/channel/channel_stack.h"
-#include "src/core/channel/context.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/surface_trace.h"
-#include <grpc/grpc.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void (*grpc_ioreq_completion_func)(grpc_exec_ctx *exec_ctx,
-                                           grpc_call *call, int success,
-                                           void *user_data);
-
-grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
-                            uint32_t propagation_mask,
-                            grpc_completion_queue *cq,
-                            const void *server_transport_data,
-                            grpc_mdelem **add_initial_metadata,
-                            size_t add_initial_metadata_count,
-                            gpr_timespec send_deadline);
-
-void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call,
-                                    grpc_completion_queue *cq);
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-void grpc_call_internal_ref(grpc_call *call, const char *reason);
-void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *call,
-                              const char *reason);
-#define GRPC_CALL_INTERNAL_REF(call, reason) \
-  grpc_call_internal_ref(call, reason)
-#define GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, reason) \
-  grpc_call_internal_unref(exec_ctx, call, reason)
-#else
-void grpc_call_internal_ref(grpc_call *call);
-void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *call);
-#define GRPC_CALL_INTERNAL_REF(call, reason) grpc_call_internal_ref(call)
-#define GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, reason) \
-  grpc_call_internal_unref(exec_ctx, call)
-#endif
-
-grpc_call_stack *grpc_call_get_call_stack(grpc_call *call);
-
-grpc_call_error grpc_call_start_batch_and_execute(grpc_exec_ctx *exec_ctx,
-                                                  grpc_call *call,
-                                                  const grpc_op *ops,
-                                                  size_t nops,
-                                                  grpc_closure *closure);
-
-/* Given the top call_element, get the call object. */
-grpc_call *grpc_call_from_top_element(grpc_call_element *surface_element);
-
-void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
-                         grpc_call *call, const grpc_op *ops, size_t nops,
-                         void *tag);
-
-/* 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));
-/* 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_api_trace) grpc_call_log_batch(sev, call, ops, nops, tag)
-
-uint8_t grpc_call_is_client(grpc_call *call);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_SURFACE_CALL_H */
diff --git a/src/core/surface/call_details.c b/src/core/surface/call_details.c
deleted file mode 100644
index 60f0029..0000000
--- a/src/core/surface/call_details.c
+++ /dev/null
@@ -1,50 +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/grpc.h>
-#include <grpc/support/alloc.h>
-
-#include <string.h>
-
-#include "src/core/surface/api_trace.h"
-
-void grpc_call_details_init(grpc_call_details* cd) {
-  GRPC_API_TRACE("grpc_call_details_init(cd=%p)", 1, (cd));
-  memset(cd, 0, sizeof(*cd));
-}
-
-void grpc_call_details_destroy(grpc_call_details* cd) {
-  GRPC_API_TRACE("grpc_call_details_destroy(cd=%p)", 1, (cd));
-  gpr_free(cd->method);
-  gpr_free(cd->host);
-}
diff --git a/src/core/surface/call_log_batch.c b/src/core/surface/call_log_batch.c
deleted file mode 100644
index 46756f4..0000000
--- a/src/core/surface/call_log_batch.c
+++ /dev/null
@@ -1,118 +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/call.h"
-
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/string_util.h>
-
-static void add_metadata(gpr_strvec *b, const grpc_metadata *md, size_t count) {
-  size_t i;
-  for (i = 0; i < count; i++) {
-    gpr_strvec_add(b, gpr_strdup("\nkey="));
-    gpr_strvec_add(b, gpr_strdup(md[i].key));
-
-    gpr_strvec_add(b, gpr_strdup(" value="));
-    gpr_strvec_add(b, gpr_dump(md[i].value, md[i].value_length,
-                               GPR_DUMP_HEX | GPR_DUMP_ASCII));
-  }
-}
-
-char *grpc_op_string(const grpc_op *op) {
-  char *tmp;
-  char *out;
-
-  gpr_strvec b;
-  gpr_strvec_init(&b);
-
-  switch (op->op) {
-    case GRPC_OP_SEND_INITIAL_METADATA:
-      gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA"));
-      add_metadata(&b, op->data.send_initial_metadata.metadata,
-                   op->data.send_initial_metadata.count);
-      break;
-    case GRPC_OP_SEND_MESSAGE:
-      gpr_asprintf(&tmp, "SEND_MESSAGE ptr=%p", op->data.send_message);
-      gpr_strvec_add(&b, tmp);
-      break;
-    case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
-      gpr_strvec_add(&b, gpr_strdup("SEND_CLOSE_FROM_CLIENT"));
-      break;
-    case GRPC_OP_SEND_STATUS_FROM_SERVER:
-      gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=%s",
-                   op->data.send_status_from_server.status,
-                   op->data.send_status_from_server.status_details);
-      gpr_strvec_add(&b, tmp);
-      add_metadata(&b, op->data.send_status_from_server.trailing_metadata,
-                   op->data.send_status_from_server.trailing_metadata_count);
-      break;
-    case GRPC_OP_RECV_INITIAL_METADATA:
-      gpr_asprintf(&tmp, "RECV_INITIAL_METADATA ptr=%p",
-                   op->data.recv_initial_metadata);
-      gpr_strvec_add(&b, tmp);
-      break;
-    case GRPC_OP_RECV_MESSAGE:
-      gpr_asprintf(&tmp, "RECV_MESSAGE ptr=%p", op->data.recv_message);
-      gpr_strvec_add(&b, tmp);
-      break;
-    case GRPC_OP_RECV_STATUS_ON_CLIENT:
-      gpr_asprintf(&tmp,
-                   "RECV_STATUS_ON_CLIENT metadata=%p status=%p details=%p",
-                   op->data.recv_status_on_client.trailing_metadata,
-                   op->data.recv_status_on_client.status,
-                   op->data.recv_status_on_client.status_details);
-      gpr_strvec_add(&b, tmp);
-      break;
-    case GRPC_OP_RECV_CLOSE_ON_SERVER:
-      gpr_asprintf(&tmp, "RECV_CLOSE_ON_SERVER cancelled=%p",
-                   op->data.recv_close_on_server.cancelled);
-      gpr_strvec_add(&b, tmp);
-  }
-  out = gpr_strvec_flatten(&b, NULL);
-  gpr_strvec_destroy(&b);
-
-  return out;
-}
-
-void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
-                         grpc_call *call, const grpc_op *ops, size_t nops,
-                         void *tag) {
-  char *tmp;
-  size_t i;
-  for (i = 0; i < nops; i++) {
-    tmp = grpc_op_string(&ops[i]);
-    gpr_log(file, line, severity, "ops[%d]: %s", i, tmp);
-    gpr_free(tmp);
-  }
-}
diff --git a/src/core/surface/call_test_only.h b/src/core/surface/call_test_only.h
deleted file mode 100644
index b57c95c..0000000
--- a/src/core/surface/call_test_only.h
+++ /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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_SURFACE_CALL_TEST_ONLY_H
-#define GRPC_INTERNAL_CORE_SURFACE_CALL_TEST_ONLY_H
-
-#include <grpc/grpc.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** Return the compression algorithm from \a call.
- *
- * \warning This function should \b only be used in test code. */
-grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm(
-    grpc_call *call);
-
-/** Return the message flags from \a call.
- *
- * \warning This function should \b only be used in test code. */
-uint32_t grpc_call_test_only_get_message_flags(grpc_call *call);
-
-/** Returns a bitset for the encodings (compression algorithms) supported by \a
- * call's peer.
- *
- * To be indexed by grpc_compression_algorithm enum values. */
-uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_SURFACE_CALL_TEST_ONLY_H */
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
deleted file mode 100644
index 12d8ebc..0000000
--- a/src/core/surface/channel.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/surface/channel.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/client_config/resolver_registry.h"
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/support/string.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/call.h"
-#include "src/core/surface/init.h"
-#include "src/core/transport/static_metadata.h"
-
-/** Cache grpc-status: X mdelems for X = 0..NUM_CACHED_STATUS_ELEMS.
- *  Avoids needing to take a metadata context lock for sending status
- *  if the status code is <= NUM_CACHED_STATUS_ELEMS.
- *  Sized to allow the most commonly used codes to fit in
- *  (OK, Cancelled, Unknown). */
-#define NUM_CACHED_STATUS_ELEMS 3
-
-typedef struct registered_call {
-  grpc_mdelem *path;
-  grpc_mdelem *authority;
-  struct registered_call *next;
-} registered_call;
-
-struct grpc_channel {
-  int is_client;
-  uint32_t max_message_length;
-  grpc_mdelem *default_authority;
-
-  gpr_mu registered_call_mu;
-  registered_call *registered_calls;
-  char *target;
-};
-
-#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1))
-#define CHANNEL_FROM_CHANNEL_STACK(channel_stack) \
-  (((grpc_channel *)(channel_stack)) - 1)
-#define CHANNEL_FROM_TOP_ELEM(top_elem) \
-  CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem))
-
-/* the protobuf library will (by default) start warning at 100megs */
-#define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024)
-
-static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, bool success);
-
-grpc_channel *grpc_channel_create_from_filters(
-    grpc_exec_ctx *exec_ctx, const char *target,
-    const grpc_channel_filter **filters, size_t num_filters,
-    const grpc_channel_args *args, int is_client) {
-  size_t i;
-  size_t size =
-      sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters);
-  grpc_channel *channel = gpr_malloc(size);
-  memset(channel, 0, sizeof(*channel));
-  channel->target = gpr_strdup(target);
-  GPR_ASSERT(grpc_is_initialized() && "call grpc_init()");
-  channel->is_client = is_client;
-  gpr_mu_init(&channel->registered_call_mu);
-  channel->registered_calls = NULL;
-
-  channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH;
-  if (args) {
-    for (i = 0; i < args->num_args; i++) {
-      if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) {
-        if (args->args[i].type != GRPC_ARG_INTEGER) {
-          gpr_log(GPR_ERROR, "%s ignored: it must be an integer",
-                  GRPC_ARG_MAX_MESSAGE_LENGTH);
-        } else if (args->args[i].value.integer < 0) {
-          gpr_log(GPR_ERROR, "%s ignored: it must be >= 0",
-                  GRPC_ARG_MAX_MESSAGE_LENGTH);
-        } else {
-          channel->max_message_length = (uint32_t)args->args[i].value.integer;
-        }
-      } else if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) {
-        if (args->args[i].type != GRPC_ARG_STRING) {
-          gpr_log(GPR_ERROR, "%s ignored: it must be a string",
-                  GRPC_ARG_DEFAULT_AUTHORITY);
-        } else {
-          if (channel->default_authority) {
-            /* setting this takes precedence over anything else */
-            GRPC_MDELEM_UNREF(channel->default_authority);
-          }
-          channel->default_authority = grpc_mdelem_from_strings(
-              ":authority", args->args[i].value.string);
-        }
-      } else if (0 ==
-                 strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) {
-        if (args->args[i].type != GRPC_ARG_STRING) {
-          gpr_log(GPR_ERROR, "%s ignored: it must be a string",
-                  GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
-        } else {
-          if (channel->default_authority) {
-            /* other ways of setting this (notably ssl) take precedence */
-            gpr_log(GPR_ERROR,
-                    "%s ignored: default host already set some other way",
-                    GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
-          } else {
-            channel->default_authority = grpc_mdelem_from_strings(
-                ":authority", args->args[i].value.string);
-          }
-        }
-      }
-    }
-  }
-
-  if (channel->is_client && channel->default_authority == NULL &&
-      target != NULL) {
-    char *default_authority = grpc_get_default_authority(target);
-    if (default_authority) {
-      channel->default_authority =
-          grpc_mdelem_from_strings(":authority", default_authority);
-    }
-    gpr_free(default_authority);
-  }
-
-  grpc_channel_stack_init(exec_ctx, 1, destroy_channel, channel, filters,
-                          num_filters, args,
-                          is_client ? "CLIENT_CHANNEL" : "SERVER_CHANNEL",
-                          CHANNEL_STACK_FROM_CHANNEL(channel));
-
-  return channel;
-}
-
-char *grpc_channel_get_target(grpc_channel *channel) {
-  GRPC_API_TRACE("grpc_channel_get_target(channel=%p)", 1, (channel));
-  return gpr_strdup(channel->target);
-}
-
-static grpc_call *grpc_channel_create_call_internal(
-    grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
-    grpc_completion_queue *cq, grpc_mdelem *path_mdelem,
-    grpc_mdelem *authority_mdelem, gpr_timespec deadline) {
-  grpc_mdelem *send_metadata[2];
-  size_t num_metadata = 0;
-
-  GPR_ASSERT(channel->is_client);
-
-  send_metadata[num_metadata++] = path_mdelem;
-  if (authority_mdelem != NULL) {
-    send_metadata[num_metadata++] = authority_mdelem;
-  } else if (channel->default_authority != NULL) {
-    send_metadata[num_metadata++] = GRPC_MDELEM_REF(channel->default_authority);
-  }
-
-  return grpc_call_create(channel, parent_call, propagation_mask, cq, NULL,
-                          send_metadata, num_metadata, deadline);
-}
-
-grpc_call *grpc_channel_create_call(grpc_channel *channel,
-                                    grpc_call *parent_call,
-                                    uint32_t propagation_mask,
-                                    grpc_completion_queue *cq,
-                                    const char *method, const char *host,
-                                    gpr_timespec deadline, void *reserved) {
-  GRPC_API_TRACE(
-      "grpc_channel_create_call("
-      "channel=%p, parent_call=%p, propagation_mask=%x, cq=%p, method=%s, "
-      "host=%s, "
-      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
-      "reserved=%p)",
-      10, (channel, parent_call, (unsigned)propagation_mask, cq, method, host,
-           (long long)deadline.tv_sec, (int)deadline.tv_nsec,
-           (int)deadline.clock_type, reserved));
-  GPR_ASSERT(!reserved);
-  return grpc_channel_create_call_internal(
-      channel, parent_call, propagation_mask, cq,
-      grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
-                                        grpc_mdstr_from_string(method)),
-      host ? grpc_mdelem_from_metadata_strings(GRPC_MDSTR_AUTHORITY,
-                                               grpc_mdstr_from_string(host))
-           : NULL,
-      deadline);
-}
-
-void *grpc_channel_register_call(grpc_channel *channel, const char *method,
-                                 const char *host, void *reserved) {
-  registered_call *rc = gpr_malloc(sizeof(registered_call));
-  GRPC_API_TRACE(
-      "grpc_channel_register_call(channel=%p, method=%s, host=%s, reserved=%p)",
-      4, (channel, method, host, reserved));
-  GPR_ASSERT(!reserved);
-  rc->path = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
-                                               grpc_mdstr_from_string(method));
-  rc->authority = host ? grpc_mdelem_from_metadata_strings(
-                             GRPC_MDSTR_AUTHORITY, grpc_mdstr_from_string(host))
-                       : NULL;
-  gpr_mu_lock(&channel->registered_call_mu);
-  rc->next = channel->registered_calls;
-  channel->registered_calls = rc;
-  gpr_mu_unlock(&channel->registered_call_mu);
-  return rc;
-}
-
-grpc_call *grpc_channel_create_registered_call(
-    grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
-    grpc_completion_queue *completion_queue, void *registered_call_handle,
-    gpr_timespec deadline, void *reserved) {
-  registered_call *rc = registered_call_handle;
-  GRPC_API_TRACE(
-      "grpc_channel_create_registered_call("
-      "channel=%p, parent_call=%p, propagation_mask=%x, completion_queue=%p, "
-      "registered_call_handle=%p, "
-      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
-      "reserved=%p)",
-      9, (channel, parent_call, (unsigned)propagation_mask, completion_queue,
-          registered_call_handle, (long long)deadline.tv_sec,
-          (int)deadline.tv_nsec, (int)deadline.clock_type, reserved));
-  GPR_ASSERT(!reserved);
-  return grpc_channel_create_call_internal(
-      channel, parent_call, propagation_mask, completion_queue,
-      GRPC_MDELEM_REF(rc->path),
-      rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline);
-}
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-#define REF_REASON reason
-#define REF_ARG , const char *reason
-#else
-#define REF_REASON ""
-#define REF_ARG
-#endif
-void grpc_channel_internal_ref(grpc_channel *c REF_ARG) {
-  GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
-}
-
-void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel *c REF_ARG) {
-  GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
-}
-
-static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg,
-                            bool iomgr_success) {
-  grpc_channel *channel = arg;
-  grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(channel));
-  while (channel->registered_calls) {
-    registered_call *rc = channel->registered_calls;
-    channel->registered_calls = rc->next;
-    GRPC_MDELEM_UNREF(rc->path);
-    if (rc->authority) {
-      GRPC_MDELEM_UNREF(rc->authority);
-    }
-    gpr_free(rc);
-  }
-  if (channel->default_authority != NULL) {
-    GRPC_MDELEM_UNREF(channel->default_authority);
-  }
-  gpr_mu_destroy(&channel->registered_call_mu);
-  gpr_free(channel->target);
-  gpr_free(channel);
-}
-
-void grpc_channel_destroy(grpc_channel *channel) {
-  grpc_transport_op op;
-  grpc_channel_element *elem;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  GRPC_API_TRACE("grpc_channel_destroy(channel=%p)", 1, (channel));
-  memset(&op, 0, sizeof(op));
-  op.disconnect = 1;
-  elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
-  elem->filter->start_transport_op(&exec_ctx, elem, &op);
-
-  GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, channel, "channel");
-
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
-  return CHANNEL_STACK_FROM_CHANNEL(channel);
-}
-
-grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
-  char tmp[GPR_LTOA_MIN_BUFSIZE];
-  switch (i) {
-    case 0:
-      return GRPC_MDELEM_GRPC_STATUS_0;
-    case 1:
-      return GRPC_MDELEM_GRPC_STATUS_1;
-    case 2:
-      return GRPC_MDELEM_GRPC_STATUS_2;
-  }
-  gpr_ltoa(i, tmp);
-  return grpc_mdelem_from_metadata_strings(GRPC_MDSTR_GRPC_STATUS,
-                                           grpc_mdstr_from_string(tmp));
-}
-
-uint32_t grpc_channel_get_max_message_length(grpc_channel *channel) {
-  return channel->max_message_length;
-}
diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h
deleted file mode 100644
index 00240c6..0000000
--- a/src/core/surface/channel.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_SURFACE_CHANNEL_H
-#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(
-    grpc_exec_ctx *exec_ctx, const char *target,
-    const grpc_channel_filter **filters, size_t count,
-    const grpc_channel_args *args, int is_client);
-
-/** Get a (borrowed) pointer to this channels underlying channel stack */
-grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
-
-/** Get a grpc_mdelem of grpc-status: X where X is the numeric value of
-    status_code.
-
-    The returned elem is owned by the caller. */
-grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel,
-                                                 int status_code);
-uint32_t grpc_channel_get_max_message_length(grpc_channel *channel);
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-void grpc_channel_internal_ref(grpc_channel *channel, const char *reason);
-void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
-                                 const char *reason);
-#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
-  grpc_channel_internal_ref(channel, reason)
-#define GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, reason) \
-  grpc_channel_internal_unref(exec_ctx, channel, reason)
-#else
-void grpc_channel_internal_ref(grpc_channel *channel);
-void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel *channel);
-#define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
-  grpc_channel_internal_ref(channel)
-#define GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, reason) \
-  grpc_channel_internal_unref(exec_ctx, channel)
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H */
diff --git a/src/core/surface/channel_connectivity.c b/src/core/surface/channel_connectivity.c
deleted file mode 100644
index 2dd4fce..0000000
--- a/src/core/surface/channel_connectivity.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/surface/channel.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/channel/client_channel.h"
-#include "src/core/channel/client_uchannel.h"
-#include "src/core/iomgr/timer.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/completion_queue.h"
-
-grpc_connectivity_state grpc_channel_check_connectivity_state(
-    grpc_channel *channel, int try_to_connect) {
-  /* forward through to the underlying client channel */
-  grpc_channel_element *client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_connectivity_state state;
-  GRPC_API_TRACE(
-      "grpc_channel_check_connectivity_state(channel=%p, try_to_connect=%d)", 2,
-      (channel, try_to_connect));
-  if (client_channel_elem->filter == &grpc_client_channel_filter) {
-    state = grpc_client_channel_check_connectivity_state(
-        &exec_ctx, client_channel_elem, try_to_connect);
-    grpc_exec_ctx_finish(&exec_ctx);
-    return state;
-  }
-  if (client_channel_elem->filter == &grpc_client_uchannel_filter) {
-    state = grpc_client_uchannel_check_connectivity_state(
-        &exec_ctx, client_channel_elem, try_to_connect);
-    grpc_exec_ctx_finish(&exec_ctx);
-    return state;
-  }
-  gpr_log(GPR_ERROR,
-          "grpc_channel_check_connectivity_state called on something that is "
-          "not a (u)client channel, but '%s'",
-          client_channel_elem->filter->name);
-  grpc_exec_ctx_finish(&exec_ctx);
-  return GRPC_CHANNEL_FATAL_FAILURE;
-}
-
-typedef enum {
-  WAITING,
-  CALLING_BACK,
-  CALLING_BACK_AND_FINISHED,
-  CALLED_BACK
-} callback_phase;
-
-typedef struct {
-  gpr_mu mu;
-  callback_phase phase;
-  int success;
-  grpc_closure on_complete;
-  grpc_timer alarm;
-  grpc_connectivity_state state;
-  grpc_completion_queue *cq;
-  grpc_cq_completion completion_storage;
-  grpc_channel *channel;
-  void *tag;
-} state_watcher;
-
-static void delete_state_watcher(grpc_exec_ctx *exec_ctx, state_watcher *w) {
-  grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(
-      grpc_channel_get_channel_stack(w->channel));
-  if (client_channel_elem->filter == &grpc_client_channel_filter) {
-    GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->channel,
-                                "watch_channel_connectivity");
-  } else if (client_channel_elem->filter == &grpc_client_uchannel_filter) {
-    GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->channel,
-                                "watch_uchannel_connectivity");
-  } else {
-    abort();
-  }
-  gpr_mu_destroy(&w->mu);
-  gpr_free(w);
-}
-
-static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw,
-                                grpc_cq_completion *ignored) {
-  int delete = 0;
-  state_watcher *w = pw;
-  gpr_mu_lock(&w->mu);
-  switch (w->phase) {
-    case WAITING:
-    case CALLED_BACK:
-      GPR_UNREACHABLE_CODE(return );
-    case CALLING_BACK:
-      w->phase = CALLED_BACK;
-      break;
-    case CALLING_BACK_AND_FINISHED:
-      delete = 1;
-      break;
-  }
-  gpr_mu_unlock(&w->mu);
-
-  if (delete) {
-    delete_state_watcher(exec_ctx, w);
-  }
-}
-
-static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
-                        int due_to_completion) {
-  int delete = 0;
-
-  if (due_to_completion) {
-    grpc_timer_cancel(exec_ctx, &w->alarm);
-  }
-
-  gpr_mu_lock(&w->mu);
-  if (due_to_completion) {
-    w->success = 1;
-  }
-  switch (w->phase) {
-    case WAITING:
-      w->phase = CALLING_BACK;
-      grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->success, finished_completion,
-                     w, &w->completion_storage);
-      break;
-    case CALLING_BACK:
-      w->phase = CALLING_BACK_AND_FINISHED;
-      break;
-    case CALLING_BACK_AND_FINISHED:
-      GPR_UNREACHABLE_CODE(return );
-    case CALLED_BACK:
-      delete = 1;
-      break;
-  }
-  gpr_mu_unlock(&w->mu);
-
-  if (delete) {
-    delete_state_watcher(exec_ctx, w);
-  }
-}
-
-static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) {
-  partly_done(exec_ctx, pw, 1);
-}
-
-static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) {
-  partly_done(exec_ctx, pw, 0);
-}
-
-void grpc_channel_watch_connectivity_state(
-    grpc_channel *channel, grpc_connectivity_state last_observed_state,
-    gpr_timespec deadline, grpc_completion_queue *cq, void *tag) {
-  grpc_channel_element *client_channel_elem =
-      grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  state_watcher *w = gpr_malloc(sizeof(*w));
-
-  GRPC_API_TRACE(
-      "grpc_channel_watch_connectivity_state("
-      "channel=%p, last_observed_state=%d, "
-      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
-      "cq=%p, tag=%p)",
-      7, (channel, (int)last_observed_state, (long long)deadline.tv_sec,
-          (int)deadline.tv_nsec, (int)deadline.clock_type, cq, tag));
-
-  grpc_cq_begin_op(cq, tag);
-
-  gpr_mu_init(&w->mu);
-  grpc_closure_init(&w->on_complete, watch_complete, w);
-  w->phase = WAITING;
-  w->state = last_observed_state;
-  w->success = 0;
-  w->cq = cq;
-  w->tag = tag;
-  w->channel = channel;
-
-  grpc_timer_init(&exec_ctx, &w->alarm,
-                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC));
-
-  if (client_channel_elem->filter == &grpc_client_channel_filter) {
-    GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
-    grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem,
-                                                 grpc_cq_pollset(cq), &w->state,
-                                                 &w->on_complete);
-  } else if (client_channel_elem->filter == &grpc_client_uchannel_filter) {
-    GRPC_CHANNEL_INTERNAL_REF(channel, "watch_uchannel_connectivity");
-    grpc_client_uchannel_watch_connectivity_state(
-        &exec_ctx, client_channel_elem, grpc_cq_pollset(cq), &w->state,
-        &w->on_complete);
-  }
-
-  grpc_exec_ctx_finish(&exec_ctx);
-}
diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c
deleted file mode 100644
index fd7e20e..0000000
--- a/src/core/surface/channel_create.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/grpc.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
-
-#include "src/core/census/grpc_filter.h"
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/client_channel.h"
-#include "src/core/channel/compress_filter.h"
-#include "src/core/channel/http_client_filter.h"
-#include "src/core/client_config/resolver_registry.h"
-#include "src/core/iomgr/tcp_client.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/channel.h"
-#include "src/core/transport/chttp2_transport.h"
-
-typedef struct {
-  grpc_connector base;
-  gpr_refcount refs;
-
-  grpc_closure *notify;
-  grpc_connect_in_args args;
-  grpc_connect_out_args *result;
-  grpc_closure initial_string_sent;
-  gpr_slice_buffer initial_string_buffer;
-
-  grpc_endpoint *tcp;
-
-  grpc_closure connected;
-} connector;
-
-static void connector_ref(grpc_connector *con) {
-  connector *c = (connector *)con;
-  gpr_ref(&c->refs);
-}
-
-static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
-  connector *c = (connector *)con;
-  if (gpr_unref(&c->refs)) {
-    /* c->initial_string_buffer does not need to be destroyed */
-    gpr_free(c);
-  }
-}
-
-static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
-                                           bool success) {
-  connector_unref(exec_ctx, arg);
-}
-
-static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  connector *c = arg;
-  grpc_closure *notify;
-  grpc_endpoint *tcp = c->tcp;
-  if (tcp != NULL) {
-    if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
-      grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
-                        c);
-      gpr_slice_buffer_init(&c->initial_string_buffer);
-      gpr_slice_buffer_add(&c->initial_string_buffer,
-                           c->args.initial_connect_string);
-      connector_ref(arg);
-      grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
-                          &c->initial_string_sent);
-    }
-    c->result->transport =
-        grpc_create_chttp2_transport(exec_ctx, c->args.channel_args, tcp, 1);
-    grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
-                                        0);
-    GPR_ASSERT(c->result->transport);
-    c->result->channel_args = c->args.channel_args;
-    c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *));
-    c->result->filters[0] = &grpc_http_client_filter;
-    c->result->num_filters = 1;
-  } else {
-    memset(c->result, 0, sizeof(*c->result));
-  }
-  notify = c->notify;
-  c->notify = NULL;
-  notify->cb(exec_ctx, notify->cb_arg, 1);
-}
-
-static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {}
-
-static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
-                              const grpc_connect_in_args *args,
-                              grpc_connect_out_args *result,
-                              grpc_closure *notify) {
-  connector *c = (connector *)con;
-  GPR_ASSERT(c->notify == NULL);
-  GPR_ASSERT(notify->cb);
-  c->notify = notify;
-  c->args = *args;
-  c->result = result;
-  c->tcp = NULL;
-  grpc_closure_init(&c->connected, connected, c);
-  grpc_tcp_client_connect(exec_ctx, &c->connected, &c->tcp,
-                          args->interested_parties, args->addr, args->addr_len,
-                          args->deadline);
-}
-
-static const grpc_connector_vtable connector_vtable = {
-    connector_ref, connector_unref, connector_shutdown, connector_connect};
-
-typedef struct {
-  grpc_subchannel_factory base;
-  gpr_refcount refs;
-  grpc_channel_args *merge_args;
-  grpc_channel *master;
-} 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_exec_ctx *exec_ctx,
-                                     grpc_subchannel_factory *scf) {
-  subchannel_factory *f = (subchannel_factory *)scf;
-  if (gpr_unref(&f->refs)) {
-    GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory");
-    grpc_channel_args_destroy(f->merge_args);
-    gpr_free(f);
-  }
-}
-
-static grpc_subchannel *subchannel_factory_create_subchannel(
-    grpc_exec_ctx *exec_ctx, 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->args = final_args;
-  s = grpc_subchannel_create(exec_ctx, &c->base, args);
-  grpc_connector_unref(exec_ctx, &c->base);
-  grpc_channel_args_destroy(final_args);
-  return s;
-}
-
-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
-                   - connect to it (trying alternatives as presented)
-                   - perform handshakes */
-grpc_channel *grpc_insecure_channel_create(const char *target,
-                                           const grpc_channel_args *args,
-                                           void *reserved) {
-  grpc_channel *channel = NULL;
-#define MAX_FILTERS 3
-  const grpc_channel_filter *filters[MAX_FILTERS];
-  grpc_resolver *resolver;
-  subchannel_factory *f;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  size_t n = 0;
-  GRPC_API_TRACE(
-      "grpc_insecure_channel_create(target=%p, args=%p, reserved=%p)", 3,
-      (target, args, reserved));
-  GPR_ASSERT(!reserved);
-  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);
-
-  channel =
-      grpc_channel_create_from_filters(&exec_ctx, target, filters, n, args, 1);
-
-  f = gpr_malloc(sizeof(*f));
-  f->base.vtable = &subchannel_factory_vtable;
-  gpr_ref_init(&f->refs, 1);
-  f->merge_args = grpc_channel_args_copy(args);
-  f->master = channel;
-  GRPC_CHANNEL_INTERNAL_REF(f->master, "subchannel_factory");
-  resolver = grpc_resolver_create(target, &f->base);
-  if (!resolver) {
-    GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, f->master, "subchannel_factory");
-    grpc_subchannel_factory_unref(&exec_ctx, &f->base);
-    grpc_exec_ctx_finish(&exec_ctx);
-    return NULL;
-  }
-
-  grpc_client_channel_set_resolver(
-      &exec_ctx, grpc_channel_get_channel_stack(channel), resolver);
-  GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "create");
-  grpc_subchannel_factory_unref(&exec_ctx, &f->base);
-
-  grpc_exec_ctx_finish(&exec_ctx);
-
-  return channel;
-}
diff --git a/src/core/surface/channel_ping.c b/src/core/surface/channel_ping.c
deleted file mode 100644
index 983f1c8..0000000
--- a/src/core/surface/channel_ping.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/surface/channel.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/completion_queue.h"
-
-typedef struct {
-  grpc_closure closure;
-  void *tag;
-  grpc_completion_queue *cq;
-  grpc_cq_completion completion_storage;
-} ping_result;
-
-static void ping_destroy(grpc_exec_ctx *exec_ctx, void *arg,
-                         grpc_cq_completion *storage) {
-  gpr_free(arg);
-}
-
-static void ping_done(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  ping_result *pr = arg;
-  grpc_cq_end_op(exec_ctx, pr->cq, pr->tag, success, ping_destroy, pr,
-                 &pr->completion_storage);
-}
-
-void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq,
-                       void *tag, void *reserved) {
-  grpc_transport_op op;
-  ping_result *pr = gpr_malloc(sizeof(*pr));
-  grpc_channel_element *top_elem =
-      grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  GPR_ASSERT(reserved == NULL);
-  memset(&op, 0, sizeof(op));
-  pr->tag = tag;
-  pr->cq = cq;
-  grpc_closure_init(&pr->closure, ping_done, pr);
-  op.send_ping = &pr->closure;
-  op.bind_pollset = grpc_cq_pollset(cq);
-  grpc_cq_begin_op(cq, tag);
-  top_elem->filter->start_transport_op(&exec_ctx, top_elem, &op);
-  grpc_exec_ctx_finish(&exec_ctx);
-}
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
deleted file mode 100644
index f6a95eb..0000000
--- a/src/core/surface/completion_queue.c
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/surface/completion_queue.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/atm.h>
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
-
-#include "src/core/iomgr/pollset.h"
-#include "src/core/iomgr/timer.h"
-#include "src/core/profiling/timers.h"
-#include "src/core/support/string.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/call.h"
-#include "src/core/surface/event_string.h"
-#include "src/core/surface/surface_trace.h"
-
-typedef struct {
-  grpc_pollset_worker **worker;
-  void *tag;
-} plucker;
-
-/* Completion queue structure */
-struct grpc_completion_queue {
-  /** owned by pollset */
-  gpr_mu *mu;
-  /** 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;
-  /** 0 initially, 1 once we've begun shutting down */
-  int shutdown;
-  int shutdown_called;
-  int is_server_cq;
-  int num_pluckers;
-  plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
-  grpc_closure pollset_shutdown_done;
-
-#ifndef NDEBUG
-  void **outstanding_tags;
-  size_t outstanding_tag_count;
-  size_t outstanding_tag_capacity;
-#endif
-
-  grpc_completion_queue *next_free;
-};
-
-#define POLLSET_FROM_CQ(cq) ((grpc_pollset *)(cq + 1))
-
-static gpr_mu g_freelist_mu;
-grpc_completion_queue *g_freelist;
-
-static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *cc,
-                                     bool success);
-
-void grpc_cq_global_init(void) { gpr_mu_init(&g_freelist_mu); }
-
-void grpc_cq_global_shutdown(void) {
-  gpr_mu_destroy(&g_freelist_mu);
-  while (g_freelist) {
-    grpc_completion_queue *next = g_freelist->next_free;
-    grpc_pollset_destroy(POLLSET_FROM_CQ(g_freelist));
-#ifndef NDEBUG
-    gpr_free(g_freelist->outstanding_tags);
-#endif
-    gpr_free(g_freelist);
-    g_freelist = next;
-  }
-}
-
-struct grpc_cq_alarm {
-  grpc_timer alarm;
-  grpc_cq_completion completion;
-  /** completion queue where events about this alarm will be posted */
-  grpc_completion_queue *cq;
-  /** user supplied tag */
-  void *tag;
-};
-
-grpc_completion_queue *grpc_completion_queue_create(void *reserved) {
-  grpc_completion_queue *cc;
-  GPR_ASSERT(!reserved);
-
-  GPR_TIMER_BEGIN("grpc_completion_queue_create", 0);
-
-  GRPC_API_TRACE("grpc_completion_queue_create(reserved=%p)", 1, (reserved));
-
-  gpr_mu_lock(&g_freelist_mu);
-  if (g_freelist == NULL) {
-    gpr_mu_unlock(&g_freelist_mu);
-
-    cc = gpr_malloc(sizeof(grpc_completion_queue) + grpc_pollset_size());
-    grpc_pollset_init(POLLSET_FROM_CQ(cc), &cc->mu);
-#ifndef NDEBUG
-    cc->outstanding_tags = NULL;
-    cc->outstanding_tag_capacity = 0;
-#endif
-  } else {
-    cc = g_freelist;
-    g_freelist = g_freelist->next_free;
-    gpr_mu_unlock(&g_freelist_mu);
-    /* pollset already initialized */
-  }
-
-  /* Initial ref is dropped by grpc_completion_queue_shutdown */
-  gpr_ref_init(&cc->pending_events, 1);
-  /* One for destroy(), one for pollset_shutdown */
-  gpr_ref_init(&cc->owning_refs, 2);
-  cc->completed_tail = &cc->completed_head;
-  cc->completed_head.next = (uintptr_t)cc->completed_tail;
-  cc->shutdown = 0;
-  cc->shutdown_called = 0;
-  cc->is_server_cq = 0;
-  cc->num_pluckers = 0;
-#ifndef NDEBUG
-  cc->outstanding_tag_count = 0;
-#endif
-  grpc_closure_init(&cc->pollset_shutdown_done, on_pollset_shutdown_done, cc);
-
-  GPR_TIMER_END("grpc_completion_queue_create", 0);
-
-  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_shutdown_done(grpc_exec_ctx *exec_ctx, void *arg,
-                                     bool success) {
-  grpc_completion_queue *cc = arg;
-  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->completed_head.next == (uintptr_t)&cc->completed_head);
-    grpc_pollset_reset(POLLSET_FROM_CQ(cc));
-    gpr_mu_lock(&g_freelist_mu);
-    cc->next_free = g_freelist;
-    g_freelist = cc;
-    gpr_mu_unlock(&g_freelist_mu);
-  }
-}
-
-void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag) {
-#ifndef NDEBUG
-  gpr_mu_lock(cc->mu);
-  GPR_ASSERT(!cc->shutdown_called);
-  if (cc->outstanding_tag_count == cc->outstanding_tag_capacity) {
-    cc->outstanding_tag_capacity = GPR_MAX(4, 2 * cc->outstanding_tag_capacity);
-    cc->outstanding_tags =
-        gpr_realloc(cc->outstanding_tags, sizeof(*cc->outstanding_tags) *
-                                              cc->outstanding_tag_capacity);
-  }
-  cc->outstanding_tags[cc->outstanding_tag_count++] = tag;
-  gpr_mu_unlock(cc->mu);
-#endif
-  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 */
-/* Queue a GRPC_OP_COMPLETED operation */
-void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
-                    void *tag, int success,
-                    void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg,
-                                 grpc_cq_completion *storage),
-                    void *done_arg, grpc_cq_completion *storage) {
-  int shutdown;
-  int i;
-  grpc_pollset_worker *pluck_worker;
-#ifndef NDEBUG
-  int found = 0;
-#endif
-
-  GPR_TIMER_BEGIN("grpc_cq_end_op", 0);
-
-  storage->tag = tag;
-  storage->done = done;
-  storage->done_arg = done_arg;
-  storage->next =
-      ((uintptr_t)&cc->completed_head) | ((uintptr_t)(success != 0));
-
-  gpr_mu_lock(cc->mu);
-#ifndef NDEBUG
-  for (i = 0; i < (int)cc->outstanding_tag_count; i++) {
-    if (cc->outstanding_tags[i] == tag) {
-      cc->outstanding_tag_count--;
-      GPR_SWAP(void *, cc->outstanding_tags[i],
-               cc->outstanding_tags[cc->outstanding_tag_count]);
-      found = 1;
-      break;
-    }
-  }
-  GPR_ASSERT(found);
-#endif
-  shutdown = gpr_unref(&cc->pending_events);
-  if (!shutdown) {
-    cc->completed_tail->next =
-        ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next);
-    cc->completed_tail = storage;
-    pluck_worker = NULL;
-    for (i = 0; i < cc->num_pluckers; i++) {
-      if (cc->pluckers[i].tag == tag) {
-        pluck_worker = *cc->pluckers[i].worker;
-        break;
-      }
-    }
-    grpc_pollset_kick(POLLSET_FROM_CQ(cc), pluck_worker);
-    gpr_mu_unlock(cc->mu);
-  } else {
-    cc->completed_tail->next =
-        ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next);
-    cc->completed_tail = storage;
-    GPR_ASSERT(!cc->shutdown);
-    GPR_ASSERT(cc->shutdown_called);
-    cc->shutdown = 1;
-    grpc_pollset_shutdown(exec_ctx, POLLSET_FROM_CQ(cc),
-                          &cc->pollset_shutdown_done);
-    gpr_mu_unlock(cc->mu);
-  }
-
-  GPR_TIMER_END("grpc_cq_end_op", 0);
-}
-
-grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
-                                      gpr_timespec deadline, void *reserved) {
-  grpc_event ret;
-  grpc_pollset_worker *worker = NULL;
-  int first_loop = 1;
-  gpr_timespec now;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  GPR_TIMER_BEGIN("grpc_completion_queue_next", 0);
-
-  GRPC_API_TRACE(
-      "grpc_completion_queue_next("
-      "cc=%p, "
-      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
-      "reserved=%p)",
-      5, (cc, (long long)deadline.tv_sec, (int)deadline.tv_nsec,
-          (int)deadline.clock_type, reserved));
-  GPR_ASSERT(!reserved);
-
-  deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
-
-  GRPC_CQ_INTERNAL_REF(cc, "next");
-  gpr_mu_lock(cc->mu);
-  for (;;) {
-    if (cc->completed_tail != &cc->completed_head) {
-      grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next;
-      cc->completed_head.next = c->next & ~(uintptr_t)1;
-      if (c == cc->completed_tail) {
-        cc->completed_tail = &cc->completed_head;
-      }
-      gpr_mu_unlock(cc->mu);
-      ret.type = GRPC_OP_COMPLETE;
-      ret.success = c->next & 1u;
-      ret.tag = c->tag;
-      c->done(&exec_ctx, c->done_arg, c);
-      break;
-    }
-    if (cc->shutdown) {
-      gpr_mu_unlock(cc->mu);
-      memset(&ret, 0, sizeof(ret));
-      ret.type = GRPC_QUEUE_SHUTDOWN;
-      break;
-    }
-    now = gpr_now(GPR_CLOCK_MONOTONIC);
-    if (!first_loop && gpr_time_cmp(now, deadline) >= 0) {
-      gpr_mu_unlock(cc->mu);
-      memset(&ret, 0, sizeof(ret));
-      ret.type = GRPC_QUEUE_TIMEOUT;
-      break;
-    }
-    first_loop = 0;
-    /* Check alarms - these are a global resource so we just ping
-       each time through on every pollset.
-       May update deadline to ensure timely wakeups.
-       TODO(ctiller): can this work be localized? */
-    gpr_timespec iteration_deadline = deadline;
-    if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) {
-      GPR_TIMER_MARK("alarm_triggered", 0);
-      gpr_mu_unlock(cc->mu);
-      grpc_exec_ctx_flush(&exec_ctx);
-      gpr_mu_lock(cc->mu);
-      continue;
-    } else {
-      grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), &worker, now,
-                        iteration_deadline);
-    }
-  }
-  GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
-  GRPC_CQ_INTERNAL_UNREF(cc, "next");
-  grpc_exec_ctx_finish(&exec_ctx);
-
-  GPR_TIMER_END("grpc_completion_queue_next", 0);
-
-  return ret;
-}
-
-static int add_plucker(grpc_completion_queue *cc, void *tag,
-                       grpc_pollset_worker **worker) {
-  if (cc->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) {
-    return 0;
-  }
-  cc->pluckers[cc->num_pluckers].tag = tag;
-  cc->pluckers[cc->num_pluckers].worker = worker;
-  cc->num_pluckers++;
-  return 1;
-}
-
-static void del_plucker(grpc_completion_queue *cc, void *tag,
-                        grpc_pollset_worker **worker) {
-  int i;
-  for (i = 0; i < cc->num_pluckers; i++) {
-    if (cc->pluckers[i].tag == tag && cc->pluckers[i].worker == worker) {
-      cc->num_pluckers--;
-      GPR_SWAP(plucker, cc->pluckers[i], cc->pluckers[cc->num_pluckers]);
-      return;
-    }
-  }
-  GPR_UNREACHABLE_CODE(return );
-}
-
-grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
-                                       gpr_timespec deadline, void *reserved) {
-  grpc_event ret;
-  grpc_cq_completion *c;
-  grpc_cq_completion *prev;
-  grpc_pollset_worker *worker = NULL;
-  gpr_timespec now;
-  int first_loop = 1;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0);
-
-  GRPC_API_TRACE(
-      "grpc_completion_queue_pluck("
-      "cc=%p, tag=%p, "
-      "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
-      "reserved=%p)",
-      6, (cc, tag, (long long)deadline.tv_sec, (int)deadline.tv_nsec,
-          (int)deadline.clock_type, reserved));
-  GPR_ASSERT(!reserved);
-
-  deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
-
-  GRPC_CQ_INTERNAL_REF(cc, "pluck");
-  gpr_mu_lock(cc->mu);
-  for (;;) {
-    prev = &cc->completed_head;
-    while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) !=
-           &cc->completed_head) {
-      if (c->tag == tag) {
-        prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1);
-        if (c == cc->completed_tail) {
-          cc->completed_tail = prev;
-        }
-        gpr_mu_unlock(cc->mu);
-        ret.type = GRPC_OP_COMPLETE;
-        ret.success = c->next & 1u;
-        ret.tag = c->tag;
-        c->done(&exec_ctx, c->done_arg, c);
-        goto done;
-      }
-      prev = c;
-    }
-    if (cc->shutdown) {
-      gpr_mu_unlock(cc->mu);
-      memset(&ret, 0, sizeof(ret));
-      ret.type = GRPC_QUEUE_SHUTDOWN;
-      break;
-    }
-    if (!add_plucker(cc, tag, &worker)) {
-      gpr_log(GPR_DEBUG,
-              "Too many outstanding grpc_completion_queue_pluck calls: maximum "
-              "is %d",
-              GRPC_MAX_COMPLETION_QUEUE_PLUCKERS);
-      gpr_mu_unlock(cc->mu);
-      memset(&ret, 0, sizeof(ret));
-      /* TODO(ctiller): should we use a different result here */
-      ret.type = GRPC_QUEUE_TIMEOUT;
-      break;
-    }
-    now = gpr_now(GPR_CLOCK_MONOTONIC);
-    if (!first_loop && gpr_time_cmp(now, deadline) >= 0) {
-      del_plucker(cc, tag, &worker);
-      gpr_mu_unlock(cc->mu);
-      memset(&ret, 0, sizeof(ret));
-      ret.type = GRPC_QUEUE_TIMEOUT;
-      break;
-    }
-    first_loop = 0;
-    /* Check alarms - these are a global resource so we just ping
-       each time through on every pollset.
-       May update deadline to ensure timely wakeups.
-       TODO(ctiller): can this work be localized? */
-    gpr_timespec iteration_deadline = deadline;
-    if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) {
-      GPR_TIMER_MARK("alarm_triggered", 0);
-      gpr_mu_unlock(cc->mu);
-      grpc_exec_ctx_flush(&exec_ctx);
-      gpr_mu_lock(cc->mu);
-    } else {
-      grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), &worker, now,
-                        iteration_deadline);
-    }
-    del_plucker(cc, tag, &worker);
-  }
-done:
-  GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
-  GRPC_CQ_INTERNAL_UNREF(cc, "pluck");
-  grpc_exec_ctx_finish(&exec_ctx);
-
-  GPR_TIMER_END("grpc_completion_queue_pluck", 0);
-
-  return ret;
-}
-
-/* Shutdown simply drops a ref that we reserved at creation time; if we drop
-   to zero here, then enter shutdown mode and wake up any waiters */
-void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  GPR_TIMER_BEGIN("grpc_completion_queue_shutdown", 0);
-  GRPC_API_TRACE("grpc_completion_queue_shutdown(cc=%p)", 1, (cc));
-  gpr_mu_lock(cc->mu);
-  if (cc->shutdown_called) {
-    gpr_mu_unlock(cc->mu);
-    GPR_TIMER_END("grpc_completion_queue_shutdown", 0);
-    return;
-  }
-  cc->shutdown_called = 1;
-  if (gpr_unref(&cc->pending_events)) {
-    GPR_ASSERT(!cc->shutdown);
-    cc->shutdown = 1;
-    grpc_pollset_shutdown(&exec_ctx, POLLSET_FROM_CQ(cc),
-                          &cc->pollset_shutdown_done);
-  }
-  gpr_mu_unlock(cc->mu);
-  grpc_exec_ctx_finish(&exec_ctx);
-  GPR_TIMER_END("grpc_completion_queue_shutdown", 0);
-}
-
-void grpc_completion_queue_destroy(grpc_completion_queue *cc) {
-  GRPC_API_TRACE("grpc_completion_queue_destroy(cc=%p)", 1, (cc));
-  GPR_TIMER_BEGIN("grpc_completion_queue_destroy", 0);
-  grpc_completion_queue_shutdown(cc);
-  GRPC_CQ_INTERNAL_UNREF(cc, "destroy");
-  GPR_TIMER_END("grpc_completion_queue_destroy", 0);
-}
-
-grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) {
-  return POLLSET_FROM_CQ(cc);
-}
-
-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
deleted file mode 100644
index 27ef90f..0000000
--- a/src/core/surface/completion_queue.h
+++ /dev/null
@@ -1,91 +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_SURFACE_COMPLETION_QUEUE_H
-#define GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H
-
-/* Internal API for completion queues */
-
-#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)(grpc_exec_ctx *exec_ctx, void *done_arg,
-               struct grpc_cq_completion *c);
-  void *done_arg;
-  /** next pointer; low bit is used to indicate success or not */
-  uintptr_t 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.
-   \a tag is currently used only in debug builds. */
-void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag);
-
-/* Queue a GRPC_OP_COMPLETED operation; tag must correspond to the tag passed to
-   grpc_cq_begin_op */
-void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
-                    void *tag, int success,
-                    void (*done)(grpc_exec_ctx *exec_ctx, 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_mark_server_cq(grpc_completion_queue *cc);
-int grpc_cq_is_server_cq(grpc_completion_queue *cc);
-
-void grpc_cq_global_init(void);
-void grpc_cq_global_shutdown(void);
-
-#endif /* GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H */
diff --git a/src/core/surface/event_string.c b/src/core/surface/event_string.c
deleted file mode 100644
index 33cd4a4..0000000
--- a/src/core/surface/event_string.c
+++ /dev/null
@@ -1,81 +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/event_string.h"
-
-#include <stdio.h>
-
-#include "src/core/support/string.h"
-#include <grpc/byte_buffer.h>
-#include <grpc/support/string_util.h>
-
-static void addhdr(gpr_strvec *buf, grpc_event *ev) {
-  char *tmp;
-  gpr_asprintf(&tmp, "tag:%p", ev->tag);
-  gpr_strvec_add(buf, tmp);
-}
-
-static const char *errstr(int success) { return success ? "OK" : "ERROR"; }
-
-static void adderr(gpr_strvec *buf, int success) {
-  char *tmp;
-  gpr_asprintf(&tmp, " %s", errstr(success));
-  gpr_strvec_add(buf, tmp);
-}
-
-char *grpc_event_string(grpc_event *ev) {
-  char *out;
-  gpr_strvec buf;
-
-  if (ev == NULL) return gpr_strdup("null");
-
-  gpr_strvec_init(&buf);
-
-  switch (ev->type) {
-    case GRPC_QUEUE_TIMEOUT:
-      gpr_strvec_add(&buf, gpr_strdup("QUEUE_TIMEOUT"));
-      break;
-    case GRPC_QUEUE_SHUTDOWN:
-      gpr_strvec_add(&buf, gpr_strdup("QUEUE_SHUTDOWN"));
-      break;
-    case GRPC_OP_COMPLETE:
-      gpr_strvec_add(&buf, gpr_strdup("OP_COMPLETE: "));
-      addhdr(&buf, ev);
-      adderr(&buf, ev->success);
-      break;
-  }
-
-  out = gpr_strvec_flatten(&buf, NULL);
-  gpr_strvec_destroy(&buf);
-  return out;
-}
diff --git a/src/core/surface/event_string.h b/src/core/surface/event_string.h
deleted file mode 100644
index 07c474e..0000000
--- a/src/core/surface/event_string.h
+++ /dev/null
@@ -1,42 +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_SURFACE_EVENT_STRING_H
-#define GRPC_INTERNAL_CORE_SURFACE_EVENT_STRING_H
-
-#include <grpc/grpc.h>
-
-/* Returns a string describing an event. Must be later freed with gpr_free() */
-char *grpc_event_string(grpc_event *ev);
-
-#endif /* GRPC_INTERNAL_CORE_SURFACE_EVENT_STRING_H */
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
deleted file mode 100644
index a4a53d3..0000000
--- a/src/core/surface/init.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#include <memory.h>
-
-#include <grpc/census.h>
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/time.h>
-#include "src/core/channel/channel_stack.h"
-#include "src/core/client_config/lb_policy_registry.h"
-#include "src/core/client_config/lb_policies/pick_first.h"
-#include "src/core/client_config/lb_policies/round_robin.h"
-#include "src/core/client_config/resolver_registry.h"
-#include "src/core/client_config/resolvers/dns_resolver.h"
-#include "src/core/client_config/resolvers/sockaddr_resolver.h"
-#include "src/core/client_config/subchannel.h"
-#include "src/core/client_config/subchannel_index.h"
-#include "src/core/debug/trace.h"
-#include "src/core/iomgr/executor.h"
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/profiling/timers.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/call.h"
-#include "src/core/surface/completion_queue.h"
-#include "src/core/surface/init.h"
-#include "src/core/surface/surface_trace.h"
-#include "src/core/transport/chttp2_transport.h"
-#include "src/core/transport/connectivity_state.h"
-
-#ifndef GRPC_DEFAULT_NAME_PREFIX
-#define GRPC_DEFAULT_NAME_PREFIX "dns:///"
-#endif
-
-#define MAX_PLUGINS 128
-
-static gpr_once g_basic_init = GPR_ONCE_INIT;
-static gpr_mu g_init_mu;
-static int g_initializations;
-
-static void do_basic_init(void) {
-  gpr_mu_init(&g_init_mu);
-  g_initializations = 0;
-}
-
-typedef struct grpc_plugin {
-  void (*init)();
-  void (*destroy)();
-} grpc_plugin;
-
-static grpc_plugin g_all_of_the_plugins[MAX_PLUGINS];
-static int g_number_of_plugins = 0;
-
-void grpc_register_plugin(void (*init)(void), void (*destroy)(void)) {
-  GRPC_API_TRACE("grpc_register_plugin(init=%p, destroy=%p)", 2,
-                 ((void*)(intptr_t)init, (void*)(intptr_t)destroy));
-  GPR_ASSERT(g_number_of_plugins != MAX_PLUGINS);
-  g_all_of_the_plugins[g_number_of_plugins].init = init;
-  g_all_of_the_plugins[g_number_of_plugins].destroy = destroy;
-  g_number_of_plugins++;
-}
-
-void grpc_init(void) {
-  int i;
-  gpr_once_init(&g_basic_init, do_basic_init);
-
-  gpr_mu_lock(&g_init_mu);
-  if (++g_initializations == 1) {
-    gpr_time_init();
-    grpc_mdctx_global_init();
-    grpc_lb_policy_registry_init(grpc_pick_first_lb_factory_create());
-    grpc_register_lb_policy(grpc_pick_first_lb_factory_create());
-    grpc_register_lb_policy(grpc_round_robin_lb_factory_create());
-    grpc_resolver_registry_init(GRPC_DEFAULT_NAME_PREFIX);
-    grpc_register_resolver_type(grpc_dns_resolver_factory_create());
-    grpc_register_resolver_type(grpc_ipv4_resolver_factory_create());
-    grpc_register_resolver_type(grpc_ipv6_resolver_factory_create());
-#ifdef GPR_POSIX_SOCKET
-    grpc_register_resolver_type(grpc_unix_resolver_factory_create());
-#endif
-    grpc_register_tracer("api", &grpc_api_trace);
-    grpc_register_tracer("channel", &grpc_trace_channel);
-    grpc_register_tracer("http", &grpc_http_trace);
-    grpc_register_tracer("flowctl", &grpc_flowctl_trace);
-    grpc_register_tracer("connectivity_state", &grpc_connectivity_state_trace);
-    grpc_security_pre_init();
-    grpc_iomgr_init();
-    grpc_executor_init();
-    grpc_tracer_init("GRPC_TRACE");
-    /* Only initialize census if no one else has and some features are
-     * available. */
-    if (census_enabled() == CENSUS_FEATURE_NONE &&
-        census_supported() != CENSUS_FEATURE_NONE) {
-      if (census_initialize(census_supported())) { /* enable all features. */
-        gpr_log(GPR_ERROR, "Could not initialize census.");
-      }
-    }
-    gpr_timers_global_init();
-    grpc_cq_global_init();
-    grpc_subchannel_index_init();
-    for (i = 0; i < g_number_of_plugins; i++) {
-      if (g_all_of_the_plugins[i].init != NULL) {
-        g_all_of_the_plugins[i].init();
-      }
-    }
-  }
-  gpr_mu_unlock(&g_init_mu);
-  GRPC_API_TRACE("grpc_init(void)", 0, ());
-}
-
-void grpc_shutdown(void) {
-  int i;
-  GRPC_API_TRACE("grpc_shutdown(void)", 0, ());
-  gpr_mu_lock(&g_init_mu);
-  if (--g_initializations == 0) {
-    grpc_executor_shutdown();
-    grpc_cq_global_shutdown();
-    grpc_iomgr_shutdown();
-    grpc_subchannel_index_shutdown();
-    census_shutdown();
-    gpr_timers_global_destroy();
-    grpc_tracer_shutdown();
-    grpc_resolver_registry_shutdown();
-    grpc_lb_policy_registry_shutdown();
-    for (i = 0; i < g_number_of_plugins; i++) {
-      if (g_all_of_the_plugins[i].destroy != NULL) {
-        g_all_of_the_plugins[i].destroy();
-      }
-    }
-    grpc_mdctx_global_shutdown();
-  }
-  gpr_mu_unlock(&g_init_mu);
-}
-
-int grpc_is_initialized(void) {
-  int r;
-  gpr_once_init(&g_basic_init, do_basic_init);
-  gpr_mu_lock(&g_init_mu);
-  r = g_initializations > 0;
-  gpr_mu_unlock(&g_init_mu);
-  return r;
-}
diff --git a/src/core/surface/init.h b/src/core/surface/init.h
deleted file mode 100644
index 771c30f..0000000
--- a/src/core/surface/init.h
+++ /dev/null
@@ -1,40 +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_SURFACE_INIT_H
-#define GRPC_INTERNAL_CORE_SURFACE_INIT_H
-
-void grpc_security_pre_init(void);
-int grpc_is_initialized(void);
-
-#endif /* GRPC_INTERNAL_CORE_SURFACE_INIT_H */
diff --git a/src/core/surface/init_secure.c b/src/core/surface/init_secure.c
deleted file mode 100644
index fa20e91..0000000
--- a/src/core/surface/init_secure.c
+++ /dev/null
@@ -1,42 +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/init.h"
-#include "src/core/debug/trace.h"
-#include "src/core/security/secure_endpoint.h"
-#include "src/core/tsi/transport_security_interface.h"
-
-void grpc_security_pre_init(void) {
-  grpc_register_tracer("secure_endpoint", &grpc_trace_secure_endpoint);
-  grpc_register_tracer("transport_security", &tsi_tracing_enabled);
-}
diff --git a/src/core/surface/init_unsecure.c b/src/core/surface/init_unsecure.c
deleted file mode 100644
index 630d564..0000000
--- a/src/core/surface/init_unsecure.c
+++ /dev/null
@@ -1,36 +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/init.h"
-
-void grpc_security_pre_init(void) {}
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
deleted file mode 100644
index 537069e..0000000
--- a/src/core/surface/lame_client.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/grpc.h>
-
-#include <string.h>
-
-#include "src/core/channel/channel_stack.h"
-#include "src/core/support/string.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/channel.h"
-#include "src/core/surface/call.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-typedef struct {
-  grpc_linked_mdelem status;
-  grpc_linked_mdelem details;
-} call_data;
-
-typedef struct {
-  grpc_status_code error_code;
-  const char *error_message;
-} channel_data;
-
-static void fill_metadata(grpc_call_element *elem, grpc_metadata_batch *mdb) {
-  call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
-  char tmp[GPR_LTOA_MIN_BUFSIZE];
-  gpr_ltoa(chand->error_code, tmp);
-  calld->status.md = grpc_mdelem_from_strings("grpc-status", tmp);
-  calld->details.md =
-      grpc_mdelem_from_strings("grpc-message", chand->error_message);
-  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->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
-}
-
-static void lame_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                           grpc_call_element *elem,
-                                           grpc_transport_stream_op *op) {
-  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-  if (op->recv_initial_metadata != NULL) {
-    fill_metadata(elem, op->recv_initial_metadata);
-  } else if (op->recv_trailing_metadata != NULL) {
-    fill_metadata(elem, op->recv_trailing_metadata);
-  }
-  grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
-}
-
-static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
-  return NULL;
-}
-
-static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
-                                    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(
-        exec_ctx, op->on_connectivity_state_change->cb_arg, 1);
-  }
-  if (op->on_consumed != NULL) {
-    op->on_consumed->cb(exec_ctx, op->on_consumed->cb_arg, 1);
-  }
-}
-
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {}
-
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {}
-
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
-  GPR_ASSERT(args->is_first);
-  GPR_ASSERT(args->is_last);
-}
-
-static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem) {}
-
-static const grpc_channel_filter lame_filter = {
-    lame_start_transport_stream_op, lame_start_transport_op, sizeof(call_data),
-    init_call_elem, grpc_call_stack_ignore_set_pollset, destroy_call_elem,
-    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
-    lame_get_peer, "lame-client",
-};
-
-#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1))
-
-grpc_channel *grpc_lame_client_channel_create(const char *target,
-                                              grpc_status_code error_code,
-                                              const char *error_message) {
-  grpc_channel *channel;
-  grpc_channel_element *elem;
-  channel_data *chand;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  static const grpc_channel_filter *filters[] = {&lame_filter};
-  channel =
-      grpc_channel_create_from_filters(&exec_ctx, target, filters, 1, NULL, 1);
-  elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
-  GRPC_API_TRACE(
-      "grpc_lame_client_channel_create(target=%s, error_code=%d, "
-      "error_message=%s)",
-      3, (target, (int)error_code, error_message));
-  GPR_ASSERT(elem->filter == &lame_filter);
-  chand = (channel_data *)elem->channel_data;
-  chand->error_code = error_code;
-  chand->error_message = error_message;
-  grpc_exec_ctx_finish(&exec_ctx);
-  return channel;
-}
diff --git a/src/core/surface/metadata_array.c b/src/core/surface/metadata_array.c
deleted file mode 100644
index 4c7bf17..0000000
--- a/src/core/surface/metadata_array.c
+++ /dev/null
@@ -1,49 +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/grpc.h>
-#include <grpc/support/alloc.h>
-
-#include <string.h>
-
-#include "src/core/surface/api_trace.h"
-
-void grpc_metadata_array_init(grpc_metadata_array* array) {
-  GRPC_API_TRACE("grpc_metadata_array_init(array=%p)", 1, (array));
-  memset(array, 0, sizeof(*array));
-}
-
-void grpc_metadata_array_destroy(grpc_metadata_array* array) {
-  GRPC_API_TRACE("grpc_metadata_array_destroy(array=%p)", 1, (array));
-  gpr_free(array->metadata);
-}
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
deleted file mode 100644
index aadfac4..0000000
--- a/src/core/surface/secure_channel_create.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/grpc.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
-
-#include "src/core/census/grpc_filter.h"
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/client_channel.h"
-#include "src/core/channel/compress_filter.h"
-#include "src/core/channel/http_client_filter.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/security_context.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/channel.h"
-#include "src/core/transport/chttp2_transport.h"
-#include "src/core/tsi/transport_security_interface.h"
-
-typedef struct {
-  grpc_connector base;
-  gpr_refcount refs;
-
-  grpc_channel_security_connector *security_connector;
-
-  grpc_closure *notify;
-  grpc_connect_in_args args;
-  grpc_connect_out_args *result;
-  grpc_closure initial_string_sent;
-  gpr_slice_buffer initial_string_buffer;
-
-  gpr_mu mu;
-  grpc_endpoint *connecting_endpoint;
-  grpc_endpoint *newly_connecting_endpoint;
-
-  grpc_closure connected_closure;
-} connector;
-
-static void connector_ref(grpc_connector *con) {
-  connector *c = (connector *)con;
-  gpr_ref(&c->refs);
-}
-
-static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
-  connector *c = (connector *)con;
-  if (gpr_unref(&c->refs)) {
-    /* c->initial_string_buffer does not need to be destroyed */
-    gpr_free(c);
-  }
-}
-
-static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
-                                     grpc_security_status status,
-                                     grpc_endpoint *secure_endpoint,
-                                     grpc_auth_context *auth_context) {
-  connector *c = arg;
-  grpc_closure *notify;
-  grpc_channel_args *args_copy = NULL;
-  gpr_mu_lock(&c->mu);
-  if (c->connecting_endpoint == NULL) {
-    memset(c->result, 0, sizeof(*c->result));
-    gpr_mu_unlock(&c->mu);
-  } else if (status != GRPC_SECURITY_OK) {
-    gpr_log(GPR_ERROR, "Secure handshake failed with error %d.", status);
-    memset(c->result, 0, sizeof(*c->result));
-    c->connecting_endpoint = NULL;
-    gpr_mu_unlock(&c->mu);
-  } else {
-    grpc_arg auth_context_arg;
-    c->connecting_endpoint = NULL;
-    gpr_mu_unlock(&c->mu);
-    c->result->transport = grpc_create_chttp2_transport(
-        exec_ctx, c->args.channel_args, secure_endpoint, 1);
-    grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
-                                        0);
-    auth_context_arg = grpc_auth_context_to_arg(auth_context);
-    args_copy = grpc_channel_args_copy_and_add(c->args.channel_args,
-                                               &auth_context_arg, 1);
-    c->result->channel_args = args_copy;
-    c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *) * 2);
-    c->result->filters[0] = &grpc_http_client_filter;
-    c->result->filters[1] = &grpc_client_auth_filter;
-    c->result->num_filters = 2;
-  }
-  notify = c->notify;
-  c->notify = NULL;
-  /* look at c->args which are connector args. */
-  notify->cb(exec_ctx, notify->cb_arg, 1);
-  if (args_copy != NULL) grpc_channel_args_destroy(args_copy);
-}
-
-static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
-                                           bool success) {
-  connector *c = arg;
-  grpc_channel_security_connector_do_handshake(exec_ctx, c->security_connector,
-                                               c->connecting_endpoint,
-                                               on_secure_handshake_done, c);
-}
-
-static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  connector *c = arg;
-  grpc_closure *notify;
-  grpc_endpoint *tcp = c->newly_connecting_endpoint;
-  if (tcp != NULL) {
-    gpr_mu_lock(&c->mu);
-    GPR_ASSERT(c->connecting_endpoint == NULL);
-    c->connecting_endpoint = tcp;
-    gpr_mu_unlock(&c->mu);
-    if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
-      grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
-                        c);
-      gpr_slice_buffer_init(&c->initial_string_buffer);
-      gpr_slice_buffer_add(&c->initial_string_buffer,
-                           c->args.initial_connect_string);
-      grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
-                          &c->initial_string_sent);
-    } else {
-      grpc_channel_security_connector_do_handshake(
-          exec_ctx, c->security_connector, tcp, on_secure_handshake_done, c);
-    }
-  } else {
-    memset(c->result, 0, sizeof(*c->result));
-    notify = c->notify;
-    c->notify = NULL;
-    notify->cb(exec_ctx, notify->cb_arg, 1);
-  }
-}
-
-static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
-  connector *c = (connector *)con;
-  grpc_endpoint *ep;
-  gpr_mu_lock(&c->mu);
-  ep = c->connecting_endpoint;
-  c->connecting_endpoint = NULL;
-  gpr_mu_unlock(&c->mu);
-  if (ep) {
-    grpc_endpoint_shutdown(exec_ctx, ep);
-  }
-}
-
-static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
-                              const grpc_connect_in_args *args,
-                              grpc_connect_out_args *result,
-                              grpc_closure *notify) {
-  connector *c = (connector *)con;
-  GPR_ASSERT(c->notify == NULL);
-  GPR_ASSERT(notify->cb);
-  c->notify = notify;
-  c->args = *args;
-  c->result = result;
-  gpr_mu_lock(&c->mu);
-  GPR_ASSERT(c->connecting_endpoint == NULL);
-  gpr_mu_unlock(&c->mu);
-  grpc_closure_init(&c->connected_closure, connected, c);
-  grpc_tcp_client_connect(
-      exec_ctx, &c->connected_closure, &c->newly_connecting_endpoint,
-      args->interested_parties, args->addr, args->addr_len, args->deadline);
-}
-
-static const grpc_connector_vtable connector_vtable = {
-    connector_ref, connector_unref, connector_shutdown, connector_connect};
-
-typedef struct {
-  grpc_subchannel_factory base;
-  gpr_refcount refs;
-  grpc_channel_args *merge_args;
-  grpc_channel_security_connector *security_connector;
-  grpc_channel *master;
-} 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_exec_ctx *exec_ctx,
-                                     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_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory");
-    grpc_channel_args_destroy(f->merge_args);
-    gpr_free(f);
-  }
-}
-
-static grpc_subchannel *subchannel_factory_create_subchannel(
-    grpc_exec_ctx *exec_ctx, 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_mu_init(&c->mu);
-  gpr_ref_init(&c->refs, 1);
-  args->args = final_args;
-  s = grpc_subchannel_create(exec_ctx, &c->base, args);
-  grpc_connector_unref(exec_ctx, &c->base);
-  grpc_channel_args_destroy(final_args);
-  return s;
-}
-
-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
-                   - connect to it (trying alternatives as presented)
-                   - perform handshakes */
-grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
-                                         const char *target,
-                                         const grpc_channel_args *args,
-                                         void *reserved) {
-  grpc_channel *channel;
-  grpc_arg connector_arg;
-  grpc_channel_args *args_copy;
-  grpc_channel_args *new_args_from_connector;
-  grpc_channel_security_connector *security_connector;
-  grpc_resolver *resolver;
-  subchannel_factory *f;
-#define MAX_FILTERS 3
-  const grpc_channel_filter *filters[MAX_FILTERS];
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  size_t n = 0;
-
-  GRPC_API_TRACE(
-      "grpc_secure_channel_create(creds=%p, target=%s, args=%p, "
-      "reserved=%p)",
-      4, (creds, target, args, reserved));
-  GPR_ASSERT(reserved == NULL);
-
-  if (grpc_find_security_connector_in_args(args) != NULL) {
-    gpr_log(GPR_ERROR, "Cannot set security context in channel args.");
-    grpc_exec_ctx_finish(&exec_ctx);
-    return grpc_lame_client_channel_create(
-        target, GRPC_STATUS_INVALID_ARGUMENT,
-        "Security connector exists in channel args.");
-  }
-
-  if (grpc_channel_credentials_create_security_connector(
-          creds, target, args, &security_connector, &new_args_from_connector) !=
-      GRPC_SECURITY_OK) {
-    grpc_exec_ctx_finish(&exec_ctx);
-    return grpc_lame_client_channel_create(
-        target, GRPC_STATUS_INVALID_ARGUMENT,
-        "Failed to create security connector.");
-  }
-
-  connector_arg = grpc_security_connector_to_arg(&security_connector->base);
-  args_copy = grpc_channel_args_copy_and_add(
-      new_args_from_connector != NULL ? new_args_from_connector : args,
-      &connector_arg, 1);
-  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);
-
-  channel = grpc_channel_create_from_filters(&exec_ctx, target, filters, n,
-                                             args_copy, 1);
-
-  f = gpr_malloc(sizeof(*f));
-  f->base.vtable = &subchannel_factory_vtable;
-  gpr_ref_init(&f->refs, 1);
-  GRPC_SECURITY_CONNECTOR_REF(&security_connector->base, "subchannel_factory");
-  f->security_connector = security_connector;
-  f->merge_args = grpc_channel_args_copy(args_copy);
-  f->master = channel;
-  GRPC_CHANNEL_INTERNAL_REF(channel, "subchannel_factory");
-  resolver = grpc_resolver_create(target, &f->base);
-  if (resolver) {
-    grpc_client_channel_set_resolver(
-        &exec_ctx, grpc_channel_get_channel_stack(channel), resolver);
-    GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "create");
-  }
-  grpc_subchannel_factory_unref(&exec_ctx, &f->base);
-  GRPC_SECURITY_CONNECTOR_UNREF(&security_connector->base, "channel_create");
-  grpc_channel_args_destroy(args_copy);
-  if (new_args_from_connector != NULL) {
-    grpc_channel_args_destroy(new_args_from_connector);
-  }
-
-  if (!resolver) {
-    GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, channel, "subchannel_factory");
-    channel = NULL;
-  }
-  grpc_exec_ctx_finish(&exec_ctx);
-
-  return channel;
-}
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
deleted file mode 100644
index 5b13d4b..0000000
--- a/src/core/surface/server.c
+++ /dev/null
@@ -1,1351 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/surface/server.h"
-
-#include <limits.h>
-#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/census/grpc_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/api_trace.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 "src/core/transport/static_metadata.h"
-
-typedef struct listener {
-  void *arg;
-  void (*start)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
-                grpc_pollset **pollsets, size_t pollset_count);
-  void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
-                  grpc_closure *closure);
-  struct listener *next;
-  grpc_closure destroy_done;
-} listener;
-
-typedef struct call_data call_data;
-typedef struct channel_data channel_data;
-typedef struct registered_method registered_method;
-
-typedef struct {
-  call_data *next;
-  call_data *prev;
-} call_link;
-
-typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type;
-
-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;
-  grpc_metadata_array *initial_metadata;
-  union {
-    struct {
-      grpc_call_details *details;
-    } batch;
-    struct {
-      registered_method *registered_method;
-      gpr_timespec *deadline;
-      grpc_byte_buffer **optional_payload;
-    } registered;
-  } data;
-  grpc_closure publish;
-} requested_call;
-
-typedef struct channel_registered_method {
-  registered_method *server_registered_method;
-  grpc_mdstr *method;
-  grpc_mdstr *host;
-} channel_registered_method;
-
-struct channel_data {
-  grpc_server *server;
-  grpc_connectivity_state connectivity_state;
-  grpc_channel *channel;
-  /* linked list of all channels on a server */
-  channel_data *next;
-  channel_data *prev;
-  channel_registered_method *registered_methods;
-  uint32_t registered_method_slots;
-  uint32_t registered_method_max_probes;
-  grpc_closure finish_destroy_channel_closure;
-  grpc_closure channel_connectivity_changed;
-};
-
-typedef struct shutdown_tag {
-  void *tag;
-  grpc_completion_queue *cq;
-  grpc_cq_completion completion;
-} shutdown_tag;
-
-typedef enum {
-  /* waiting for metadata */
-  NOT_STARTED,
-  /* inital metadata read, not flow controlled in yet */
-  PENDING,
-  /* flow controlled in, on completion queue */
-  ACTIVATED,
-  /* cancelled before being queued */
-  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;
-
-  grpc_completion_queue *cq_new;
-
-  grpc_metadata_batch *recv_initial_metadata;
-  grpc_metadata_array initial_metadata;
-
-  grpc_closure got_initial_metadata;
-  grpc_closure server_on_recv_initial_metadata;
-  grpc_closure kill_zombie_closure;
-  grpc_closure *on_done_recv_initial_metadata;
-
-  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;
-  grpc_channel_filter const **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;
-  size_t max_requested_calls;
-
-  gpr_atm shutdown_flag;
-  uint8_t 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) \
-  (((channel_data *)(elem)->channel_data)->server)
-
-static void begin_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
-                       call_data *calld, requested_call *rc);
-static void fail_call(grpc_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx, grpc_server *server);
-
-/*
- * 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++;
-  }
-  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");
-  }
-}
-
-struct shutdown_cleanup_args {
-  grpc_closure closure;
-  gpr_slice slice;
-};
-
-static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg,
-                             bool iomgr_status_ignored) {
-  struct shutdown_cleanup_args *a = arg;
-  gpr_slice_unref(a->slice);
-  gpr_free(a);
-}
-
-static void send_shutdown(grpc_exec_ctx *exec_ctx, 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_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(exec_ctx, elem, &op);
-}
-
-static void channel_broadcaster_shutdown(grpc_exec_ctx *exec_ctx,
-                                         channel_broadcaster *cb,
-                                         int send_goaway,
-                                         int force_disconnect) {
-  size_t i;
-
-  for (i = 0; i < cb->num_channels; i++) {
-    send_shutdown(exec_ctx, cb->channels[i], send_goaway, force_disconnect);
-    GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, cb->channels[i], "broadcast");
-  }
-  gpr_free(cb->channels);
-}
-
-/*
- * request_matcher
- */
-
-static void request_matcher_init(request_matcher *rm, size_t entries) {
-  memset(rm, 0, sizeof(*rm));
-  rm->requests = gpr_stack_lockfree_create(entries);
-}
-
-static void request_matcher_destroy(request_matcher *rm) {
-  GPR_ASSERT(gpr_stack_lockfree_pop(rm->requests) == -1);
-  gpr_stack_lockfree_destroy(rm->requests);
-}
-
-static void kill_zombie(grpc_exec_ctx *exec_ctx, void *elem, bool success) {
-  grpc_call_destroy(grpc_call_from_top_element(elem));
-}
-
-static void request_matcher_zombify_all_pending_calls(grpc_exec_ctx *exec_ctx,
-                                                      request_matcher *rm) {
-  while (rm->pending_head) {
-    call_data *calld = rm->pending_head;
-    rm->pending_head = calld->pending_next;
-    gpr_mu_lock(&calld->mu_state);
-    calld->state = ZOMBIED;
-    gpr_mu_unlock(&calld->mu_state);
-    grpc_closure_init(
-        &calld->kill_zombie_closure, kill_zombie,
-        grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
-    grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
-  }
-}
-
-static void request_matcher_kill_requests(grpc_exec_ctx *exec_ctx,
-                                          grpc_server *server,
-                                          request_matcher *rm) {
-  int request_id;
-  while ((request_id = gpr_stack_lockfree_pop(rm->requests)) != -1) {
-    fail_call(exec_ctx, server, &server->requested_calls[request_id]);
-  }
-}
-
-/*
- * server proper
- */
-
-static void server_ref(grpc_server *server) {
-  gpr_ref(&server->internal_refcount);
-}
-
-static void server_delete(grpc_exec_ctx *exec_ctx, grpc_server *server) {
-  registered_method *rm;
-  size_t i;
-  grpc_channel_args_destroy(server->channel_args);
-  gpr_mu_destroy(&server->mu_global);
-  gpr_mu_destroy(&server->mu_call);
-  gpr_free((void *)server->channel_filters);
-  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);
-    gpr_free(rm);
-  }
-  for (i = 0; i < server->cq_count; 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);
-}
-
-static void server_unref(grpc_exec_ctx *exec_ctx, grpc_server *server) {
-  if (gpr_unref(&server->internal_refcount)) {
-    server_delete(exec_ctx, server);
-  }
-}
-
-static int is_channel_orphaned(channel_data *chand) {
-  return chand->next == chand;
-}
-
-static void orphan_channel(channel_data *chand) {
-  chand->next->prev = chand->prev;
-  chand->prev->next = chand->next;
-  chand->next = chand->prev = chand;
-}
-
-static void finish_destroy_channel(grpc_exec_ctx *exec_ctx, void *cd,
-                                   bool success) {
-  channel_data *chand = cd;
-  grpc_server *server = chand->server;
-  GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "server");
-  server_unref(exec_ctx, server);
-}
-
-static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand) {
-  if (is_channel_orphaned(chand)) return;
-  GPR_ASSERT(chand->server != NULL);
-  orphan_channel(chand);
-  server_ref(chand->server);
-  maybe_finish_shutdown(exec_ctx, chand->server);
-  chand->finish_destroy_channel_closure.cb = finish_destroy_channel;
-  chand->finish_destroy_channel_closure.cb_arg = chand;
-
-  grpc_transport_op op;
-  memset(&op, 0, sizeof(op));
-  op.set_accept_stream = true;
-  op.on_consumed = &chand->finish_destroy_channel_closure;
-  grpc_channel_next_op(exec_ctx,
-                       grpc_channel_stack_element(
-                           grpc_channel_get_channel_stack(chand->channel), 0),
-                       &op);
-}
-
-static void finish_start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_server *server,
-                                 grpc_call_element *elem, request_matcher *rm) {
-  call_data *calld = elem->call_data;
-  int request_id;
-
-  if (gpr_atm_acq_load(&server->shutdown_flag)) {
-    gpr_mu_lock(&calld->mu_state);
-    calld->state = ZOMBIED;
-    gpr_mu_unlock(&calld->mu_state);
-    grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
-    grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
-    return;
-  }
-
-  request_id = gpr_stack_lockfree_pop(rm->requests);
-  if (request_id == -1) {
-    gpr_mu_lock(&server->mu_call);
-    gpr_mu_lock(&calld->mu_state);
-    calld->state = PENDING;
-    gpr_mu_unlock(&calld->mu_state);
-    if (rm->pending_head == NULL) {
-      rm->pending_tail = rm->pending_head = calld;
-    } else {
-      rm->pending_tail->pending_next = calld;
-      rm->pending_tail = calld;
-    }
-    calld->pending_next = NULL;
-    gpr_mu_unlock(&server->mu_call);
-  } else {
-    gpr_mu_lock(&calld->mu_state);
-    calld->state = ACTIVATED;
-    gpr_mu_unlock(&calld->mu_state);
-    begin_call(exec_ctx, server, calld, &server->requested_calls[request_id]);
-  }
-}
-
-static void start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
-  channel_data *chand = elem->channel_data;
-  call_data *calld = elem->call_data;
-  grpc_server *server = chand->server;
-  uint32_t i;
-  uint32_t hash;
-  channel_registered_method *rm;
-
-  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++) {
-      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(exec_ctx, server, elem,
-                           &rm->server_registered_method->request_matcher);
-      return;
-    }
-    /* check for a wildcard method definition (no host set) */
-    hash = GRPC_MDSTR_KV_HASH(0, calld->path->hash);
-    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 != NULL) continue;
-      if (rm->method != calld->path) continue;
-      finish_start_new_rpc(exec_ctx, server, elem,
-                           &rm->server_registered_method->request_matcher);
-      return;
-    }
-  }
-  finish_start_new_rpc(exec_ctx, server, elem,
-                       &server->unregistered_request_matcher);
-}
-
-static int num_listeners(grpc_server *server) {
-  listener *l;
-  int n = 0;
-  for (l = server->listeners; l; l = l->next) {
-    n++;
-  }
-  return n;
-}
-
-static void done_shutdown_event(grpc_exec_ctx *exec_ctx, void *server,
-                                grpc_cq_completion *completion) {
-  server_unref(exec_ctx, 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 kill_pending_work_locked(grpc_exec_ctx *exec_ctx,
-                                     grpc_server *server) {
-  registered_method *rm;
-  request_matcher_kill_requests(exec_ctx, server,
-                                &server->unregistered_request_matcher);
-  request_matcher_zombify_all_pending_calls(
-      exec_ctx, &server->unregistered_request_matcher);
-  for (rm = server->registered_methods; rm; rm = rm->next) {
-    request_matcher_kill_requests(exec_ctx, server, &rm->request_matcher);
-    request_matcher_zombify_all_pending_calls(exec_ctx, &rm->request_matcher);
-  }
-}
-
-static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx,
-                                  grpc_server *server) {
-  size_t i;
-  if (!gpr_atm_acq_load(&server->shutdown_flag) || server->shutdown_published) {
-    return;
-  }
-
-  kill_pending_work_locked(exec_ctx, server);
-
-  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(exec_ctx, server->shutdown_tags[i].cq,
-                   server->shutdown_tags[i].tag, 1, done_shutdown_event, server,
-                   &server->shutdown_tags[i].completion);
-  }
-}
-
-static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
-  grpc_call_element *elem = user_data;
-  call_data *calld = elem->call_data;
-  if (md->key == GRPC_MDSTR_PATH) {
-    calld->path = GRPC_MDSTR_REF(md->value);
-    return NULL;
-  } else if (md->key == GRPC_MDSTR_AUTHORITY) {
-    calld->host = GRPC_MDSTR_REF(md->value);
-    return NULL;
-  }
-  return md;
-}
-
-static void server_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
-                                            bool success) {
-  grpc_call_element *elem = ptr;
-  call_data *calld = elem->call_data;
-  gpr_timespec op_deadline;
-
-  grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, elem);
-  op_deadline = calld->recv_initial_metadata->deadline;
-  if (0 != gpr_time_cmp(op_deadline, gpr_inf_future(op_deadline.clock_type))) {
-    calld->deadline = op_deadline;
-  }
-  if (calld->host && calld->path) {
-    /* do nothing */
-  } else {
-    success = 0;
-  }
-
-  calld->on_done_recv_initial_metadata->cb(
-      exec_ctx, calld->on_done_recv_initial_metadata->cb_arg, success);
-}
-
-static void server_mutate_op(grpc_call_element *elem,
-                             grpc_transport_stream_op *op) {
-  call_data *calld = elem->call_data;
-
-  if (op->recv_initial_metadata != NULL) {
-    calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready = &calld->server_on_recv_initial_metadata;
-  }
-}
-
-static void server_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                             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(exec_ctx, elem, op);
-}
-
-static void got_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
-                                 bool success) {
-  grpc_call_element *elem = ptr;
-  call_data *calld = elem->call_data;
-  if (success) {
-    start_new_rpc(exec_ctx, elem);
-  } else {
-    gpr_mu_lock(&calld->mu_state);
-    if (calld->state == NOT_STARTED) {
-      calld->state = ZOMBIED;
-      gpr_mu_unlock(&calld->mu_state);
-      grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
-      grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
-    } else if (calld->state == PENDING) {
-      calld->state = ZOMBIED;
-      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);
-    }
-  }
-}
-
-static void accept_stream(grpc_exec_ctx *exec_ctx, void *cd,
-                          grpc_transport *transport,
-                          const void *transport_server_data) {
-  channel_data *chand = cd;
-  /* create a call */
-  grpc_call *call =
-      grpc_call_create(chand->channel, NULL, 0, NULL, transport_server_data,
-                       NULL, 0, gpr_inf_future(GPR_CLOCK_MONOTONIC));
-  grpc_call_element *elem =
-      grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
-  call_data *calld = elem->call_data;
-  grpc_op op;
-  memset(&op, 0, sizeof(op));
-  op.op = GRPC_OP_RECV_INITIAL_METADATA;
-  op.data.recv_initial_metadata = &calld->initial_metadata;
-  grpc_closure_init(&calld->got_initial_metadata, got_initial_metadata, elem);
-  grpc_call_start_batch_and_execute(exec_ctx, call, &op, 1,
-                                    &calld->got_initial_metadata);
-}
-
-static void channel_connectivity_changed(grpc_exec_ctx *exec_ctx, void *cd,
-                                         bool 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(exec_ctx,
-                         grpc_channel_stack_element(
-                             grpc_channel_get_channel_stack(chand->channel), 0),
-                         &op);
-  } else {
-    gpr_mu_lock(&server->mu_global);
-    destroy_channel(exec_ctx, chand);
-    gpr_mu_unlock(&server->mu_global);
-    GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "connectivity");
-  }
-}
-
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
-  call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
-  memset(calld, 0, sizeof(call_data));
-  calld->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
-  calld->call = grpc_call_from_top_element(elem);
-  gpr_mu_init(&calld->mu_state);
-
-  grpc_closure_init(&calld->server_on_recv_initial_metadata,
-                    server_on_recv_initial_metadata, elem);
-
-  server_ref(chand->server);
-}
-
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {
-  channel_data *chand = elem->channel_data;
-  call_data *calld = elem->call_data;
-
-  GPR_ASSERT(calld->state != PENDING);
-
-  if (calld->host) {
-    GRPC_MDSTR_UNREF(calld->host);
-  }
-  if (calld->path) {
-    GRPC_MDSTR_UNREF(calld->path);
-  }
-  grpc_metadata_array_destroy(&calld->initial_metadata);
-
-  gpr_mu_destroy(&calld->mu_state);
-
-  server_unref(exec_ctx, chand->server);
-}
-
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
-  channel_data *chand = elem->channel_data;
-  GPR_ASSERT(args->is_first);
-  GPR_ASSERT(!args->is_last);
-  chand->server = NULL;
-  chand->channel = NULL;
-  chand->next = chand->prev = chand;
-  chand->registered_methods = NULL;
-  chand->connectivity_state = GRPC_CHANNEL_IDLE;
-  grpc_closure_init(&chand->channel_connectivity_changed,
-                    channel_connectivity_changed, chand);
-}
-
-static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem) {
-  size_t i;
-  channel_data *chand = elem->channel_data;
-  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);
-      }
-      if (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_global);
-    chand->next->prev = chand->prev;
-    chand->prev->next = chand->next;
-    chand->next = chand->prev = chand;
-    maybe_finish_shutdown(exec_ctx, chand->server);
-    gpr_mu_unlock(&chand->server->mu_global);
-    server_unref(exec_ctx, chand->server);
-  }
-}
-
-static const grpc_channel_filter server_surface_filter = {
-    server_start_transport_stream_op, grpc_channel_next_op, sizeof(call_data),
-    init_call_elem, grpc_call_stack_ignore_set_pollset, destroy_call_elem,
-    sizeof(channel_data), init_channel_elem, destroy_channel_elem,
-    grpc_call_next_get_peer, "server",
-};
-
-void grpc_server_register_completion_queue(grpc_server *server,
-                                           grpc_completion_queue *cq,
-                                           void *reserved) {
-  size_t i, n;
-  GRPC_API_TRACE(
-      "grpc_server_register_completion_queue(server=%p, cq=%p, reserved=%p)", 3,
-      (server, cq, reserved));
-  GPR_ASSERT(!reserved);
-  for (i = 0; i < server->cq_count; i++) {
-    if (server->cqs[i] == cq) return;
-  }
-  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(
-    const grpc_channel_filter **filters, size_t filter_count,
-    const grpc_channel_args *args) {
-  size_t i;
-  int census_enabled = grpc_channel_args_is_census_enabled(args);
-
-  grpc_server *server = gpr_malloc(sizeof(grpc_server));
-
-  GPR_ASSERT(grpc_is_initialized() && "call grpc_init()");
-
-  memset(server, 0, sizeof(grpc_server));
-
-  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, (int)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
-     grpc_server_census_filter (optional) - for stats collection and tracing
-     {passed in filter stack}
-     grpc_connected_channel_filter - for interfacing with transports */
-  server->channel_filter_count = filter_count + 1u + (census_enabled ? 1u : 0u);
-  server->channel_filters =
-      gpr_malloc(server->channel_filter_count * sizeof(grpc_channel_filter *));
-  server->channel_filters[0] = &server_surface_filter;
-  if (census_enabled) {
-    server->channel_filters[1] = &grpc_server_census_filter;
-  }
-  for (i = 0; i < filter_count; i++) {
-    server->channel_filters[i + 1u + (census_enabled ? 1u : 0u)] = filters[i];
-  }
-
-  server->channel_args = grpc_channel_args_copy(args);
-
-  return server;
-}
-
-static int streq(const char *a, const char *b) {
-  if (a == NULL && b == NULL) return 1;
-  if (a == NULL) return 0;
-  if (b == NULL) return 0;
-  return 0 == strcmp(a, b);
-}
-
-void *grpc_server_register_method(grpc_server *server, const char *method,
-                                  const char *host) {
-  registered_method *m;
-  GRPC_API_TRACE("grpc_server_register_method(server=%p, method=%s, host=%s)",
-                 3, (server, method, host));
-  if (!method) {
-    gpr_log(GPR_ERROR,
-            "grpc_server_register_method method string cannot be NULL");
-    return NULL;
-  }
-  for (m = server->registered_methods; m; m = m->next) {
-    if (streq(m->method, method) && streq(m->host, host)) {
-      gpr_log(GPR_ERROR, "duplicate registration for %s@%s", method,
-              host ? host : "*");
-      return NULL;
-    }
-  }
-  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;
-  server->registered_methods = m;
-  return m;
-}
-
-void grpc_server_start(grpc_server *server) {
-  listener *l;
-  size_t i;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  GRPC_API_TRACE("grpc_server_start(server=%p)", 1, (server));
-
-  server->pollsets = gpr_malloc(sizeof(grpc_pollset *) * server->cq_count);
-  for (i = 0; i < server->cq_count; i++) {
-    server->pollsets[i] = grpc_cq_pollset(server->cqs[i]);
-  }
-
-  for (l = server->listeners; l; l = l->next) {
-    l->start(&exec_ctx, server, l->arg, server->pollsets, server->cq_count);
-  }
-
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
-                                 grpc_transport *transport,
-                                 grpc_channel_filter const **extra_filters,
-                                 size_t num_extra_filters,
-                                 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);
-  size_t i;
-  size_t num_registered_methods;
-  size_t alloc;
-  registered_method *rm;
-  channel_registered_method *crm;
-  grpc_channel *channel;
-  channel_data *chand;
-  grpc_mdstr *host;
-  grpc_mdstr *method;
-  uint32_t hash;
-  size_t slots;
-  uint32_t probes;
-  uint32_t max_probes = 0;
-  grpc_transport_op op;
-
-  for (i = 0; i < s->channel_filter_count; i++) {
-    filters[i] = s->channel_filters[i];
-  }
-  for (; i < s->channel_filter_count + num_extra_filters; i++) {
-    filters[i] = extra_filters[i - s->channel_filter_count];
-  }
-  filters[i] = &grpc_connected_channel_filter;
-
-  for (i = 0; i < s->cq_count; i++) {
-    memset(&op, 0, sizeof(op));
-    op.bind_pollset = grpc_cq_pollset(s->cqs[i]);
-    grpc_transport_perform_op(exec_ctx, transport, &op);
-  }
-
-  channel = grpc_channel_create_from_filters(exec_ctx, NULL, filters,
-                                             num_filters, args, 0);
-  chand = (channel_data *)grpc_channel_stack_element(
-              grpc_channel_get_channel_stack(channel), 0)->channel_data;
-  chand->server = s;
-  server_ref(s);
-  chand->channel = channel;
-
-  num_registered_methods = 0;
-  for (rm = s->registered_methods; rm; rm = rm->next) {
-    num_registered_methods++;
-  }
-  /* build a lookup table phrased in terms of mdstr's in this channels context
-     to quickly find registered methods */
-  if (num_registered_methods > 0) {
-    slots = 2 * num_registered_methods;
-    alloc = sizeof(channel_registered_method) * slots;
-    chand->registered_methods = gpr_malloc(alloc);
-    memset(chand->registered_methods, 0, alloc);
-    for (rm = s->registered_methods; rm; rm = rm->next) {
-      host = rm->host ? grpc_mdstr_from_string(rm->host) : NULL;
-      method = grpc_mdstr_from_string(rm->method);
-      hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash);
-      for (probes = 0; chand->registered_methods[(hash + probes) % slots]
-                               .server_registered_method != NULL;
-           probes++)
-        ;
-      if (probes > max_probes) max_probes = probes;
-      crm = &chand->registered_methods[(hash + probes) % slots];
-      crm->server_registered_method = rm;
-      crm->host = host;
-      crm->method = method;
-    }
-    GPR_ASSERT(slots <= UINT32_MAX);
-    chand->registered_method_slots = (uint32_t)slots;
-    chand->registered_method_max_probes = max_probes;
-  }
-
-  grpc_connected_channel_bind_transport(grpc_channel_get_channel_stack(channel),
-                                        transport);
-
-  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_global);
-
-  gpr_free((void *)filters);
-
-  GRPC_CHANNEL_INTERNAL_REF(channel, "connectivity");
-  memset(&op, 0, sizeof(op));
-  op.set_accept_stream = true;
-  op.set_accept_stream_fn = accept_stream;
-  op.set_accept_stream_user_data = chand;
-  op.on_connectivity_state_change = &chand->channel_connectivity_changed;
-  op.connectivity_state = &chand->connectivity_state;
-  op.disconnect = gpr_atm_acq_load(&s->shutdown_flag) != 0;
-  grpc_transport_perform_op(exec_ctx, transport, &op);
-}
-
-void done_published_shutdown(grpc_exec_ctx *exec_ctx, void *done_arg,
-                             grpc_cq_completion *storage) {
-  (void)done_arg;
-  gpr_free(storage);
-}
-
-static void listener_destroy_done(grpc_exec_ctx *exec_ctx, void *s,
-                                  bool success) {
-  grpc_server *server = s;
-  gpr_mu_lock(&server->mu_global);
-  server->listeners_destroyed++;
-  maybe_finish_shutdown(exec_ctx, server);
-  gpr_mu_unlock(&server->mu_global);
-}
-
-void grpc_server_shutdown_and_notify(grpc_server *server,
-                                     grpc_completion_queue *cq, void *tag) {
-  listener *l;
-  shutdown_tag *sdt;
-  channel_broadcaster broadcaster;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  GRPC_API_TRACE("grpc_server_shutdown_and_notify(server=%p, cq=%p, tag=%p)", 3,
-                 (server, cq, tag));
-
-  /* lock, and gather up some stuff to do */
-  gpr_mu_lock(&server->mu_global);
-  grpc_cq_begin_op(cq, tag);
-  if (server->shutdown_published) {
-    grpc_cq_end_op(&exec_ctx, cq, tag, 1, done_published_shutdown, NULL,
-                   gpr_malloc(sizeof(grpc_cq_completion)));
-    gpr_mu_unlock(&server->mu_global);
-    goto done;
-  }
-  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 (gpr_atm_acq_load(&server->shutdown_flag)) {
-    gpr_mu_unlock(&server->mu_global);
-    goto done;
-  }
-
-  server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME);
-
-  channel_broadcaster_init(server, &broadcaster);
-
-  gpr_atm_rel_store(&server->shutdown_flag, 1);
-
-  /* collect all unregistered then registered calls */
-  gpr_mu_lock(&server->mu_call);
-  kill_pending_work_locked(&exec_ctx, server);
-  gpr_mu_unlock(&server->mu_call);
-
-  maybe_finish_shutdown(&exec_ctx, server);
-  gpr_mu_unlock(&server->mu_global);
-
-  /* Shutdown listeners */
-  for (l = server->listeners; l; l = l->next) {
-    grpc_closure_init(&l->destroy_done, listener_destroy_done, server);
-    l->destroy(&exec_ctx, server, l->arg, &l->destroy_done);
-  }
-
-  channel_broadcaster_shutdown(&exec_ctx, &broadcaster, 1, 0);
-
-done:
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-void grpc_server_cancel_all_calls(grpc_server *server) {
-  channel_broadcaster broadcaster;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  GRPC_API_TRACE("grpc_server_cancel_all_calls(server=%p)", 1, (server));
-
-  gpr_mu_lock(&server->mu_global);
-  channel_broadcaster_init(server, &broadcaster);
-  gpr_mu_unlock(&server->mu_global);
-
-  channel_broadcaster_shutdown(&exec_ctx, &broadcaster, 0, 1);
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-void grpc_server_destroy(grpc_server *server) {
-  listener *l;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  GRPC_API_TRACE("grpc_server_destroy(server=%p)", 1, (server));
-
-  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) {
-    l = server->listeners;
-    server->listeners = l->next;
-    gpr_free(l);
-  }
-
-  gpr_mu_unlock(&server->mu_global);
-
-  server_unref(&exec_ctx, server);
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-void grpc_server_add_listener(
-    grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
-    void (*start)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
-                  grpc_pollset **pollsets, size_t pollset_count),
-    void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
-                    grpc_closure *on_done)) {
-  listener *l = gpr_malloc(sizeof(listener));
-  l->arg = arg;
-  l->start = start;
-  l->destroy = destroy;
-  l->next = server->listeners;
-  server->listeners = l;
-}
-
-static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx,
-                                          grpc_server *server,
-                                          requested_call *rc) {
-  call_data *calld = NULL;
-  request_matcher *rm = NULL;
-  int request_id;
-  if (gpr_atm_acq_load(&server->shutdown_flag)) {
-    fail_call(exec_ctx, 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(exec_ctx, server, rc);
-    return GRPC_CALL_OK;
-  }
-  switch (rc->type) {
-    case BATCH_CALL:
-      rm = &server->unregistered_request_matcher;
-      break;
-    case REGISTERED_CALL:
-      rm = &rc->data.registered.registered_method->request_matcher;
-      break;
-  }
-  server->requested_calls[request_id] = *rc;
-  gpr_free(rc);
-  if (gpr_stack_lockfree_push(rm->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 = rm->pending_head) != NULL) {
-      request_id = gpr_stack_lockfree_pop(rm->requests);
-      if (request_id == -1) break;
-      rm->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_closure_init(
-            &calld->kill_zombie_closure, kill_zombie,
-            grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
-        grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true,
-                              NULL);
-      } else {
-        GPR_ASSERT(calld->state == PENDING);
-        calld->state = ACTIVATED;
-        gpr_mu_unlock(&calld->mu_state);
-        begin_call(exec_ctx, 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(
-    grpc_server *server, grpc_call **call, grpc_call_details *details,
-    grpc_metadata_array *initial_metadata,
-    grpc_completion_queue *cq_bound_to_call,
-    grpc_completion_queue *cq_for_notification, void *tag) {
-  grpc_call_error error;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  requested_call *rc = gpr_malloc(sizeof(*rc));
-  GRPC_API_TRACE(
-      "grpc_server_request_call("
-      "server=%p, call=%p, details=%p, initial_metadata=%p, "
-      "cq_bound_to_call=%p, cq_for_notification=%p, tag=%p)",
-      7, (server, call, details, initial_metadata, cq_bound_to_call,
-          cq_for_notification, tag));
-  if (!grpc_cq_is_server_cq(cq_for_notification)) {
-    gpr_free(rc);
-    error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
-    goto done;
-  }
-  grpc_cq_begin_op(cq_for_notification, tag);
-  details->reserved = NULL;
-  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->initial_metadata = initial_metadata;
-  error = queue_call_request(&exec_ctx, server, rc);
-done:
-  grpc_exec_ctx_finish(&exec_ctx);
-  return error;
-}
-
-grpc_call_error grpc_server_request_registered_call(
-    grpc_server *server, void *rmp, grpc_call **call, gpr_timespec *deadline,
-    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) {
-  grpc_call_error error;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  requested_call *rc = gpr_malloc(sizeof(*rc));
-  registered_method *rm = rmp;
-  GRPC_API_TRACE(
-      "grpc_server_request_registered_call("
-      "server=%p, rmp=%p, call=%p, deadline=%p, initial_metadata=%p, "
-      "optional_payload=%p, cq_bound_to_call=%p, cq_for_notification=%p, "
-      "tag=%p)",
-      9, (server, rmp, call, deadline, initial_metadata, optional_payload,
-          cq_bound_to_call, cq_for_notification, tag));
-  if (!grpc_cq_is_server_cq(cq_for_notification)) {
-    gpr_free(rc);
-    error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
-    goto done;
-  }
-  grpc_cq_begin_op(cq_for_notification, tag);
-  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 = rm;
-  rc->data.registered.deadline = deadline;
-  rc->initial_metadata = initial_metadata;
-  rc->data.registered.optional_payload = optional_payload;
-  error = queue_call_request(&exec_ctx, server, rc);
-done:
-  grpc_exec_ctx_finish(&exec_ctx);
-  return error;
-}
-
-static void publish_registered_or_batch(grpc_exec_ctx *exec_ctx,
-                                        void *user_data, bool success);
-
-static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) {
-  gpr_slice slice = value->slice;
-  size_t len = GPR_SLICE_LENGTH(slice);
-
-  if (len + 1 > *capacity) {
-    *capacity = GPR_MAX(len + 1, *capacity * 2);
-    *dest = gpr_realloc(*dest, *capacity);
-  }
-  memcpy(*dest, grpc_mdstr_as_c_string(value), len + 1);
-}
-
-static void begin_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
-                       call_data *calld, requested_call *rc) {
-  grpc_op ops[1];
-  grpc_op *op = ops;
-
-  memset(ops, 0, sizeof(ops));
-
-  /* called once initial metadata has been read by the call, but BEFORE
-     the ioreq to fetch it out of the call has been executed.
-     This means metadata related fields can be relied on in calld, but to
-     fill in the metadata array passed by the client, we need to perform
-     an ioreq op, that should complete immediately. */
-
-  grpc_call_set_completion_queue(exec_ctx, calld->call, rc->cq_bound_to_call);
-  grpc_closure_init(&rc->publish, publish_registered_or_batch, rc);
-  *rc->call = calld->call;
-  calld->cq_new = rc->cq_for_notification;
-  GPR_SWAP(grpc_metadata_array, *rc->initial_metadata, calld->initial_metadata);
-  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,
-            &rc->data.batch.details->method_capacity, calld->path);
-      rc->data.batch.details->deadline = calld->deadline;
-      break;
-    case REGISTERED_CALL:
-      *rc->data.registered.deadline = calld->deadline;
-      if (rc->data.registered.optional_payload) {
-        op->op = GRPC_OP_RECV_MESSAGE;
-        op->data.recv_message = rc->data.registered.optional_payload;
-        op++;
-      }
-      break;
-    default:
-      GPR_UNREACHABLE_CODE(return );
-  }
-
-  GRPC_CALL_INTERNAL_REF(calld->call, "server");
-  grpc_call_start_batch_and_execute(exec_ctx, calld->call, ops,
-                                    (size_t)(op - ops), &rc->publish);
-}
-
-static void done_request_event(grpc_exec_ctx *exec_ctx, 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_ASSERT(rc - server->requested_calls <= INT_MAX);
-    gpr_stack_lockfree_push(server->request_freelist,
-                            (int)(rc - server->requested_calls));
-  } else {
-    gpr_free(req);
-  }
-
-  server_unref(exec_ctx, server);
-}
-
-static void fail_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
-                      requested_call *rc) {
-  *rc->call = NULL;
-  rc->initial_metadata->count = 0;
-
-  server_ref(server);
-  grpc_cq_end_op(exec_ctx, rc->cq_for_notification, rc->tag, 0,
-                 done_request_event, rc, &rc->completion);
-}
-
-static void publish_registered_or_batch(grpc_exec_ctx *exec_ctx, void *prc,
-                                        bool success) {
-  requested_call *rc = prc;
-  grpc_call *call = *rc->call;
-  grpc_call_element *elem =
-      grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
-  call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
-  server_ref(chand->server);
-  grpc_cq_end_op(exec_ctx, calld->cq_new, rc->tag, success, done_request_event,
-                 rc, &rc->completion);
-  GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "server");
-}
-
-const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) {
-  return server->channel_args;
-}
-
-int grpc_server_has_open_connections(grpc_server *server) {
-  int r;
-  gpr_mu_lock(&server->mu_global);
-  r = server->root_channel_data.next != &server->root_channel_data;
-  gpr_mu_unlock(&server->mu_global);
-  return r;
-}
diff --git a/src/core/surface/server.h b/src/core/surface/server.h
deleted file mode 100644
index a957fdb..0000000
--- a/src/core/surface/server.h
+++ /dev/null
@@ -1,67 +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_SURFACE_SERVER_H
-#define GRPC_INTERNAL_CORE_SURFACE_SERVER_H
-
-#include "src/core/channel/channel_stack.h"
-#include <grpc/grpc.h>
-#include "src/core/transport/transport.h"
-
-/* Create a server */
-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 */
-void grpc_server_add_listener(
-    grpc_exec_ctx *exec_ctx, grpc_server *server, void *listener,
-    void (*start)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
-                  grpc_pollset **pollsets, size_t npollsets),
-    void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_server *server, void *arg,
-                    grpc_closure *on_done));
-
-/* Setup a transport - creates a channel stack, binds the transport to the
-   server */
-void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *server,
-                                 grpc_transport *transport,
-                                 grpc_channel_filter const **extra_filters,
-                                 size_t num_extra_filters,
-                                 const grpc_channel_args *args);
-
-const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);
-
-int grpc_server_has_open_connections(grpc_server *server);
-
-#endif /* GRPC_INTERNAL_CORE_SURFACE_SERVER_H */
diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c
deleted file mode 100644
index ce970df..0000000
--- a/src/core/surface/server_chttp2.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/grpc.h>
-
-#include "src/core/channel/http_server_filter.h"
-#include "src/core/iomgr/resolve_address.h"
-#include "src/core/iomgr/tcp_server.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/server.h"
-#include "src/core/transport/chttp2_transport.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-static void setup_transport(grpc_exec_ctx *exec_ctx, void *server,
-                            grpc_transport *transport) {
-  static grpc_channel_filter const *extra_filters[] = {
-      &grpc_http_server_filter};
-  grpc_server_setup_transport(exec_ctx, server, transport, extra_filters,
-                              GPR_ARRAY_SIZE(extra_filters),
-                              grpc_server_get_channel_args(server));
-}
-
-static void new_transport(grpc_exec_ctx *exec_ctx, void *server,
-                          grpc_endpoint *tcp,
-                          grpc_tcp_server_acceptor *acceptor) {
-  /*
-   * Beware that the call to grpc_create_chttp2_transport() has to happen before
-   * grpc_tcp_server_destroy(). This is fine here, but similar code
-   * asynchronously doing a handshake instead of calling grpc_tcp_server_start()
-   * (as in server_secure_chttp2.c) needs to add synchronization to avoid this
-   * case.
-   */
-  grpc_transport *transport = grpc_create_chttp2_transport(
-      exec_ctx, grpc_server_get_channel_args(server), tcp, 0);
-  setup_transport(exec_ctx, server, transport);
-  grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
-}
-
-/* Server callback: start listening on our ports */
-static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
-                  grpc_pollset **pollsets, size_t pollset_count) {
-  grpc_tcp_server *tcp = tcpp;
-  grpc_tcp_server_start(exec_ctx, tcp, pollsets, pollset_count, new_transport,
-                        server);
-}
-
-/* Server callback: destroy the tcp listener (so we don't generate further
-   callbacks) */
-static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
-                    grpc_closure *destroy_done) {
-  grpc_tcp_server *tcp = tcpp;
-  grpc_tcp_server_unref(exec_ctx, tcp);
-  grpc_exec_ctx_enqueue(exec_ctx, destroy_done, true, NULL);
-}
-
-int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
-  grpc_resolved_addresses *resolved = NULL;
-  grpc_tcp_server *tcp = NULL;
-  size_t i;
-  unsigned count = 0;
-  int port_num = -1;
-  int port_temp;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2,
-                 (server, addr));
-
-  resolved = grpc_blocking_resolve_address(addr, "http");
-  if (!resolved) {
-    goto error;
-  }
-
-  tcp = grpc_tcp_server_create(NULL);
-  GPR_ASSERT(tcp);
-
-  for (i = 0; i < resolved->naddrs; i++) {
-    port_temp = grpc_tcp_server_add_port(
-        tcp, (struct sockaddr *)&resolved->addrs[i].addr,
-        resolved->addrs[i].len);
-    if (port_temp > 0) {
-      if (port_num == -1) {
-        port_num = port_temp;
-      } else {
-        GPR_ASSERT(port_num == port_temp);
-      }
-      count++;
-    }
-  }
-  if (count == 0) {
-    gpr_log(GPR_ERROR, "No address added out of total %d resolved",
-            resolved->naddrs);
-    goto error;
-  }
-  if (count != resolved->naddrs) {
-    gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
-            count, resolved->naddrs);
-  }
-  grpc_resolved_addresses_destroy(resolved);
-
-  /* Register with the server only upon success */
-  grpc_server_add_listener(&exec_ctx, server, tcp, start, destroy);
-  goto done;
-
-/* Error path: cleanup and return */
-error:
-  if (resolved) {
-    grpc_resolved_addresses_destroy(resolved);
-  }
-  if (tcp) {
-    grpc_tcp_server_unref(&exec_ctx, tcp);
-  }
-  port_num = 0;
-
-done:
-  grpc_exec_ctx_finish(&exec_ctx);
-  return port_num;
-}
diff --git a/src/core/surface/server_create.c b/src/core/surface/server_create.c
deleted file mode 100644
index 5e37e80..0000000
--- a/src/core/surface/server_create.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/grpc.h>
-#include "src/core/census/grpc_filter.h"
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/compress_filter.h"
-#include "src/core/surface/api_trace.h"
-#include "src/core/surface/completion_queue.h"
-#include "src/core/surface/server.h"
-
-grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) {
-  const grpc_channel_filter *filters[3];
-  size_t num_filters = 0;
-  filters[num_filters++] = &grpc_compress_filter;
-  GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved));
-  return grpc_server_create_from_filters(filters, num_filters, args);
-}
diff --git a/src/core/surface/surface_trace.h b/src/core/surface/surface_trace.h
deleted file mode 100644
index 93b2859..0000000
--- a/src/core/surface/surface_trace.h
+++ /dev/null
@@ -1,48 +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_SURFACE_SURFACE_TRACE_H
-#define GRPC_INTERNAL_CORE_SURFACE_SURFACE_TRACE_H
-
-#include "src/core/debug/trace.h"
-#include "src/core/surface/api_trace.h"
-#include <grpc/support/log.h>
-
-#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event)    \
-  if (grpc_api_trace) {                                 \
-    char *_ev = grpc_event_string(event);               \
-    gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \
-    gpr_free(_ev);                                      \
-  }
-
-#endif /* GRPC_INTERNAL_CORE_SURFACE_SURFACE_TRACE_H */
diff --git a/src/core/surface/version.c b/src/core/surface/version.c
deleted file mode 100644
index 19f0983..0000000
--- a/src/core/surface/version.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/* This file is autogenerated from:
-   templates/src/core/surface/version.c.template */
-
-#include <grpc/grpc.h>
-
-const char *grpc_version_string(void) { return "0.13.1-pre1"; }
diff --git a/src/core/transport/byte_stream.c b/src/core/transport/byte_stream.c
deleted file mode 100644
index 8e6fb2c..0000000
--- a/src/core/transport/byte_stream.c
+++ /dev/null
@@ -1,78 +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/transport/byte_stream.h"
-
-#include <stdlib.h>
-
-#include <grpc/support/log.h>
-
-int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
-                          grpc_byte_stream *byte_stream, gpr_slice *slice,
-                          size_t max_size_hint, grpc_closure *on_complete) {
-  return byte_stream->next(exec_ctx, byte_stream, slice, max_size_hint,
-                           on_complete);
-}
-
-void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
-                              grpc_byte_stream *byte_stream) {
-  byte_stream->destroy(exec_ctx, byte_stream);
-}
-
-/* slice_buffer_stream */
-
-static int slice_buffer_stream_next(grpc_exec_ctx *exec_ctx,
-                                    grpc_byte_stream *byte_stream,
-                                    gpr_slice *slice, size_t max_size_hint,
-                                    grpc_closure *on_complete) {
-  grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream;
-  GPR_ASSERT(stream->cursor < stream->backing_buffer->count);
-  *slice = gpr_slice_ref(stream->backing_buffer->slices[stream->cursor]);
-  stream->cursor++;
-  return 1;
-}
-
-static void slice_buffer_stream_destroy(grpc_exec_ctx *exec_ctx,
-                                        grpc_byte_stream *byte_stream) {}
-
-void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream,
-                                   gpr_slice_buffer *slice_buffer,
-                                   uint32_t flags) {
-  GPR_ASSERT(slice_buffer->length <= UINT32_MAX);
-  stream->base.length = (uint32_t)slice_buffer->length;
-  stream->base.flags = flags;
-  stream->base.next = slice_buffer_stream_next;
-  stream->base.destroy = slice_buffer_stream_destroy;
-  stream->backing_buffer = slice_buffer;
-  stream->cursor = 0;
-}
diff --git a/src/core/transport/byte_stream.h b/src/core/transport/byte_stream.h
deleted file mode 100644
index d2e51e7..0000000
--- a/src/core/transport/byte_stream.h
+++ /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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_TRANSPORT_BYTE_STREAM_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_BYTE_STREAM_H
-
-#include "src/core/iomgr/exec_ctx.h"
-#include <grpc/support/slice_buffer.h>
-
-/** Internal bit flag for grpc_begin_message's \a flags signaling the use of
- * compression for the message */
-#define GRPC_WRITE_INTERNAL_COMPRESS (0x80000000u)
-/** Mask of all valid internal flags. */
-#define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS)
-
-struct grpc_byte_stream;
-typedef struct grpc_byte_stream grpc_byte_stream;
-
-struct grpc_byte_stream {
-  uint32_t length;
-  uint32_t flags;
-  int (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream,
-              gpr_slice *slice, size_t max_size_hint,
-              grpc_closure *on_complete);
-  void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream);
-};
-
-/* returns 1 if the bytes are available immediately (in which case
- * on_complete will not be called), 0 if the bytes will be available
- * asynchronously.
- *
- * on entry, *remaining can be set as a hint as to the maximum number
- * of bytes that would be acceptable to read.
- *
- * fills *buffer, *length, *remaining with the bytes, length of bytes
- * and length of data remaining to be read before either returning 1
- * or calling on_complete.
- *
- * once a slice is returned into *slice, it is owned by the caller.
- */
-int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
-                          grpc_byte_stream *byte_stream, gpr_slice *slice,
-                          size_t max_size_hint, grpc_closure *on_complete);
-
-void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
-                              grpc_byte_stream *byte_stream);
-
-/* grpc_byte_stream that wraps a slice buffer */
-typedef struct grpc_slice_buffer_stream {
-  grpc_byte_stream base;
-  gpr_slice_buffer *backing_buffer;
-  size_t cursor;
-} grpc_slice_buffer_stream;
-
-void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream,
-                                   gpr_slice_buffer *slice_buffer,
-                                   uint32_t flags);
-
-#endif /* GRPC_INTERNAL_CORE_TRANSPORT_BYTE_STREAM_H */
diff --git a/src/core/transport/chttp2/alpn.c b/src/core/transport/chttp2/alpn.c
deleted file mode 100644
index 69da4e6..0000000
--- a/src/core/transport/chttp2/alpn.c
+++ /dev/null
@@ -1,56 +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/transport/chttp2/alpn.h"
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-/* in order of preference */
-static const char *const supported_versions[] = {"h2"};
-
-int grpc_chttp2_is_alpn_version_supported(const char *version, size_t size) {
-  size_t i;
-  for (i = 0; i < GPR_ARRAY_SIZE(supported_versions); i++) {
-    if (!strncmp(version, supported_versions[i], size)) return 1;
-  }
-  return 0;
-}
-
-size_t grpc_chttp2_num_alpn_versions(void) {
-  return GPR_ARRAY_SIZE(supported_versions);
-}
-
-const char *grpc_chttp2_get_alpn_version_index(size_t i) {
-  GPR_ASSERT(i < GPR_ARRAY_SIZE(supported_versions));
-  return supported_versions[i];
-}
diff --git a/src/core/transport/chttp2/alpn.h b/src/core/transport/chttp2/alpn.h
deleted file mode 100644
index f38b4c3..0000000
--- a/src/core/transport/chttp2/alpn.h
+++ /dev/null
@@ -1,49 +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_TRANSPORT_CHTTP2_ALPN_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_ALPN_H
-
-#include <string.h>
-
-/* Retuns 1 if the version is supported, 0 otherwise. */
-int grpc_chttp2_is_alpn_version_supported(const char *version, size_t size);
-
-/* Returns the number of protocol versions to advertise */
-size_t grpc_chttp2_num_alpn_versions(void);
-
-/* Returns the protocol version at index i (0 <= i <
- * grpc_chttp2_num_alpn_versions()) */
-const char *grpc_chttp2_get_alpn_version_index(size_t i);
-
-#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
deleted file mode 100644
index f26bc7e..0000000
--- a/src/core/transport/chttp2/bin_encoder.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/transport/chttp2/bin_encoder.h"
-
-#include <string.h>
-
-#include "src/core/transport/chttp2/huffsyms.h"
-#include <grpc/support/log.h>
-
-static const char alphabet[] =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-typedef struct {
-  uint16_t bits;
-  uint8_t 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 uint8_t tail_xtra[3] = {0, 2, 3};
-
-gpr_slice grpc_chttp2_base64_encode(gpr_slice input) {
-  size_t input_length = GPR_SLICE_LENGTH(input);
-  size_t input_triplets = input_length / 3;
-  size_t tail_case = input_length % 3;
-  size_t output_length = input_triplets * 4 + tail_xtra[tail_case];
-  gpr_slice output = gpr_slice_malloc(output_length);
-  uint8_t *in = GPR_SLICE_START_PTR(input);
-  char *out = (char *)GPR_SLICE_START_PTR(output);
-  size_t i;
-
-  /* encode full triplets */
-  for (i = 0; i < input_triplets; i++) {
-    out[0] = alphabet[in[0] >> 2];
-    out[1] = alphabet[((in[0] & 0x3) << 4) | (in[1] >> 4)];
-    out[2] = alphabet[((in[1] & 0xf) << 2) | (in[2] >> 6)];
-    out[3] = alphabet[in[2] & 0x3f];
-    out += 4;
-    in += 3;
-  }
-
-  /* encode the remaining bytes */
-  switch (tail_case) {
-    case 0:
-      break;
-    case 1:
-      out[0] = alphabet[in[0] >> 2];
-      out[1] = alphabet[(in[0] & 0x3) << 4];
-      out += 2;
-      in += 1;
-      break;
-    case 2:
-      out[0] = alphabet[in[0] >> 2];
-      out[1] = alphabet[((in[0] & 0x3) << 4) | (in[1] >> 4)];
-      out[2] = alphabet[(in[1] & 0xf) << 2];
-      out += 3;
-      in += 2;
-      break;
-  }
-
-  GPR_ASSERT(out == (char *)GPR_SLICE_END_PTR(output));
-  GPR_ASSERT(in == GPR_SLICE_END_PTR(input));
-  return output;
-}
-
-gpr_slice grpc_chttp2_huffman_compress(gpr_slice input) {
-  size_t nbits;
-  uint8_t *in;
-  uint8_t *out;
-  gpr_slice output;
-  uint32_t temp = 0;
-  uint32_t temp_length = 0;
-
-  nbits = 0;
-  for (in = GPR_SLICE_START_PTR(input); in != GPR_SLICE_END_PTR(input); ++in) {
-    nbits += grpc_chttp2_huffsyms[*in].length;
-  }
-
-  output = gpr_slice_malloc(nbits / 8 + (nbits % 8 != 0));
-  out = GPR_SLICE_START_PTR(output);
-  for (in = GPR_SLICE_START_PTR(input); in != GPR_SLICE_END_PTR(input); ++in) {
-    int sym = *in;
-    temp <<= grpc_chttp2_huffsyms[sym].length;
-    temp |= grpc_chttp2_huffsyms[sym].bits;
-    temp_length += grpc_chttp2_huffsyms[sym].length;
-
-    while (temp_length > 8) {
-      temp_length -= 8;
-      *out++ = (uint8_t)(temp >> temp_length);
-    }
-  }
-
-  if (temp_length) {
-    /* NB: the following integer arithmetic operation needs to be in its
-     * expanded form due to the "integral promotion" performed (see section
-     * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type
-     * is then required to avoid the compiler warning */
-    *out++ = (uint8_t)((uint8_t)(temp << (8u - temp_length)) |
-                       (uint8_t)(0xffu >> temp_length));
-  }
-
-  GPR_ASSERT(out == GPR_SLICE_END_PTR(output));
-
-  return output;
-}
-
-typedef struct {
-  uint32_t temp;
-  uint32_t temp_length;
-  uint8_t *out;
-} huff_out;
-
-static void enc_flush_some(huff_out *out) {
-  while (out->temp_length > 8) {
-    out->temp_length -= 8;
-    *out->out++ = (uint8_t)(out->temp >> out->temp_length);
-  }
-}
-
-static void enc_add2(huff_out *out, uint8_t a, uint8_t b) {
-  b64_huff_sym sa = huff_alphabet[a];
-  b64_huff_sym sb = huff_alphabet[b];
-  out->temp = (out->temp << (sa.length + sb.length)) |
-              ((uint32_t)sa.bits << sb.length) | sb.bits;
-  out->temp_length += (uint32_t)sa.length + (uint32_t)sb.length;
-  enc_flush_some(out);
-}
-
-static void enc_add1(huff_out *out, uint8_t a) {
-  b64_huff_sym sa = huff_alphabet[a];
-  out->temp = (out->temp << sa.length) | sa.bits;
-  out->temp_length += sa.length;
-  enc_flush_some(out);
-}
-
-gpr_slice grpc_chttp2_base64_encode_and_huffman_compress(gpr_slice input) {
-  size_t input_length = GPR_SLICE_LENGTH(input);
-  size_t input_triplets = input_length / 3;
-  size_t tail_case = input_length % 3;
-  size_t output_syms = input_triplets * 4 + tail_xtra[tail_case];
-  size_t max_output_bits = 11 * output_syms;
-  size_t max_output_length = max_output_bits / 8 + (max_output_bits % 8 != 0);
-  gpr_slice output = gpr_slice_malloc(max_output_length);
-  uint8_t *in = GPR_SLICE_START_PTR(input);
-  uint8_t *start_out = GPR_SLICE_START_PTR(output);
-  huff_out out;
-  size_t i;
-
-  out.temp = 0;
-  out.temp_length = 0;
-  out.out = start_out;
-
-  /* encode full triplets */
-  for (i = 0; i < input_triplets; i++) {
-    enc_add2(&out, in[0] >> 2, (uint8_t)((in[0] & 0x3) << 4) | (in[1] >> 4));
-    enc_add2(&out, (uint8_t)((in[1] & 0xf) << 2) | (in[2] >> 6),
-             (uint8_t)(in[2] & 0x3f));
-    in += 3;
-  }
-
-  /* encode the remaining bytes */
-  switch (tail_case) {
-    case 0:
-      break;
-    case 1:
-      enc_add2(&out, in[0] >> 2, (uint8_t)((in[0] & 0x3) << 4));
-      in += 1;
-      break;
-    case 2:
-      enc_add2(&out, in[0] >> 2,
-               (uint8_t)((in[0] & 0x3) << 4) | (uint8_t)(in[1] >> 4));
-      enc_add1(&out, (uint8_t)((in[1] & 0xf) << 2));
-      in += 2;
-      break;
-  }
-
-  if (out.temp_length) {
-    /* NB: the following integer arithmetic operation needs to be in its
-     * expanded form due to the "integral promotion" performed (see section
-     * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type
-     * is then required to avoid the compiler warning */
-    *out.out++ = (uint8_t)((uint8_t)(out.temp << (8u - out.temp_length)) |
-                           (uint8_t)(0xffu >> out.temp_length));
-  }
-
-  GPR_ASSERT(out.out <= GPR_SLICE_END_PTR(output));
-  GPR_SLICE_SET_LENGTH(output, out.out - start_out);
-
-  GPR_ASSERT(in == GPR_SLICE_END_PTR(input));
-  return output;
-}
diff --git a/src/core/transport/chttp2/bin_encoder.h b/src/core/transport/chttp2/bin_encoder.h
deleted file mode 100644
index 036fddf..0000000
--- a/src/core/transport/chttp2/bin_encoder.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_BIN_ENCODER_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_BIN_ENCODER_H
-
-#include <grpc/support/slice.h>
-
-/* base64 encode a slice. Returns a new slice, does not take ownership of the
-   input */
-gpr_slice grpc_chttp2_base64_encode(gpr_slice input);
-
-/* Compress a slice with the static huffman encoder detailed in the hpack
-   standard. Returns a new slice, does not take ownership of the input */
-gpr_slice grpc_chttp2_huffman_compress(gpr_slice input);
-
-/* equivalent to:
-   gpr_slice x = grpc_chttp2_base64_encode(input);
-   gpr_slice y = grpc_chttp2_huffman_compress(x);
-   gpr_slice_unref(x);
-   return y; */
-gpr_slice grpc_chttp2_base64_encode_and_huffman_compress(gpr_slice input);
-
-#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
deleted file mode 100644
index 879ee03..0000000
--- a/src/core/transport/chttp2/frame.h
+++ /dev/null
@@ -1,69 +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_TRANSPORT_CHTTP2_FRAME_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_H
-
-#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-
-/* Common definitions for frame handling in the chttp2 transport */
-
-typedef enum {
-  GRPC_CHTTP2_PARSE_OK,
-  GRPC_CHTTP2_STREAM_ERROR,
-  GRPC_CHTTP2_CONNECTION_ERROR
-} grpc_chttp2_parse_error;
-
-/* 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
-#define GRPC_CHTTP2_FRAME_CONTINUATION 9
-#define GRPC_CHTTP2_FRAME_RST_STREAM 3
-#define GRPC_CHTTP2_FRAME_SETTINGS 4
-#define GRPC_CHTTP2_FRAME_PING 6
-#define GRPC_CHTTP2_FRAME_GOAWAY 7
-#define GRPC_CHTTP2_FRAME_WINDOW_UPDATE 8
-
-#define GRPC_CHTTP2_MAX_PAYLOAD_LENGTH ((1 << 14) - 1)
-
-#define GRPC_CHTTP2_DATA_FLAG_END_STREAM 1
-#define GRPC_CHTTP2_FLAG_ACK 1
-#define GRPC_CHTTP2_DATA_FLAG_END_HEADERS 4
-#define GRPC_CHTTP2_DATA_FLAG_PADDED 8
-#define GRPC_CHTTP2_FLAG_HAS_PRIORITY 0x20
-
-#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
deleted file mode 100644
index f9a1af8..0000000
--- a/src/core/transport/chttp2/frame_data.c
+++ /dev/null
@@ -1,248 +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/transport/chttp2/frame_data.h"
-
-#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>
-#include <grpc/support/useful.h>
-#include "src/core/transport/transport.h"
-
-grpc_chttp2_parse_error grpc_chttp2_data_parser_init(
-    grpc_chttp2_data_parser *parser) {
-  parser->state = GRPC_CHTTP2_DATA_FH_0;
-  parser->parsing_frame = NULL;
-  return GRPC_CHTTP2_PARSE_OK;
-}
-
-void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
-                                     grpc_chttp2_data_parser *parser) {
-  grpc_byte_stream *bs;
-  if (parser->parsing_frame) {
-    grpc_chttp2_incoming_byte_stream_finished(exec_ctx, parser->parsing_frame,
-                                              0, 1);
-  }
-  while (
-      (bs = grpc_chttp2_incoming_frame_queue_pop(&parser->incoming_frames))) {
-    grpc_byte_stream_destroy(exec_ctx, bs);
-  }
-}
-
-grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
-    grpc_chttp2_data_parser *parser, uint8_t flags) {
-  if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
-    gpr_log(GPR_ERROR, "unsupported data flags: 0x%02x", flags);
-    return GRPC_CHTTP2_STREAM_ERROR;
-  }
-
-  if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
-    parser->is_last_frame = 1;
-  } else {
-    parser->is_last_frame = 0;
-  }
-
-  return GRPC_CHTTP2_PARSE_OK;
-}
-
-void grpc_chttp2_incoming_frame_queue_merge(
-    grpc_chttp2_incoming_frame_queue *head_dst,
-    grpc_chttp2_incoming_frame_queue *tail_src) {
-  if (tail_src->head == NULL) {
-    return;
-  }
-
-  if (head_dst->head == NULL) {
-    *head_dst = *tail_src;
-    memset(tail_src, 0, sizeof(*tail_src));
-    return;
-  }
-
-  head_dst->tail->next_message = tail_src->head;
-  head_dst->tail = tail_src->tail;
-  memset(tail_src, 0, sizeof(*tail_src));
-}
-
-grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop(
-    grpc_chttp2_incoming_frame_queue *q) {
-  grpc_byte_stream *out;
-  if (q->head == NULL) {
-    return NULL;
-  }
-  out = &q->head->base;
-  if (q->head == q->tail) {
-    memset(q, 0, sizeof(*q));
-  } else {
-    q->head = q->head->next_message;
-  }
-  return out;
-}
-
-void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf,
-                             uint32_t write_bytes, int is_eof,
-                             gpr_slice_buffer *outbuf) {
-  gpr_slice hdr;
-  uint8_t *p;
-
-  hdr = gpr_slice_malloc(9);
-  p = GPR_SLICE_START_PTR(hdr);
-  GPR_ASSERT(write_bytes < (1 << 24));
-  *p++ = (uint8_t)(write_bytes >> 16);
-  *p++ = (uint8_t)(write_bytes >> 8);
-  *p++ = (uint8_t)(write_bytes);
-  *p++ = GRPC_CHTTP2_FRAME_DATA;
-  *p++ = is_eof ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0;
-  *p++ = (uint8_t)(id >> 24);
-  *p++ = (uint8_t)(id >> 16);
-  *p++ = (uint8_t)(id >> 8);
-  *p++ = (uint8_t)(id);
-  gpr_slice_buffer_add(outbuf, hdr);
-
-  gpr_slice_buffer_move_first(inbuf, write_bytes, outbuf);
-}
-
-grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
-  uint8_t *const beg = GPR_SLICE_START_PTR(slice);
-  uint8_t *const end = GPR_SLICE_END_PTR(slice);
-  uint8_t *cur = beg;
-  grpc_chttp2_data_parser *p = parser;
-  uint32_t message_flags;
-  grpc_chttp2_incoming_byte_stream *incoming_byte_stream;
-
-  if (is_last && p->is_last_frame) {
-    stream_parsing->received_close = 1;
-  }
-
-  if (cur == end) {
-    return GRPC_CHTTP2_PARSE_OK;
-  }
-
-  switch (p->state) {
-  fh_0:
-    case GRPC_CHTTP2_DATA_FH_0:
-      p->frame_type = *cur;
-      switch (p->frame_type) {
-        case 0:
-          p->is_frame_compressed = 0; /* GPR_FALSE */
-          break;
-        case 1:
-          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 = ((uint32_t)*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 |= ((uint32_t)*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 |= ((uint32_t)*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 |= ((uint32_t)*cur);
-      p->state = GRPC_CHTTP2_DATA_FRAME;
-      ++cur;
-      message_flags = 0;
-      if (p->is_frame_compressed) {
-        message_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
-      }
-      p->parsing_frame = incoming_byte_stream =
-          grpc_chttp2_incoming_byte_stream_create(
-              exec_ctx, transport_parsing, stream_parsing, p->frame_size,
-              message_flags, &p->incoming_frames);
-    /* 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;
-      }
-      grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
-                                               stream_parsing);
-      if ((uint32_t)(end - cur) == p->frame_size) {
-        grpc_chttp2_incoming_byte_stream_push(
-            exec_ctx, p->parsing_frame,
-            gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
-        grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1,
-                                                  1);
-        p->parsing_frame = NULL;
-        p->state = GRPC_CHTTP2_DATA_FH_0;
-        return GRPC_CHTTP2_PARSE_OK;
-      } else if ((uint32_t)(end - cur) > p->frame_size) {
-        grpc_chttp2_incoming_byte_stream_push(
-            exec_ctx, p->parsing_frame,
-            gpr_slice_sub(slice, (size_t)(cur - beg),
-                          (size_t)(cur + p->frame_size - beg)));
-        grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1,
-                                                  1);
-        p->parsing_frame = NULL;
-        cur += p->frame_size;
-        goto fh_0; /* loop */
-      } else {
-        grpc_chttp2_incoming_byte_stream_push(
-            exec_ctx, p->parsing_frame,
-            gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
-        GPR_ASSERT((size_t)(end - cur) <= p->frame_size);
-        p->frame_size -= (uint32_t)(end - cur);
-        return GRPC_CHTTP2_PARSE_OK;
-      }
-  }
-
-  GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
-}
diff --git a/src/core/transport/chttp2/frame_data.h b/src/core/transport/chttp2/frame_data.h
deleted file mode 100644
index 936b7a2..0000000
--- a/src/core/transport/chttp2/frame_data.h
+++ /dev/null
@@ -1,101 +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_TRANSPORT_CHTTP2_FRAME_DATA_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_DATA_H
-
-/* Parser for GRPC streams embedded in DATA frames */
-
-#include "src/core/iomgr/exec_ctx.h"
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
-#include "src/core/transport/byte_stream.h"
-#include "src/core/transport/chttp2/frame.h"
-
-typedef enum {
-  GRPC_CHTTP2_DATA_FH_0,
-  GRPC_CHTTP2_DATA_FH_1,
-  GRPC_CHTTP2_DATA_FH_2,
-  GRPC_CHTTP2_DATA_FH_3,
-  GRPC_CHTTP2_DATA_FH_4,
-  GRPC_CHTTP2_DATA_FRAME
-} grpc_chttp2_stream_state;
-
-typedef struct grpc_chttp2_incoming_byte_stream
-    grpc_chttp2_incoming_byte_stream;
-
-typedef struct grpc_chttp2_incoming_frame_queue {
-  grpc_chttp2_incoming_byte_stream *head;
-  grpc_chttp2_incoming_byte_stream *tail;
-} grpc_chttp2_incoming_frame_queue;
-
-typedef struct {
-  grpc_chttp2_stream_state state;
-  uint8_t is_last_frame;
-  uint8_t frame_type;
-  uint32_t frame_size;
-
-  int is_frame_compressed;
-  grpc_chttp2_incoming_frame_queue incoming_frames;
-  grpc_chttp2_incoming_byte_stream *parsing_frame;
-} grpc_chttp2_data_parser;
-
-void grpc_chttp2_incoming_frame_queue_merge(
-    grpc_chttp2_incoming_frame_queue *head_dst,
-    grpc_chttp2_incoming_frame_queue *tail_src);
-grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop(
-    grpc_chttp2_incoming_frame_queue *q);
-
-/* initialize per-stream state for data frame parsing */
-grpc_chttp2_parse_error grpc_chttp2_data_parser_init(
-    grpc_chttp2_data_parser *parser);
-
-void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
-                                     grpc_chttp2_data_parser *parser);
-
-/* start processing a new data frame */
-grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
-    grpc_chttp2_data_parser *parser, uint8_t flags);
-
-/* 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(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
-
-void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf,
-                             uint32_t write_bytes, int is_eof,
-                             gpr_slice_buffer *outbuf);
-
-#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
deleted file mode 100644
index 2fa525e..0000000
--- a/src/core/transport/chttp2/frame_goaway.c
+++ /dev/null
@@ -1,193 +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/transport/chttp2/frame_goaway.h"
-#include "src/core/transport/chttp2/internal.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p) {
-  p->debug_data = NULL;
-}
-
-void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p) {
-  gpr_free(p->debug_data);
-}
-
-grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
-    grpc_chttp2_goaway_parser *p, uint32_t length, uint8_t flags) {
-  if (length < 8) {
-    gpr_log(GPR_ERROR, "goaway frame too short (%d bytes)", length);
-    return GRPC_CHTTP2_CONNECTION_ERROR;
-  }
-
-  gpr_free(p->debug_data);
-  p->debug_length = length - 8;
-  p->debug_data = gpr_malloc(p->debug_length);
-  p->debug_pos = 0;
-  p->state = GRPC_CHTTP2_GOAWAY_LSI0;
-  return GRPC_CHTTP2_PARSE_OK;
-}
-
-grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
-  uint8_t *const beg = GPR_SLICE_START_PTR(slice);
-  uint8_t *const end = GPR_SLICE_END_PTR(slice);
-  uint8_t *cur = beg;
-  grpc_chttp2_goaway_parser *p = parser;
-
-  switch (p->state) {
-    case GRPC_CHTTP2_GOAWAY_LSI0:
-      if (cur == end) {
-        p->state = GRPC_CHTTP2_GOAWAY_LSI0;
-        return GRPC_CHTTP2_PARSE_OK;
-      }
-      p->last_stream_id = ((uint32_t)*cur) << 24;
-      ++cur;
-    /* fallthrough */
-    case GRPC_CHTTP2_GOAWAY_LSI1:
-      if (cur == end) {
-        p->state = GRPC_CHTTP2_GOAWAY_LSI1;
-        return GRPC_CHTTP2_PARSE_OK;
-      }
-      p->last_stream_id |= ((uint32_t)*cur) << 16;
-      ++cur;
-    /* fallthrough */
-    case GRPC_CHTTP2_GOAWAY_LSI2:
-      if (cur == end) {
-        p->state = GRPC_CHTTP2_GOAWAY_LSI2;
-        return GRPC_CHTTP2_PARSE_OK;
-      }
-      p->last_stream_id |= ((uint32_t)*cur) << 8;
-      ++cur;
-    /* fallthrough */
-    case GRPC_CHTTP2_GOAWAY_LSI3:
-      if (cur == end) {
-        p->state = GRPC_CHTTP2_GOAWAY_LSI3;
-        return GRPC_CHTTP2_PARSE_OK;
-      }
-      p->last_stream_id |= ((uint32_t)*cur);
-      ++cur;
-    /* fallthrough */
-    case GRPC_CHTTP2_GOAWAY_ERR0:
-      if (cur == end) {
-        p->state = GRPC_CHTTP2_GOAWAY_ERR0;
-        return GRPC_CHTTP2_PARSE_OK;
-      }
-      p->error_code = ((uint32_t)*cur) << 24;
-      ++cur;
-    /* fallthrough */
-    case GRPC_CHTTP2_GOAWAY_ERR1:
-      if (cur == end) {
-        p->state = GRPC_CHTTP2_GOAWAY_ERR1;
-        return GRPC_CHTTP2_PARSE_OK;
-      }
-      p->error_code |= ((uint32_t)*cur) << 16;
-      ++cur;
-    /* fallthrough */
-    case GRPC_CHTTP2_GOAWAY_ERR2:
-      if (cur == end) {
-        p->state = GRPC_CHTTP2_GOAWAY_ERR2;
-        return GRPC_CHTTP2_PARSE_OK;
-      }
-      p->error_code |= ((uint32_t)*cur) << 8;
-      ++cur;
-    /* fallthrough */
-    case GRPC_CHTTP2_GOAWAY_ERR3:
-      if (cur == end) {
-        p->state = GRPC_CHTTP2_GOAWAY_ERR3;
-        return GRPC_CHTTP2_PARSE_OK;
-      }
-      p->error_code |= ((uint32_t)*cur);
-      ++cur;
-    /* fallthrough */
-    case GRPC_CHTTP2_GOAWAY_DEBUG:
-      memcpy(p->debug_data + p->debug_pos, cur, (size_t)(end - cur));
-      GPR_ASSERT((size_t)(end - cur) < UINT32_MAX - p->debug_pos);
-      p->debug_pos += (uint32_t)(end - cur);
-      p->state = GRPC_CHTTP2_GOAWAY_DEBUG;
-      if (is_last) {
-        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 = (grpc_status_code)p->error_code;
-        transport_parsing->goaway_text =
-            gpr_slice_new(p->debug_data, p->debug_length, gpr_free);
-        p->debug_data = NULL;
-      }
-      return GRPC_CHTTP2_PARSE_OK;
-  }
-  GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
-}
-
-void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,
-                               gpr_slice debug_data,
-                               gpr_slice_buffer *slice_buffer) {
-  gpr_slice header = gpr_slice_malloc(9 + 4 + 4);
-  uint8_t *p = GPR_SLICE_START_PTR(header);
-  uint32_t frame_length;
-  GPR_ASSERT(GPR_SLICE_LENGTH(debug_data) < UINT32_MAX - 4 - 4);
-  frame_length = 4 + 4 + (uint32_t)GPR_SLICE_LENGTH(debug_data);
-
-  /* frame header: length */
-  *p++ = (uint8_t)(frame_length >> 16);
-  *p++ = (uint8_t)(frame_length >> 8);
-  *p++ = (uint8_t)(frame_length);
-  /* frame header: type */
-  *p++ = GRPC_CHTTP2_FRAME_GOAWAY;
-  /* frame header: flags */
-  *p++ = 0;
-  /* frame header: stream id */
-  *p++ = 0;
-  *p++ = 0;
-  *p++ = 0;
-  *p++ = 0;
-  /* payload: last stream id */
-  *p++ = (uint8_t)(last_stream_id >> 24);
-  *p++ = (uint8_t)(last_stream_id >> 16);
-  *p++ = (uint8_t)(last_stream_id >> 8);
-  *p++ = (uint8_t)(last_stream_id);
-  /* payload: error code */
-  *p++ = (uint8_t)(error_code >> 24);
-  *p++ = (uint8_t)(error_code >> 16);
-  *p++ = (uint8_t)(error_code >> 8);
-  *p++ = (uint8_t)(error_code);
-  GPR_ASSERT(p == GPR_SLICE_END_PTR(header));
-  gpr_slice_buffer_add(slice_buffer, header);
-  gpr_slice_buffer_add(slice_buffer, debug_data);
-}
diff --git a/src/core/transport/chttp2/frame_goaway.h b/src/core/transport/chttp2/frame_goaway.h
deleted file mode 100644
index e1a72b4..0000000
--- a/src/core/transport/chttp2/frame_goaway.h
+++ /dev/null
@@ -1,77 +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_TRANSPORT_CHTTP2_FRAME_GOAWAY_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H
-
-#include "src/core/iomgr/exec_ctx.h"
-#include "src/core/transport/chttp2/frame.h"
-#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
-
-typedef enum {
-  GRPC_CHTTP2_GOAWAY_LSI0,
-  GRPC_CHTTP2_GOAWAY_LSI1,
-  GRPC_CHTTP2_GOAWAY_LSI2,
-  GRPC_CHTTP2_GOAWAY_LSI3,
-  GRPC_CHTTP2_GOAWAY_ERR0,
-  GRPC_CHTTP2_GOAWAY_ERR1,
-  GRPC_CHTTP2_GOAWAY_ERR2,
-  GRPC_CHTTP2_GOAWAY_ERR3,
-  GRPC_CHTTP2_GOAWAY_DEBUG
-} grpc_chttp2_goaway_parse_state;
-
-typedef struct {
-  grpc_chttp2_goaway_parse_state state;
-  uint32_t last_stream_id;
-  uint32_t error_code;
-  char *debug_data;
-  uint32_t debug_length;
-  uint32_t debug_pos;
-} grpc_chttp2_goaway_parser;
-
-void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p);
-void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p);
-grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
-    grpc_chttp2_goaway_parser *parser, uint32_t length, uint8_t flags);
-grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
-    grpc_exec_ctx *exec_ctx, 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(uint32_t last_stream_id, uint32_t error_code,
-                               gpr_slice debug_data,
-                               gpr_slice_buffer *slice_buffer);
-
-#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
deleted file mode 100644
index c6ab522..0000000
--- a/src/core/transport/chttp2/frame_ping.c
+++ /dev/null
@@ -1,97 +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/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(uint8_t ack, uint8_t *opaque_8bytes) {
-  gpr_slice slice = gpr_slice_malloc(9 + 8);
-  uint8_t *p = GPR_SLICE_START_PTR(slice);
-
-  *p++ = 0;
-  *p++ = 0;
-  *p++ = 8;
-  *p++ = GRPC_CHTTP2_FRAME_PING;
-  *p++ = ack ? 1 : 0;
-  *p++ = 0;
-  *p++ = 0;
-  *p++ = 0;
-  *p++ = 0;
-  memcpy(p, opaque_8bytes, 8);
-
-  return slice;
-}
-
-grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
-    grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags) {
-  if (flags & 0xfe || length != 8) {
-    gpr_log(GPR_ERROR, "invalid ping: length=%d, flags=%02x", length, flags);
-    return GRPC_CHTTP2_CONNECTION_ERROR;
-  }
-  parser->byte = 0;
-  parser->is_ack = flags;
-  return GRPC_CHTTP2_PARSE_OK;
-}
-
-grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
-  uint8_t *const beg = GPR_SLICE_START_PTR(slice);
-  uint8_t *const end = GPR_SLICE_END_PTR(slice);
-  uint8_t *cur = beg;
-  grpc_chttp2_ping_parser *p = parser;
-
-  while (p->byte != 8 && cur != end) {
-    p->opaque_8bytes[p->byte] = *cur;
-    cur++;
-    p->byte++;
-  }
-
-  if (p->byte == 8) {
-    GPR_ASSERT(is_last);
-    if (p->is_ack) {
-      grpc_chttp2_ack_ping(exec_ctx, transport_parsing, p->opaque_8bytes);
-    } else {
-      gpr_slice_buffer_add(&transport_parsing->qbuf,
-                           grpc_chttp2_ping_create(1, p->opaque_8bytes));
-    }
-  }
-
-  return GRPC_CHTTP2_PARSE_OK;
-}
diff --git a/src/core/transport/chttp2/frame_ping.h b/src/core/transport/chttp2/frame_ping.h
deleted file mode 100644
index 16d7a72..0000000
--- a/src/core/transport/chttp2/frame_ping.h
+++ /dev/null
@@ -1,56 +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_TRANSPORT_CHTTP2_FRAME_PING_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_PING_H
-
-#include "src/core/iomgr/exec_ctx.h"
-#include <grpc/support/slice.h>
-#include "src/core/transport/chttp2/frame.h"
-
-typedef struct {
-  uint8_t byte;
-  uint8_t is_ack;
-  uint8_t opaque_8bytes[8];
-} grpc_chttp2_ping_parser;
-
-gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes);
-
-grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
-    grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags);
-grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
-    grpc_exec_ctx *exec_ctx, 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 */
diff --git a/src/core/transport/chttp2/frame_rst_stream.c b/src/core/transport/chttp2/frame_rst_stream.c
deleted file mode 100644
index 754529e..0000000
--- a/src/core/transport/chttp2/frame_rst_stream.c
+++ /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 "src/core/transport/chttp2/frame_rst_stream.h"
-#include "src/core/transport/chttp2/internal.h"
-
-#include <grpc/support/log.h>
-
-#include "src/core/transport/chttp2/frame.h"
-
-gpr_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code) {
-  gpr_slice slice = gpr_slice_malloc(13);
-  uint8_t *p = GPR_SLICE_START_PTR(slice);
-
-  *p++ = 0;
-  *p++ = 0;
-  *p++ = 4;
-  *p++ = GRPC_CHTTP2_FRAME_RST_STREAM;
-  *p++ = 0;
-  *p++ = (uint8_t)(id >> 24);
-  *p++ = (uint8_t)(id >> 16);
-  *p++ = (uint8_t)(id >> 8);
-  *p++ = (uint8_t)(id);
-  *p++ = (uint8_t)(code >> 24);
-  *p++ = (uint8_t)(code >> 16);
-  *p++ = (uint8_t)(code >> 8);
-  *p++ = (uint8_t)(code);
-
-  return slice;
-}
-
-grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame(
-    grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags) {
-  if (length != 4) {
-    gpr_log(GPR_ERROR, "invalid rst_stream: length=%d, flags=%02x", length,
-            flags);
-    return GRPC_CHTTP2_CONNECTION_ERROR;
-  }
-  parser->byte = 0;
-  return GRPC_CHTTP2_PARSE_OK;
-}
-
-grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
-  uint8_t *const beg = GPR_SLICE_START_PTR(slice);
-  uint8_t *const end = GPR_SLICE_END_PTR(slice);
-  uint8_t *cur = beg;
-  grpc_chttp2_rst_stream_parser *p = parser;
-
-  while (p->byte != 4 && cur != end) {
-    p->reason_bytes[p->byte] = *cur;
-    cur++;
-    p->byte++;
-  }
-
-  if (p->byte == 4) {
-    GPR_ASSERT(is_last);
-    stream_parsing->received_close = 1;
-    stream_parsing->saw_rst_stream = 1;
-    stream_parsing->rst_stream_reason = (((uint32_t)p->reason_bytes[0]) << 24) |
-                                        (((uint32_t)p->reason_bytes[1]) << 16) |
-                                        (((uint32_t)p->reason_bytes[2]) << 8) |
-                                        (((uint32_t)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
deleted file mode 100644
index 72ca654..0000000
--- a/src/core/transport/chttp2/frame_rst_stream.h
+++ /dev/null
@@ -1,55 +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_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H
-
-#include <grpc/support/slice.h>
-#include "src/core/transport/chttp2/frame.h"
-#include "src/core/iomgr/exec_ctx.h"
-
-typedef struct {
-  uint8_t byte;
-  uint8_t reason_bytes[4];
-} grpc_chttp2_rst_stream_parser;
-
-gpr_slice grpc_chttp2_rst_stream_create(uint32_t stream_id, uint32_t code);
-
-grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame(
-    grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags);
-grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
-    grpc_exec_ctx *exec_ctx, 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 */
diff --git a/src/core/transport/chttp2/frame_settings.c b/src/core/transport/chttp2/frame_settings.c
deleted file mode 100644
index cc49dd4..0000000
--- a/src/core/transport/chttp2/frame_settings.c
+++ /dev/null
@@ -1,259 +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/transport/chttp2/frame_settings.h"
-#include "src/core/transport/chttp2/internal.h"
-
-#include <string.h>
-
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/debug/trace.h"
-#include "src/core/transport/chttp2/frame.h"
-#include "src/core/transport/chttp2/http2_errors.h"
-#include "src/core/transport/chttp2_transport.h"
-
-#define MAX_MAX_HEADER_LIST_SIZE (1024 * 1024 * 1024)
-
-/* HTTP/2 mandated initial connection settings */
-const grpc_chttp2_setting_parameters
-    grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
-        {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
-         GRPC_CHTTP2_PROTOCOL_ERROR},
-        {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff,
-         GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
-        {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
-         GRPC_CHTTP2_PROTOCOL_ERROR},
-        {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu,
-         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
-        {"INITIAL_WINDOW_SIZE", 65535, 0, 0x7fffffffu,
-         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
-         GRPC_CHTTP2_FLOW_CONTROL_ERROR},
-        {"MAX_FRAME_SIZE", 16384, 16384, 16777215,
-         GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
-        {"MAX_HEADER_LIST_SIZE", MAX_MAX_HEADER_LIST_SIZE, 0,
-         MAX_MAX_HEADER_LIST_SIZE, GRPC_CHTTP2_CLAMP_INVALID_VALUE,
-         GRPC_CHTTP2_PROTOCOL_ERROR},
-};
-
-static uint8_t *fill_header(uint8_t *out, uint32_t length, uint8_t flags) {
-  *out++ = (uint8_t)(length >> 16);
-  *out++ = (uint8_t)(length >> 8);
-  *out++ = (uint8_t)(length);
-  *out++ = GRPC_CHTTP2_FRAME_SETTINGS;
-  *out++ = flags;
-  *out++ = 0;
-  *out++ = 0;
-  *out++ = 0;
-  *out++ = 0;
-  return out;
-}
-
-gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
-                                      uint32_t force_mask, size_t count) {
-  size_t i;
-  uint32_t n = 0;
-  gpr_slice output;
-  uint8_t *p;
-
-  for (i = 0; i < count; i++) {
-    n += (new[i] != old[i] || (force_mask & (1u << i)) != 0);
-  }
-
-  output = gpr_slice_malloc(9 + 6 * n);
-  p = fill_header(GPR_SLICE_START_PTR(output), 6 * n, 0);
-
-  for (i = 0; i < count; i++) {
-    if (new[i] != old[i] || (force_mask & (1u << i)) != 0) {
-      GPR_ASSERT(i);
-      *p++ = (uint8_t)(i >> 8);
-      *p++ = (uint8_t)(i);
-      *p++ = (uint8_t)(new[i] >> 24);
-      *p++ = (uint8_t)(new[i] >> 16);
-      *p++ = (uint8_t)(new[i] >> 8);
-      *p++ = (uint8_t)(new[i]);
-      old[i] = new[i];
-    }
-  }
-
-  GPR_ASSERT(p == GPR_SLICE_END_PTR(output));
-
-  return output;
-}
-
-gpr_slice grpc_chttp2_settings_ack_create(void) {
-  gpr_slice output = gpr_slice_malloc(9);
-  fill_header(GPR_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
-  return output;
-}
-
-grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
-    grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags,
-    uint32_t *settings) {
-  parser->target_settings = settings;
-  memcpy(parser->incoming_settings, settings,
-         GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
-  parser->is_ack = 0;
-  parser->state = GRPC_CHTTP2_SPS_ID0;
-  if (flags == GRPC_CHTTP2_FLAG_ACK) {
-    parser->is_ack = 1;
-    if (length != 0) {
-      gpr_log(GPR_ERROR, "non-empty settings ack frame received");
-      return GRPC_CHTTP2_CONNECTION_ERROR;
-    }
-    return GRPC_CHTTP2_PARSE_OK;
-  } else if (flags != 0) {
-    gpr_log(GPR_ERROR, "invalid flags on settings frame");
-    return GRPC_CHTTP2_CONNECTION_ERROR;
-  } else if (length % 6 != 0) {
-    gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes");
-    return GRPC_CHTTP2_CONNECTION_ERROR;
-  } else {
-    return GRPC_CHTTP2_PARSE_OK;
-  }
-}
-
-grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
-    grpc_exec_ctx *exec_ctx, 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 uint8_t *cur = GPR_SLICE_START_PTR(slice);
-  const uint8_t *end = GPR_SLICE_END_PTR(slice);
-
-  if (parser->is_ack) {
-    return GRPC_CHTTP2_PARSE_OK;
-  }
-
-  for (;;) {
-    switch (parser->state) {
-      case GRPC_CHTTP2_SPS_ID0:
-        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(uint32_t));
-            gpr_slice_buffer_add(&transport_parsing->qbuf,
-                                 grpc_chttp2_settings_ack_create());
-          }
-          return GRPC_CHTTP2_PARSE_OK;
-        }
-        parser->id = (uint16_t)(((uint16_t)*cur) << 8);
-        cur++;
-      /* fallthrough */
-      case GRPC_CHTTP2_SPS_ID1:
-        if (cur == end) {
-          parser->state = GRPC_CHTTP2_SPS_ID1;
-          return GRPC_CHTTP2_PARSE_OK;
-        }
-        parser->id = (uint16_t)(parser->id | (*cur));
-        cur++;
-      /* fallthrough */
-      case GRPC_CHTTP2_SPS_VAL0:
-        if (cur == end) {
-          parser->state = GRPC_CHTTP2_SPS_VAL0;
-          return GRPC_CHTTP2_PARSE_OK;
-        }
-        parser->value = ((uint32_t)*cur) << 24;
-        cur++;
-      /* fallthrough */
-      case GRPC_CHTTP2_SPS_VAL1:
-        if (cur == end) {
-          parser->state = GRPC_CHTTP2_SPS_VAL1;
-          return GRPC_CHTTP2_PARSE_OK;
-        }
-        parser->value |= ((uint32_t)*cur) << 16;
-        cur++;
-      /* fallthrough */
-      case GRPC_CHTTP2_SPS_VAL2:
-        if (cur == end) {
-          parser->state = GRPC_CHTTP2_SPS_VAL2;
-          return GRPC_CHTTP2_PARSE_OK;
-        }
-        parser->value |= ((uint32_t)*cur) << 8;
-        cur++;
-      /* fallthrough */
-      case GRPC_CHTTP2_SPS_VAL3:
-        if (cur == end) {
-          parser->state = GRPC_CHTTP2_SPS_VAL3;
-          return GRPC_CHTTP2_PARSE_OK;
-        } else {
-          parser->state = GRPC_CHTTP2_SPS_ID0;
-        }
-        parser->value |= *cur;
-        cur++;
-
-        if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) {
-          const grpc_chttp2_setting_parameters *sp =
-              &grpc_chttp2_settings_parameters[parser->id];
-          if (parser->value < sp->min_value || parser->value > sp->max_value) {
-            switch (sp->invalid_value_behavior) {
-              case GRPC_CHTTP2_CLAMP_INVALID_VALUE:
-                parser->value =
-                    GPR_CLAMP(parser->value, sp->min_value, sp->max_value);
-                break;
-              case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE:
-                grpc_chttp2_goaway_append(
-                    transport_parsing->last_incoming_stream_id, sp->error_value,
-                    gpr_slice_from_static_string("HTTP2 settings error"),
-                    &transport_parsing->qbuf);
-                gpr_log(GPR_ERROR, "invalid value %u passed for %s",
-                        parser->value, sp->name);
-                return GRPC_CHTTP2_CONNECTION_ERROR;
-            }
-          }
-          if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
-              parser->incoming_settings[parser->id] != parser->value) {
-            transport_parsing->initial_window_update =
-                (int64_t)parser->value - parser->incoming_settings[parser->id];
-            if (grpc_http_trace) {
-              gpr_log(GPR_DEBUG, "adding %d for initial_window change",
-                      (int)transport_parsing->initial_window_update);
-            }
-          }
-          parser->incoming_settings[parser->id] = parser->value;
-          if (grpc_http_trace) {
-            gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d",
-                    transport_parsing->is_client ? "CLI" : "SVR", parser->id,
-                    parser->value);
-          }
-        } else {
-          gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
-                  parser->id, parser->value);
-        }
-        break;
-    }
-  }
-}
diff --git a/src/core/transport/chttp2/frame_settings.h b/src/core/transport/chttp2/frame_settings.h
deleted file mode 100644
index 3c918e3..0000000
--- a/src/core/transport/chttp2/frame_settings.h
+++ /dev/null
@@ -1,103 +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_TRANSPORT_CHTTP2_FRAME_SETTINGS_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H
-
-#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include "src/core/transport/chttp2/frame.h"
-#include "src/core/iomgr/exec_ctx.h"
-
-typedef enum {
-  GRPC_CHTTP2_SPS_ID0,
-  GRPC_CHTTP2_SPS_ID1,
-  GRPC_CHTTP2_SPS_VAL0,
-  GRPC_CHTTP2_SPS_VAL1,
-  GRPC_CHTTP2_SPS_VAL2,
-  GRPC_CHTTP2_SPS_VAL3
-} grpc_chttp2_settings_parse_state;
-
-/* The things HTTP/2 defines as connection level settings */
-typedef enum {
-  GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE = 1,
-  GRPC_CHTTP2_SETTINGS_ENABLE_PUSH = 2,
-  GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 3,
-  GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 4,
-  GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE = 5,
-  GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 6,
-  GRPC_CHTTP2_NUM_SETTINGS
-} grpc_chttp2_setting_id;
-
-typedef struct {
-  grpc_chttp2_settings_parse_state state;
-  uint32_t *target_settings;
-  uint8_t is_ack;
-  uint16_t id;
-  uint32_t value;
-  uint32_t incoming_settings[GRPC_CHTTP2_NUM_SETTINGS];
-} grpc_chttp2_settings_parser;
-
-typedef enum {
-  GRPC_CHTTP2_CLAMP_INVALID_VALUE,
-  GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE
-} grpc_chttp2_invalid_value_behavior;
-
-typedef struct {
-  const char *name;
-  uint32_t default_value;
-  uint32_t min_value;
-  uint32_t max_value;
-  grpc_chttp2_invalid_value_behavior invalid_value_behavior;
-  uint32_t error_value;
-} grpc_chttp2_setting_parameters;
-
-/* HTTP/2 mandated connection setting parameters */
-extern const grpc_chttp2_setting_parameters
-    grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS];
-
-/* Create a settings frame by diffing old & new, and updating old to be new */
-gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
-                                      uint32_t force_mask, size_t count);
-/* Create an ack settings frame */
-gpr_slice grpc_chttp2_settings_ack_create(void);
-
-grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
-    grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags,
-    uint32_t *settings);
-grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
-    grpc_exec_ctx *exec_ctx, 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 */
diff --git a/src/core/transport/chttp2/frame_window_update.c b/src/core/transport/chttp2/frame_window_update.c
deleted file mode 100644
index 62d9bac..0000000
--- a/src/core/transport/chttp2/frame_window_update.c
+++ /dev/null
@@ -1,113 +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/transport/chttp2/frame_window_update.h"
-#include "src/core/transport/chttp2/internal.h"
-
-#include <grpc/support/log.h>
-
-gpr_slice grpc_chttp2_window_update_create(uint32_t id,
-                                           uint32_t window_update) {
-  gpr_slice slice = gpr_slice_malloc(13);
-  uint8_t *p = GPR_SLICE_START_PTR(slice);
-
-  GPR_ASSERT(window_update);
-
-  *p++ = 0;
-  *p++ = 0;
-  *p++ = 4;
-  *p++ = GRPC_CHTTP2_FRAME_WINDOW_UPDATE;
-  *p++ = 0;
-  *p++ = (uint8_t)(id >> 24);
-  *p++ = (uint8_t)(id >> 16);
-  *p++ = (uint8_t)(id >> 8);
-  *p++ = (uint8_t)(id);
-  *p++ = (uint8_t)(window_update >> 24);
-  *p++ = (uint8_t)(window_update >> 16);
-  *p++ = (uint8_t)(window_update >> 8);
-  *p++ = (uint8_t)(window_update);
-
-  return slice;
-}
-
-grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
-    grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags) {
-  if (flags || length != 4) {
-    gpr_log(GPR_ERROR, "invalid window update: length=%d, flags=%02x", length,
-            flags);
-    return GRPC_CHTTP2_CONNECTION_ERROR;
-  }
-  parser->byte = 0;
-  parser->amount = 0;
-  return GRPC_CHTTP2_PARSE_OK;
-}
-
-grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
-  uint8_t *const beg = GPR_SLICE_START_PTR(slice);
-  uint8_t *const end = GPR_SLICE_END_PTR(slice);
-  uint8_t *cur = beg;
-  grpc_chttp2_window_update_parser *p = parser;
-
-  while (p->byte != 4 && cur != end) {
-    p->amount |= ((uint32_t)*cur) << (8 * (3 - p->byte));
-    cur++;
-    p->byte++;
-  }
-
-  if (p->byte == 4) {
-    uint32_t received_update = p->amount;
-    if (received_update == 0 || (received_update & 0x80000000u)) {
-      gpr_log(GPR_ERROR, "invalid window update bytes: %d", p->amount);
-      return GRPC_CHTTP2_CONNECTION_ERROR;
-    }
-    GPR_ASSERT(is_last);
-
-    if (transport_parsing->incoming_stream_id != 0) {
-      if (stream_parsing != NULL) {
-        GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", transport_parsing,
-                                       stream_parsing, outgoing_window,
-                                       received_update);
-        grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
-                                                 stream_parsing);
-      }
-    } else {
-      GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parse", transport_parsing,
-                                        outgoing_window, received_update);
-    }
-  }
-
-  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
deleted file mode 100644
index 89d835c..0000000
--- a/src/core/transport/chttp2/frame_window_update.h
+++ /dev/null
@@ -1,56 +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_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H
-
-#include "src/core/iomgr/exec_ctx.h"
-#include <grpc/support/slice.h>
-#include "src/core/transport/chttp2/frame.h"
-
-typedef struct {
-  uint8_t byte;
-  uint8_t is_connection_update;
-  uint32_t amount;
-} grpc_chttp2_window_update_parser;
-
-gpr_slice grpc_chttp2_window_update_create(uint32_t id, uint32_t window_delta);
-
-grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
-    grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags);
-grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
-    grpc_exec_ctx *exec_ctx, 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 */
diff --git a/src/core/transport/chttp2/hpack_encoder.c b/src/core/transport/chttp2/hpack_encoder.c
deleted file mode 100644
index f30f574..0000000
--- a/src/core/transport/chttp2/hpack_encoder.c
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/transport/chttp2/hpack_encoder.h"
-
-#include <assert.h>
-#include <string.h>
-
-/* This is here for grpc_is_binary_header
- * TODO(murgatroid99): Remove this
- */
-#include <grpc/grpc.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/transport/chttp2/bin_encoder.h"
-#include "src/core/transport/chttp2/hpack_table.h"
-#include "src/core/transport/chttp2/timeout_encoding.h"
-#include "src/core/transport/chttp2/varint.h"
-#include "src/core/transport/static_metadata.h"
-
-#define HASH_FRAGMENT_1(x) ((x)&255)
-#define HASH_FRAGMENT_2(x) ((x >> 8) & 255)
-#define HASH_FRAGMENT_3(x) ((x >> 16) & 255)
-#define HASH_FRAGMENT_4(x) ((x >> 24) & 255)
-
-/* if the probability of this item being seen again is < 1/x then don't add
-   it to the table */
-#define ONE_ON_ADD_PROBABILITY 128
-/* don't consider adding anything bigger than this to the hpack table */
-#define MAX_DECODER_SPACE_USAGE 512
-
-typedef struct {
-  int is_first_frame;
-  /* number of bytes in 'output' when we started the frame - used to calculate
-     frame length */
-  size_t output_length_at_start_of_frame;
-  /* index (in output) of the header for the current frame */
-  size_t header_idx;
-  /* have we seen a regular (non-colon-prefixed) header yet? */
-  uint8_t seen_regular_header;
-  /* output stream id */
-  uint32_t stream_id;
-  gpr_slice_buffer *output;
-} framer_state;
-
-/* fills p (which is expected to be 9 bytes long) with a data frame header */
-static void fill_header(uint8_t *p, uint8_t type, uint32_t id, size_t len,
-                        uint8_t flags) {
-  GPR_ASSERT(len < 16777316);
-  *p++ = (uint8_t)(len >> 16);
-  *p++ = (uint8_t)(len >> 8);
-  *p++ = (uint8_t)(len);
-  *p++ = type;
-  *p++ = flags;
-  *p++ = (uint8_t)(id >> 24);
-  *p++ = (uint8_t)(id >> 16);
-  *p++ = (uint8_t)(id >> 8);
-  *p++ = (uint8_t)(id);
-}
-
-/* finish a frame - fill in the previously reserved header */
-static void finish_frame(framer_state *st, int is_header_boundary,
-                         int is_last_in_stream) {
-  uint8_t type = 0xff;
-  type = st->is_first_frame ? GRPC_CHTTP2_FRAME_HEADER
-                            : GRPC_CHTTP2_FRAME_CONTINUATION;
-  fill_header(
-      GPR_SLICE_START_PTR(st->output->slices[st->header_idx]), type,
-      st->stream_id, st->output->length - st->output_length_at_start_of_frame,
-      (uint8_t)((is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) |
-                (is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0)));
-  st->is_first_frame = 0;
-}
-
-/* begin a new frame: reserve off header space, remember how many bytes we'd
-   output before beginning */
-static void begin_frame(framer_state *st) {
-  st->header_idx =
-      gpr_slice_buffer_add_indexed(st->output, gpr_slice_malloc(9));
-  st->output_length_at_start_of_frame = st->output->length;
-}
-
-/* make sure that the current frame is of the type desired, and has sufficient
-   space to add at least about_to_add bytes -- finishes the current frame if
-   needed */
-static void ensure_space(framer_state *st, size_t need_bytes) {
-  if (st->output->length - st->output_length_at_start_of_frame + need_bytes <=
-      GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) {
-    return;
-  }
-  finish_frame(st, 0, 0);
-  begin_frame(st);
-}
-
-/* increment a filter count, halve all counts if one element reaches max */
-static void inc_filter(uint8_t idx, uint32_t *sum, uint8_t *elems) {
-  elems[idx]++;
-  if (elems[idx] < 255) {
-    (*sum)++;
-  } else {
-    int i;
-    *sum = 0;
-    for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_FILTERS; i++) {
-      elems[i] /= 2;
-      (*sum) += elems[i];
-    }
-  }
-}
-
-static void add_header_data(framer_state *st, gpr_slice slice) {
-  size_t len = GPR_SLICE_LENGTH(slice);
-  size_t remaining;
-  if (len == 0) return;
-  remaining = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH +
-              st->output_length_at_start_of_frame - st->output->length;
-  if (len <= remaining) {
-    gpr_slice_buffer_add(st->output, slice);
-  } else {
-    gpr_slice_buffer_add(st->output, gpr_slice_split_head(&slice, remaining));
-    finish_frame(st, 0, 0);
-    begin_frame(st);
-    add_header_data(st, slice);
-  }
-}
-
-static uint8_t *add_tiny_header_data(framer_state *st, size_t len) {
-  ensure_space(st, len);
-  return gpr_slice_buffer_tiny_add(st->output, len);
-}
-
-static void evict_entry(grpc_chttp2_hpack_compressor *c) {
-  c->tail_remote_index++;
-  GPR_ASSERT(c->tail_remote_index > 0);
-  GPR_ASSERT(c->table_size >=
-             c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
-  GPR_ASSERT(c->table_elems > 0);
-  c->table_size =
-      (uint16_t)(c->table_size -
-                 c->table_elem_size[c->tail_remote_index % c->cap_table_elems]);
-  c->table_elems--;
-}
-
-/* add an element to the decoder table */
-static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
-  uint32_t key_hash = elem->key->hash;
-  uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
-  uint32_t new_index = c->tail_remote_index + c->table_elems + 1;
-  size_t elem_size = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
-                     GPR_SLICE_LENGTH(elem->value->slice);
-
-  GPR_ASSERT(elem_size < 65536);
-
-  if (elem_size > c->max_table_size) {
-    while (c->table_size > 0) {
-      evict_entry(c);
-    }
-    return;
-  }
-
-  /* Reserve space for this element in the remote table: if this overflows
-     the current table, drop elements until it fits, matching the decompressor
-     algorithm */
-  while (c->table_size + elem_size > c->max_table_size) {
-    evict_entry(c);
-  }
-  GPR_ASSERT(c->table_elems < c->max_table_size);
-  c->table_elem_size[new_index % c->cap_table_elems] = (uint16_t)elem_size;
-  c->table_size = (uint16_t)(c->table_size + elem_size);
-  c->table_elems++;
-
-  /* Store this element into {entries,indices}_elem */
-  if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) {
-    /* already there: update with new index */
-    c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
-  } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) {
-    /* already there (cuckoo): update with new index */
-    c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
-  } else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) {
-    /* not there, but a free element: add */
-    c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
-    c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
-  } else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) {
-    /* not there (cuckoo), but a free element: add */
-    c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
-    c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
-  } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] <
-             c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) {
-    /* not there: replace oldest */
-    GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_2(elem_hash)]);
-    c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
-    c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
-  } else {
-    /* not there: replace oldest */
-    GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_3(elem_hash)]);
-    c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
-    c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
-  }
-
-  /* do exactly the same for the key (so we can find by that again too) */
-
-  if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key) {
-    c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
-  } 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->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->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);
-    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);
-    c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
-  }
-}
-
-static void emit_indexed(grpc_chttp2_hpack_compressor *c, uint32_t elem_index,
-                         framer_state *st) {
-  uint32_t len = GRPC_CHTTP2_VARINT_LENGTH(elem_index, 1);
-  GRPC_CHTTP2_WRITE_VARINT(elem_index, 1, 0x80, add_tiny_header_data(st, len),
-                           len);
-}
-
-static gpr_slice get_wire_value(grpc_mdelem *elem, uint8_t *huffman_prefix) {
-  if (grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(elem->key->slice),
-                            GPR_SLICE_LENGTH(elem->key->slice))) {
-    *huffman_prefix = 0x80;
-    return grpc_mdstr_as_base64_encoded_and_huffman_compressed(elem->value);
-  }
-  /* TODO(ctiller): opportunistically compress non-binary headers */
-  *huffman_prefix = 0x00;
-  return elem->value->slice;
-}
-
-static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c,
-                               uint32_t key_index, grpc_mdelem *elem,
-                               framer_state *st) {
-  uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2);
-  uint8_t huffman_prefix;
-  gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
-  size_t len_val = GPR_SLICE_LENGTH(value_slice);
-  uint32_t len_val_len;
-  GPR_ASSERT(len_val <= UINT32_MAX);
-  len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
-  GRPC_CHTTP2_WRITE_VARINT(key_index, 2, 0x40,
-                           add_tiny_header_data(st, len_pfx), len_pfx);
-  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
-                           add_tiny_header_data(st, len_val_len), len_val_len);
-  add_header_data(st, gpr_slice_ref(value_slice));
-}
-
-static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
-                              uint32_t key_index, grpc_mdelem *elem,
-                              framer_state *st) {
-  uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4);
-  uint8_t huffman_prefix;
-  gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
-  size_t len_val = GPR_SLICE_LENGTH(value_slice);
-  uint32_t len_val_len;
-  GPR_ASSERT(len_val <= UINT32_MAX);
-  len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
-  GRPC_CHTTP2_WRITE_VARINT(key_index, 4, 0x00,
-                           add_tiny_header_data(st, len_pfx), len_pfx);
-  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
-                           add_tiny_header_data(st, len_val_len), len_val_len);
-  add_header_data(st, gpr_slice_ref(value_slice));
-}
-
-static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
-                                 grpc_mdelem *elem, framer_state *st) {
-  uint32_t len_key = (uint32_t)GPR_SLICE_LENGTH(elem->key->slice);
-  uint8_t huffman_prefix;
-  gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
-  uint32_t len_val = (uint32_t)GPR_SLICE_LENGTH(value_slice);
-  uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
-  uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
-  GPR_ASSERT(len_key <= UINT32_MAX);
-  GPR_ASSERT(GPR_SLICE_LENGTH(value_slice) <= UINT32_MAX);
-  *add_tiny_header_data(st, 1) = 0x40;
-  GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
-                           add_tiny_header_data(st, len_key_len), len_key_len);
-  add_header_data(st, gpr_slice_ref(elem->key->slice));
-  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
-                           add_tiny_header_data(st, len_val_len), len_val_len);
-  add_header_data(st, gpr_slice_ref(value_slice));
-}
-
-static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
-                                grpc_mdelem *elem, framer_state *st) {
-  uint32_t len_key = (uint32_t)GPR_SLICE_LENGTH(elem->key->slice);
-  uint8_t huffman_prefix;
-  gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
-  uint32_t len_val = (uint32_t)GPR_SLICE_LENGTH(value_slice);
-  uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
-  uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
-  GPR_ASSERT(len_key <= UINT32_MAX);
-  GPR_ASSERT(GPR_SLICE_LENGTH(value_slice) <= UINT32_MAX);
-  *add_tiny_header_data(st, 1) = 0x00;
-  GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
-                           add_tiny_header_data(st, len_key_len), len_key_len);
-  add_header_data(st, gpr_slice_ref(elem->key->slice));
-  GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
-                           add_tiny_header_data(st, len_val_len), len_val_len);
-  add_header_data(st, gpr_slice_ref(value_slice));
-}
-
-static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c,
-                                             framer_state *st) {
-  uint32_t len = GRPC_CHTTP2_VARINT_LENGTH(c->max_table_size, 3);
-  GRPC_CHTTP2_WRITE_VARINT(c->max_table_size, 3, 0x20,
-                           add_tiny_header_data(st, len), len);
-  c->advertise_table_size_change = 0;
-}
-
-static uint32_t dynidx(grpc_chttp2_hpack_compressor *c, uint32_t elem_index) {
-  return 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY + c->tail_remote_index +
-         c->table_elems - elem_index;
-}
-
-/* encode an mdelem */
-static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
-                      framer_state *st) {
-  uint32_t key_hash = elem->key->hash;
-  uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
-  size_t decoder_space_usage;
-  uint32_t indices_key;
-  int should_add_elem;
-
-  GPR_ASSERT(GPR_SLICE_LENGTH(elem->key->slice) > 0);
-  if (GPR_SLICE_START_PTR(elem->key->slice)[0] != ':') { /* regular header */
-    st->seen_regular_header = 1;
-  } else {
-    GPR_ASSERT(
-        st->seen_regular_header == 0 &&
-        "Reserved header (colon-prefixed) happening after regular ones.");
-  }
-
-  inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems);
-
-  /* is this elem currently in the decoders table? */
-
-  if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem &&
-      c->indices_elems[HASH_FRAGMENT_2(elem_hash)] > c->tail_remote_index) {
-    /* HIT: complete element (first cuckoo hash) */
-    emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
-                 st);
-    return;
-  }
-
-  if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem &&
-      c->indices_elems[HASH_FRAGMENT_3(elem_hash)] > c->tail_remote_index) {
-    /* HIT: complete element (second cuckoo hash) */
-    emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
-                 st);
-    return;
-  }
-
-  /* should this elem be in the table? */
-  decoder_space_usage = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
-                        GPR_SLICE_LENGTH(elem->value->slice);
-  should_add_elem = decoder_space_usage < MAX_DECODER_SPACE_USAGE &&
-                    c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
-                        c->filter_elems_sum / ONE_ON_ADD_PROBABILITY;
-
-  /* no hits for the elem... maybe there's a key? */
-
-  indices_key = c->indices_keys[HASH_FRAGMENT_2(key_hash)];
-  if (c->entries_keys[HASH_FRAGMENT_2(key_hash)] == elem->key &&
-      indices_key > c->tail_remote_index) {
-    /* HIT: key (first cuckoo hash) */
-    if (should_add_elem) {
-      emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
-      add_elem(c, elem);
-      return;
-    } else {
-      emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
-      return;
-    }
-    GPR_UNREACHABLE_CODE(return );
-  }
-
-  indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
-  if (c->entries_keys[HASH_FRAGMENT_3(key_hash)] == elem->key &&
-      indices_key > c->tail_remote_index) {
-    /* HIT: key (first cuckoo hash) */
-    if (should_add_elem) {
-      emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
-      add_elem(c, elem);
-      return;
-    } else {
-      emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
-      return;
-    }
-    GPR_UNREACHABLE_CODE(return );
-  }
-
-  /* no elem, key in the table... fall back to literal emission */
-
-  if (should_add_elem) {
-    emit_lithdr_incidx_v(c, elem, st);
-    add_elem(c, elem);
-    return;
-  } else {
-    emit_lithdr_noidx_v(c, elem, st);
-    return;
-  }
-  GPR_UNREACHABLE_CODE(return );
-}
-
-#define STRLEN_LIT(x) (sizeof(x) - 1)
-#define TIMEOUT_KEY "grpc-timeout"
-
-static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
-                         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(deadline.clock_type)), timeout_str);
-  mdelem = grpc_mdelem_from_metadata_strings(
-      GRPC_MDSTR_GRPC_TIMEOUT, grpc_mdstr_from_string(timeout_str));
-  hpack_enc(c, mdelem, st);
-  GRPC_MDELEM_UNREF(mdelem);
-}
-
-static uint32_t elems_for_bytes(uint32_t bytes) { return (bytes + 31) / 32; }
-
-void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c) {
-  memset(c, 0, sizeof(*c));
-  c->max_table_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
-  c->cap_table_elems = elems_for_bytes(c->max_table_size);
-  c->max_table_elems = c->cap_table_elems;
-  c->max_usable_size = GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE;
-  c->table_elem_size =
-      gpr_malloc(sizeof(*c->table_elem_size) * c->cap_table_elems);
-  memset(c->table_elem_size, 0,
-         sizeof(*c->table_elem_size) * c->cap_table_elems);
-}
-
-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]);
-  }
-  gpr_free(c->table_elem_size);
-}
-
-void grpc_chttp2_hpack_compressor_set_max_usable_size(
-    grpc_chttp2_hpack_compressor *c, uint32_t max_table_size) {
-  c->max_usable_size = max_table_size;
-  grpc_chttp2_hpack_compressor_set_max_table_size(
-      c, GPR_MIN(c->max_table_size, max_table_size));
-}
-
-static void rebuild_elems(grpc_chttp2_hpack_compressor *c, uint32_t new_cap) {
-  uint16_t *table_elem_size = gpr_malloc(sizeof(*table_elem_size) * new_cap);
-  uint32_t i;
-
-  memset(table_elem_size, 0, sizeof(*table_elem_size) * new_cap);
-  GPR_ASSERT(c->table_elems <= new_cap);
-
-  for (i = 0; i < c->table_elems; i++) {
-    uint32_t ofs = c->tail_remote_index + i + 1;
-    table_elem_size[ofs % new_cap] =
-        c->table_elem_size[ofs % c->cap_table_elems];
-  }
-
-  c->cap_table_elems = new_cap;
-  gpr_free(c->table_elem_size);
-  c->table_elem_size = table_elem_size;
-}
-
-void grpc_chttp2_hpack_compressor_set_max_table_size(
-    grpc_chttp2_hpack_compressor *c, uint32_t max_table_size) {
-  max_table_size = GPR_MIN(max_table_size, c->max_usable_size);
-  if (max_table_size == c->max_table_size) {
-    return;
-  }
-  while (c->table_size > 0 && c->table_size > max_table_size) {
-    evict_entry(c);
-  }
-  c->max_table_size = max_table_size;
-  c->max_table_elems = elems_for_bytes(max_table_size);
-  if (c->max_table_elems > c->cap_table_elems) {
-    rebuild_elems(c, GPR_MAX(c->max_table_elems, 2 * c->cap_table_elems));
-  } else if (c->max_table_elems < c->cap_table_elems / 3) {
-    uint32_t new_cap = GPR_MAX(c->max_table_elems, 16);
-    if (new_cap != c->cap_table_elems) {
-      rebuild_elems(c, new_cap);
-    }
-  }
-  c->advertise_table_size_change = 1;
-  gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size);
-}
-
-void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
-                               uint32_t stream_id,
-                               grpc_metadata_batch *metadata, int is_eof,
-                               gpr_slice_buffer *outbuf) {
-  framer_state st;
-  grpc_linked_mdelem *l;
-  gpr_timespec deadline;
-
-  GPR_ASSERT(stream_id != 0);
-
-  st.seen_regular_header = 0;
-  st.stream_id = stream_id;
-  st.output = outbuf;
-  st.is_first_frame = 1;
-
-  /* Encode a metadata batch; store the returned values, representing
-     a metadata element that needs to be unreffed back into the metadata
-     slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got
-     updated). After this loop, we'll do a batch unref of elements. */
-  begin_frame(&st);
-  if (c->advertise_table_size_change != 0) {
-    emit_advertise_table_size_change(c, &st);
-  }
-  grpc_metadata_batch_assert_ok(metadata);
-  for (l = metadata->list.head; l; l = l->next) {
-    hpack_enc(c, l->md, &st);
-  }
-  deadline = metadata->deadline;
-  if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) != 0) {
-    deadline_enc(c, deadline, &st);
-  }
-
-  finish_frame(&st, 1, is_eof);
-}
diff --git a/src/core/transport/chttp2/hpack_encoder.h b/src/core/transport/chttp2/hpack_encoder.h
deleted file mode 100644
index 19b5cb7..0000000
--- a/src/core/transport/chttp2/hpack_encoder.h
+++ /dev/null
@@ -1,95 +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_TRANSPORT_CHTTP2_HPACK_ENCODER_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_ENCODER_H
-
-#include "src/core/transport/chttp2/frame.h"
-#include "src/core/transport/metadata.h"
-#include "src/core/transport/metadata_batch.h"
-#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
-
-#define GRPC_CHTTP2_HPACKC_NUM_FILTERS 256
-#define GRPC_CHTTP2_HPACKC_NUM_VALUES 256
-/* initial table size, per spec */
-#define GRPC_CHTTP2_HPACKC_INITIAL_TABLE_SIZE 4096
-/* maximum table size we'll actually use */
-#define GRPC_CHTTP2_HPACKC_MAX_TABLE_SIZE (1024 * 1024)
-
-typedef struct {
-  uint32_t filter_elems_sum;
-  uint32_t max_table_size;
-  uint32_t max_table_elems;
-  uint32_t cap_table_elems;
-  /** if non-zero, advertise to the decoder that we'll start using a table
-      of this size */
-  uint8_t advertise_table_size_change;
-  /** maximum number of bytes we'll use for the decode table (to guard against
-      peers ooming us by setting decode table size high) */
-  uint32_t max_usable_size;
-  /* one before the lowest usable table index */
-  uint32_t tail_remote_index;
-  uint32_t table_size;
-  uint32_t table_elems;
-
-  /* filter tables for elems: this tables provides an approximate
-     popularity count for particular hashes, and are used to determine whether
-     a new literal should be added to the compression table or not.
-     They track a single integer that counts how often a particular value has
-     been seen. When that count reaches max (255), all values are halved. */
-  uint8_t filter_elems[GRPC_CHTTP2_HPACKC_NUM_FILTERS];
-
-  /* entry tables for keys & elems: these tables track values that have been
-     seen and *may* be in the decompressor table */
-  grpc_mdstr *entries_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
-  grpc_mdelem *entries_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
-  uint32_t indices_keys[GRPC_CHTTP2_HPACKC_NUM_VALUES];
-  uint32_t indices_elems[GRPC_CHTTP2_HPACKC_NUM_VALUES];
-
-  uint16_t *table_elem_size;
-} grpc_chttp2_hpack_compressor;
-
-void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c);
-void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c);
-void grpc_chttp2_hpack_compressor_set_max_table_size(
-    grpc_chttp2_hpack_compressor *c, uint32_t max_table_size);
-void grpc_chttp2_hpack_compressor_set_max_usable_size(
-    grpc_chttp2_hpack_compressor *c, uint32_t max_table_size);
-
-void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, uint32_t id,
-                               grpc_metadata_batch *metadata, int is_eof,
-                               gpr_slice_buffer *outbuf);
-
-#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_ENCODER_H */
diff --git a/src/core/transport/chttp2/hpack_parser.c b/src/core/transport/chttp2/hpack_parser.c
deleted file mode 100644
index a63c7db..0000000
--- a/src/core/transport/chttp2/hpack_parser.c
+++ /dev/null
@@ -1,1449 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/transport/chttp2/hpack_parser.h"
-#include "src/core/transport/chttp2/internal.h"
-
-#include <stddef.h>
-#include <string.h>
-#include <assert.h>
-
-/* This is here for grpc_is_binary_header
- * TODO(murgatroid99): Remove this
- */
-#include <grpc/grpc.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/profiling/timers.h"
-#include "src/core/support/string.h"
-#include "src/core/transport/chttp2/bin_encoder.h"
-
-typedef enum {
-  NOT_BINARY,
-  B64_BYTE0,
-  B64_BYTE1,
-  B64_BYTE2,
-  B64_BYTE3
-} binary_state;
-
-/* How parsing works:
-
-   The parser object keeps track of a function pointer which represents the
-   current parse state.
-
-   Each time new bytes are presented, we call into the current state, which
-   recursively parses until all bytes in the given chunk are exhausted.
-
-   The parse state that terminates then saves its function pointer to be the
-   current state so that it can resume when more bytes are available.
-
-   It's expected that most optimizing compilers will turn this code into
-   a set of indirect jumps, and so not waste stack space. */
-
-/* forward declarations for parsing states */
-static int parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                       const uint8_t *end);
-static int parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                       const uint8_t *end);
-static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                            const uint8_t *end);
-
-static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                               const uint8_t *end);
-static int parse_key_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                            const uint8_t *end);
-static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p,
-                                               const uint8_t *cur,
-                                               const uint8_t *end);
-static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p,
-                                               const uint8_t *cur,
-                                               const uint8_t *end);
-
-static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                        const uint8_t *end);
-static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                        const uint8_t *end);
-static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                        const uint8_t *end);
-static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                        const uint8_t *end);
-static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                        const uint8_t *end);
-static int parse_value5up(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                          const uint8_t *end);
-
-static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                               const uint8_t *end);
-static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                               const uint8_t *end);
-static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                               const uint8_t *end);
-static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                               const uint8_t *end);
-static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end);
-static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                              const uint8_t *end);
-static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                                const uint8_t *end);
-
-/* we translate the first byte of a hpack field into one of these decoding
-   cases, then use a lookup table to jump directly to the appropriate parser.
-
-   _X => the integer index is all ones, meaning we need to do varint decoding
-   _V => the integer index is all zeros, meaning we need to decode an additional
-         string value */
-typedef enum {
-  INDEXED_FIELD,
-  INDEXED_FIELD_X,
-  LITHDR_INCIDX,
-  LITHDR_INCIDX_X,
-  LITHDR_INCIDX_V,
-  LITHDR_NOTIDX,
-  LITHDR_NOTIDX_X,
-  LITHDR_NOTIDX_V,
-  LITHDR_NVRIDX,
-  LITHDR_NVRIDX_X,
-  LITHDR_NVRIDX_V,
-  MAX_TBL_SIZE,
-  MAX_TBL_SIZE_X,
-  ILLEGAL
-} first_byte_type;
-
-/* 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_max_tbl_size_x,  parse_illegal_op};
-
-/* indexes the first byte to a parse state function - generated by
-   gen_hpack_tables.c */
-static const uint8_t first_byte_lut[256] = {
-    LITHDR_NOTIDX_V, LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX,
-    LITHDR_NOTIDX,   LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX,
-    LITHDR_NOTIDX,   LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX,
-    LITHDR_NOTIDX,   LITHDR_NOTIDX, LITHDR_NOTIDX, LITHDR_NOTIDX_X,
-    LITHDR_NVRIDX_V, LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
-    LITHDR_NVRIDX,   LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
-    LITHDR_NVRIDX,   LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX,
-    LITHDR_NVRIDX,   LITHDR_NVRIDX, LITHDR_NVRIDX, LITHDR_NVRIDX_X,
-    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
-    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
-    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
-    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
-    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
-    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
-    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE,
-    MAX_TBL_SIZE,    MAX_TBL_SIZE,  MAX_TBL_SIZE,  MAX_TBL_SIZE_X,
-    LITHDR_INCIDX_V, LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX,
-    LITHDR_INCIDX,   LITHDR_INCIDX, LITHDR_INCIDX, LITHDR_INCIDX_X,
-    ILLEGAL,         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,   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,   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,   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,   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,   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,   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,   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,
-};
-
-/* 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
-   considered returns the next state.
-
-   generated by gen_hpack_tables.c */
-static const uint8_t next_tbl[256] = {
-    0,  1,  2,  3,  4,  1,  2, 5,  6,  1, 7,  8,  1,  3,  3,  9,  10, 11, 1,  1,
-    1,  12, 1,  2,  13, 1,  1, 1,  1,  1, 1,  1,  1,  1,  1,  1,  1,  1,  1,  2,
-    14, 1,  15, 16, 1,  17, 1, 15, 2,  7, 3,  18, 19, 1,  1,  1,  1,  20, 1,  1,
-    1,  1,  1,  1,  1,  1,  1, 1,  15, 2, 2,  7,  21, 1,  22, 1,  1,  1,  1,  1,
-    1,  1,  1,  15, 2,  2,  2, 2,  2,  2, 23, 24, 25, 1,  1,  1,  1,  2,  2,  2,
-    26, 3,  3,  27, 10, 28, 1, 1,  1,  1, 1,  1,  2,  3,  29, 10, 30, 1,  1,  1,
-    1,  1,  1,  1,  1,  1,  1, 1,  1,  1, 1,  31, 1,  1,  1,  1,  1,  1,  1,  2,
-    2,  2,  2,  2,  2,  2,  2, 32, 1,  1, 15, 33, 1,  34, 35, 9,  36, 1,  1,  1,
-    1,  1,  1,  1,  37, 1,  1, 1,  1,  1, 1,  2,  2,  2,  2,  2,  2,  2,  26, 9,
-    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,
-};
-
-/* next state, based upon current state and the current nibble: see above.
-   generated by gen_hpack_tables.c */
-static const int16_t next_sub_tbl[48 * 16] = {
-    1,   204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217,
-    218, 2,   6,   10,  13,  14,  15,  16,  17,  2,   6,   10,  13,  14,  15,
-    16,  17,  3,   7,   11,  24,  3,   7,   11,  24,  3,   7,   11,  24,  3,
-    7,   11,  24,  4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,
-    4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   5,
-    199, 200, 201, 202, 203, 4,   8,   4,   8,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   9,   133, 134, 135, 136, 137, 138, 139, 140,
-    141, 142, 143, 144, 145, 146, 147, 3,   7,   11,  24,  3,   7,   11,  24,
-    4,   8,   4,   8,   4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   12,  132, 4,   8,   4,   8,   4,   8,
-    4,   8,   4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   18,  19,  20,  21,  4,   8,   4,
-    8,   4,   8,   4,   8,   4,   8,   0,   0,   0,   22,  23,  91,  25,  26,
-    27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  3,
-    7,   11,  24,  3,   7,   11,  24,  0,   0,   0,   0,   0,   41,  42,  43,
-    2,   6,   10,  13,  14,  15,  16,  17,  3,   7,   11,  24,  3,   7,   11,
-    24,  4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   0,   0,
-    44,  45,  2,   6,   10,  13,  14,  15,  16,  17,  46,  47,  48,  49,  50,
-    51,  52,  57,  4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   53,  54,  55,  56,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,
-    68,  69,  70,  71,  72,  74,  0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   73,  75,  76,  77,  78,  79,  80,  81,  82,
-    83,  84,  85,  86,  87,  88,  89,  90,  3,   7,   11,  24,  3,   7,   11,
-    24,  3,   7,   11,  24,  0,   0,   0,   0,   3,   7,   11,  24,  3,   7,
-    11,  24,  4,   8,   4,   8,   0,   0,   0,   92,  0,   0,   0,   93,  94,
-    95,  96,  97,  98,  99,  100, 101, 102, 103, 104, 105, 3,   7,   11,  24,
-    4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,
-    8,   4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 4,
-    8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   0,   0,
-    0,   117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
-    131, 2,   6,   10,  13,  14,  15,  16,  17,  4,   8,   4,   8,   4,   8,
-    4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   4,   8,   148,
-    149, 150, 151, 3,   7,   11,  24,  4,   8,   4,   8,   0,   0,   0,   0,
-    0,   0,   152, 153, 3,   7,   11,  24,  3,   7,   11,  24,  3,   7,   11,
-    24,  154, 155, 156, 164, 3,   7,   11,  24,  3,   7,   11,  24,  3,   7,
-    11,  24,  4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    157, 158, 159, 160, 161, 162, 163, 165, 166, 167, 168, 169, 170, 171, 172,
-    173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187,
-    188, 189, 190, 191, 192, 193, 194, 195, 196, 4,   8,   4,   8,   4,   8,
-    4,   8,   4,   8,   4,   8,   4,   8,   197, 198, 4,   8,   4,   8,   4,
-    8,   4,   8,   0,   0,   0,   0,   0,   0,   219, 220, 3,   7,   11,  24,
-    4,   8,   4,   8,   4,   8,   0,   0,   221, 222, 223, 224, 3,   7,   11,
-    24,  3,   7,   11,  24,  4,   8,   4,   8,   4,   8,   225, 228, 4,   8,
-    4,   8,   4,   8,   0,   0,   0,   0,   0,   0,   0,   0,   226, 227, 229,
-    230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244,
-    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,
-};
-
-/* emission table: indexed like next_tbl, ultimately gives the byte to be
-   emitted, or -1 for no byte, or 256 for end of stream
-
-   generated by gen_hpack_tables.c */
-static const uint16_t emit_tbl[256] = {
-    0,   1,   2,   3,   4,   5,   6,   7,   0,   8,   9,   10,  11,  12,  13,
-    14,  15,  16,  17,  18,  19,  20,  21,  22,  0,   23,  24,  25,  26,  27,
-    28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,
-    43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  0,   55,  56,
-    57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  0,
-    71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,
-    86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99,  100,
-    101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
-    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
-    131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145,
-    146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 0,
-    160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
-    0,   175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
-    189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
-    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,
-};
-
-/* generated by gen_hpack_tables.c */
-static const int16_t emit_sub_tbl[249 * 16] = {
-    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
-    -1,  48,  48,  48,  48,  48,  48,  48,  48,  49,  49,  49,  49,  49,  49,
-    49,  49,  48,  48,  48,  48,  49,  49,  49,  49,  50,  50,  50,  50,  97,
-    97,  97,  97,  48,  48,  49,  49,  50,  50,  97,  97,  99,  99,  101, 101,
-    105, 105, 111, 111, 48,  49,  50,  97,  99,  101, 105, 111, 115, 116, -1,
-    -1,  -1,  -1,  -1,  -1,  32,  32,  32,  32,  32,  32,  32,  32,  37,  37,
-    37,  37,  37,  37,  37,  37,  99,  99,  99,  99,  101, 101, 101, 101, 105,
-    105, 105, 105, 111, 111, 111, 111, 115, 115, 116, 116, 32,  37,  45,  46,
-    47,  51,  52,  53,  54,  55,  56,  57,  61,  61,  61,  61,  61,  61,  61,
-    61,  65,  65,  65,  65,  65,  65,  65,  65,  115, 115, 115, 115, 116, 116,
-    116, 116, 32,  32,  37,  37,  45,  45,  46,  46,  61,  65,  95,  98,  100,
-    102, 103, 104, 108, 109, 110, 112, 114, 117, -1,  -1,  58,  58,  58,  58,
-    58,  58,  58,  58,  66,  66,  66,  66,  66,  66,  66,  66,  47,  47,  51,
-    51,  52,  52,  53,  53,  54,  54,  55,  55,  56,  56,  57,  57,  61,  61,
-    65,  65,  95,  95,  98,  98,  100, 100, 102, 102, 103, 103, 104, 104, 108,
-    108, 109, 109, 110, 110, 112, 112, 114, 114, 117, 117, 58,  66,  67,  68,
-    69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,
-    84,  85,  86,  87,  89,  106, 107, 113, 118, 119, 120, 121, 122, -1,  -1,
-    -1,  -1,  38,  38,  38,  38,  38,  38,  38,  38,  42,  42,  42,  42,  42,
-    42,  42,  42,  44,  44,  44,  44,  44,  44,  44,  44,  59,  59,  59,  59,
-    59,  59,  59,  59,  88,  88,  88,  88,  88,  88,  88,  88,  90,  90,  90,
-    90,  90,  90,  90,  90,  33,  33,  34,  34,  40,  40,  41,  41,  63,  63,
-    39,  43,  124, -1,  -1,  -1,  35,  35,  35,  35,  35,  35,  35,  35,  62,
-    62,  62,  62,  62,  62,  62,  62,  0,   0,   0,   0,   36,  36,  36,  36,
-    64,  64,  64,  64,  91,  91,  91,  91,  69,  69,  69,  69,  69,  69,  69,
-    69,  70,  70,  70,  70,  70,  70,  70,  70,  71,  71,  71,  71,  71,  71,
-    71,  71,  72,  72,  72,  72,  72,  72,  72,  72,  73,  73,  73,  73,  73,
-    73,  73,  73,  74,  74,  74,  74,  74,  74,  74,  74,  75,  75,  75,  75,
-    75,  75,  75,  75,  76,  76,  76,  76,  76,  76,  76,  76,  77,  77,  77,
-    77,  77,  77,  77,  77,  78,  78,  78,  78,  78,  78,  78,  78,  79,  79,
-    79,  79,  79,  79,  79,  79,  80,  80,  80,  80,  80,  80,  80,  80,  81,
-    81,  81,  81,  81,  81,  81,  81,  82,  82,  82,  82,  82,  82,  82,  82,
-    83,  83,  83,  83,  83,  83,  83,  83,  84,  84,  84,  84,  84,  84,  84,
-    84,  85,  85,  85,  85,  85,  85,  85,  85,  86,  86,  86,  86,  86,  86,
-    86,  86,  87,  87,  87,  87,  87,  87,  87,  87,  89,  89,  89,  89,  89,
-    89,  89,  89,  106, 106, 106, 106, 106, 106, 106, 106, 107, 107, 107, 107,
-    107, 107, 107, 107, 113, 113, 113, 113, 113, 113, 113, 113, 118, 118, 118,
-    118, 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, 120, 120,
-    120, 120, 120, 120, 120, 120, 121, 121, 121, 121, 121, 121, 121, 121, 122,
-    122, 122, 122, 122, 122, 122, 122, 38,  38,  38,  38,  42,  42,  42,  42,
-    44,  44,  44,  44,  59,  59,  59,  59,  88,  88,  88,  88,  90,  90,  90,
-    90,  33,  34,  40,  41,  63,  -1,  -1,  -1,  39,  39,  39,  39,  39,  39,
-    39,  39,  43,  43,  43,  43,  43,  43,  43,  43,  124, 124, 124, 124, 124,
-    124, 124, 124, 35,  35,  35,  35,  62,  62,  62,  62,  0,   0,   36,  36,
-    64,  64,  91,  91,  93,  93,  126, 126, 94,  125, -1,  -1,  60,  60,  60,
-    60,  60,  60,  60,  60,  96,  96,  96,  96,  96,  96,  96,  96,  123, 123,
-    123, 123, 123, 123, 123, 123, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  92,
-    92,  92,  92,  92,  92,  92,  92,  195, 195, 195, 195, 195, 195, 195, 195,
-    208, 208, 208, 208, 208, 208, 208, 208, 128, 128, 128, 128, 130, 130, 130,
-    130, 131, 131, 131, 131, 162, 162, 162, 162, 184, 184, 184, 184, 194, 194,
-    194, 194, 224, 224, 224, 224, 226, 226, 226, 226, 153, 153, 161, 161, 167,
-    167, 172, 172, 176, 176, 177, 177, 179, 179, 209, 209, 216, 216, 217, 217,
-    227, 227, 229, 229, 230, 230, 129, 132, 133, 134, 136, 146, 154, 156, 160,
-    163, 164, 169, 170, 173, 178, 181, 185, 186, 187, 189, 190, 196, 198, 228,
-    232, 233, -1,  -1,  -1,  -1,  1,   1,   1,   1,   1,   1,   1,   1,   135,
-    135, 135, 135, 135, 135, 135, 135, 137, 137, 137, 137, 137, 137, 137, 137,
-    138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139, 139, 139, 139,
-    139, 140, 140, 140, 140, 140, 140, 140, 140, 141, 141, 141, 141, 141, 141,
-    141, 141, 143, 143, 143, 143, 143, 143, 143, 143, 147, 147, 147, 147, 147,
-    147, 147, 147, 149, 149, 149, 149, 149, 149, 149, 149, 150, 150, 150, 150,
-    150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 151, 151, 152, 152, 152,
-    152, 152, 152, 152, 152, 155, 155, 155, 155, 155, 155, 155, 155, 157, 157,
-    157, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158, 158, 158, 158, 165,
-    165, 165, 165, 165, 165, 165, 165, 166, 166, 166, 166, 166, 166, 166, 166,
-    168, 168, 168, 168, 168, 168, 168, 168, 174, 174, 174, 174, 174, 174, 174,
-    174, 175, 175, 175, 175, 175, 175, 175, 175, 180, 180, 180, 180, 180, 180,
-    180, 180, 182, 182, 182, 182, 182, 182, 182, 182, 183, 183, 183, 183, 183,
-    183, 183, 183, 188, 188, 188, 188, 188, 188, 188, 188, 191, 191, 191, 191,
-    191, 191, 191, 191, 197, 197, 197, 197, 197, 197, 197, 197, 231, 231, 231,
-    231, 231, 231, 231, 231, 239, 239, 239, 239, 239, 239, 239, 239, 9,   9,
-    9,   9,   142, 142, 142, 142, 144, 144, 144, 144, 145, 145, 145, 145, 148,
-    148, 148, 148, 159, 159, 159, 159, 171, 171, 171, 171, 206, 206, 206, 206,
-    215, 215, 215, 215, 225, 225, 225, 225, 236, 236, 236, 236, 237, 237, 237,
-    237, 199, 199, 207, 207, 234, 234, 235, 235, 192, 193, 200, 201, 202, 205,
-    210, 213, 218, 219, 238, 240, 242, 243, 255, -1,  203, 203, 203, 203, 203,
-    203, 203, 203, 204, 204, 204, 204, 204, 204, 204, 204, 211, 211, 211, 211,
-    211, 211, 211, 211, 212, 212, 212, 212, 212, 212, 212, 212, 214, 214, 214,
-    214, 214, 214, 214, 214, 221, 221, 221, 221, 221, 221, 221, 221, 222, 222,
-    222, 222, 222, 222, 222, 222, 223, 223, 223, 223, 223, 223, 223, 223, 241,
-    241, 241, 241, 241, 241, 241, 241, 244, 244, 244, 244, 244, 244, 244, 244,
-    245, 245, 245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246,
-    246, 247, 247, 247, 247, 247, 247, 247, 247, 248, 248, 248, 248, 248, 248,
-    248, 248, 250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251,
-    251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253,
-    253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 2,   2,   2,
-    2,   3,   3,   3,   3,   4,   4,   4,   4,   5,   5,   5,   5,   6,   6,
-    6,   6,   7,   7,   7,   7,   8,   8,   8,   8,   11,  11,  11,  11,  12,
-    12,  12,  12,  14,  14,  14,  14,  15,  15,  15,  15,  16,  16,  16,  16,
-    17,  17,  17,  17,  18,  18,  18,  18,  19,  19,  19,  19,  20,  20,  20,
-    20,  21,  21,  21,  21,  23,  23,  23,  23,  24,  24,  24,  24,  25,  25,
-    25,  25,  26,  26,  26,  26,  27,  27,  27,  27,  28,  28,  28,  28,  29,
-    29,  29,  29,  30,  30,  30,  30,  31,  31,  31,  31,  127, 127, 127, 127,
-    220, 220, 220, 220, 249, 249, 249, 249, 10,  13,  22,  256, 93,  93,  93,
-    93,  126, 126, 126, 126, 94,  94,  125, 125, 60,  96,  123, -1,  92,  195,
-    208, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  128,
-    128, 128, 128, 128, 128, 128, 128, 130, 130, 130, 130, 130, 130, 130, 130,
-    131, 131, 131, 131, 131, 131, 131, 131, 162, 162, 162, 162, 162, 162, 162,
-    162, 184, 184, 184, 184, 184, 184, 184, 184, 194, 194, 194, 194, 194, 194,
-    194, 194, 224, 224, 224, 224, 224, 224, 224, 224, 226, 226, 226, 226, 226,
-    226, 226, 226, 153, 153, 153, 153, 161, 161, 161, 161, 167, 167, 167, 167,
-    172, 172, 172, 172, 176, 176, 176, 176, 177, 177, 177, 177, 179, 179, 179,
-    179, 209, 209, 209, 209, 216, 216, 216, 216, 217, 217, 217, 217, 227, 227,
-    227, 227, 229, 229, 229, 229, 230, 230, 230, 230, 129, 129, 132, 132, 133,
-    133, 134, 134, 136, 136, 146, 146, 154, 154, 156, 156, 160, 160, 163, 163,
-    164, 164, 169, 169, 170, 170, 173, 173, 178, 178, 181, 181, 185, 185, 186,
-    186, 187, 187, 189, 189, 190, 190, 196, 196, 198, 198, 228, 228, 232, 232,
-    233, 233, 1,   135, 137, 138, 139, 140, 141, 143, 147, 149, 150, 151, 152,
-    155, 157, 158, 165, 166, 168, 174, 175, 180, 182, 183, 188, 191, 197, 231,
-    239, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  9,   9,   9,
-    9,   9,   9,   9,   9,   142, 142, 142, 142, 142, 142, 142, 142, 144, 144,
-    144, 144, 144, 144, 144, 144, 145, 145, 145, 145, 145, 145, 145, 145, 148,
-    148, 148, 148, 148, 148, 148, 148, 159, 159, 159, 159, 159, 159, 159, 159,
-    171, 171, 171, 171, 171, 171, 171, 171, 206, 206, 206, 206, 206, 206, 206,
-    206, 215, 215, 215, 215, 215, 215, 215, 215, 225, 225, 225, 225, 225, 225,
-    225, 225, 236, 236, 236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 237,
-    237, 237, 237, 199, 199, 199, 199, 207, 207, 207, 207, 234, 234, 234, 234,
-    235, 235, 235, 235, 192, 192, 193, 193, 200, 200, 201, 201, 202, 202, 205,
-    205, 210, 210, 213, 213, 218, 218, 219, 219, 238, 238, 240, 240, 242, 242,
-    243, 243, 255, 255, 203, 204, 211, 212, 214, 221, 222, 223, 241, 244, 245,
-    246, 247, 248, 250, 251, 252, 253, 254, -1,  -1,  -1,  -1,  -1,  -1,  -1,
-    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  2,   2,   2,   2,   2,   2,   2,
-    2,   3,   3,   3,   3,   3,   3,   3,   3,   4,   4,   4,   4,   4,   4,
-    4,   4,   5,   5,   5,   5,   5,   5,   5,   5,   6,   6,   6,   6,   6,
-    6,   6,   6,   7,   7,   7,   7,   7,   7,   7,   7,   8,   8,   8,   8,
-    8,   8,   8,   8,   11,  11,  11,  11,  11,  11,  11,  11,  12,  12,  12,
-    12,  12,  12,  12,  12,  14,  14,  14,  14,  14,  14,  14,  14,  15,  15,
-    15,  15,  15,  15,  15,  15,  16,  16,  16,  16,  16,  16,  16,  16,  17,
-    17,  17,  17,  17,  17,  17,  17,  18,  18,  18,  18,  18,  18,  18,  18,
-    19,  19,  19,  19,  19,  19,  19,  19,  20,  20,  20,  20,  20,  20,  20,
-    20,  21,  21,  21,  21,  21,  21,  21,  21,  23,  23,  23,  23,  23,  23,
-    23,  23,  24,  24,  24,  24,  24,  24,  24,  24,  25,  25,  25,  25,  25,
-    25,  25,  25,  26,  26,  26,  26,  26,  26,  26,  26,  27,  27,  27,  27,
-    27,  27,  27,  27,  28,  28,  28,  28,  28,  28,  28,  28,  29,  29,  29,
-    29,  29,  29,  29,  29,  30,  30,  30,  30,  30,  30,  30,  30,  31,  31,
-    31,  31,  31,  31,  31,  31,  127, 127, 127, 127, 127, 127, 127, 127, 220,
-    220, 220, 220, 220, 220, 220, 220, 249, 249, 249, 249, 249, 249, 249, 249,
-    10,  10,  13,  13,  22,  22,  256, 256, 67,  67,  67,  67,  67,  67,  67,
-    67,  68,  68,  68,  68,  68,  68,  68,  68,  95,  95,  95,  95,  95,  95,
-    95,  95,  98,  98,  98,  98,  98,  98,  98,  98,  100, 100, 100, 100, 100,
-    100, 100, 100, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103,
-    103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 108, 108, 108,
-    108, 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, 109, 109, 110, 110,
-    110, 110, 110, 110, 110, 110, 112, 112, 112, 112, 112, 112, 112, 112, 114,
-    114, 114, 114, 114, 114, 114, 114, 117, 117, 117, 117, 117, 117, 117, 117,
-    58,  58,  58,  58,  66,  66,  66,  66,  67,  67,  67,  67,  68,  68,  68,
-    68,  69,  69,  69,  69,  70,  70,  70,  70,  71,  71,  71,  71,  72,  72,
-    72,  72,  73,  73,  73,  73,  74,  74,  74,  74,  75,  75,  75,  75,  76,
-    76,  76,  76,  77,  77,  77,  77,  78,  78,  78,  78,  79,  79,  79,  79,
-    80,  80,  80,  80,  81,  81,  81,  81,  82,  82,  82,  82,  83,  83,  83,
-    83,  84,  84,  84,  84,  85,  85,  85,  85,  86,  86,  86,  86,  87,  87,
-    87,  87,  89,  89,  89,  89,  106, 106, 106, 106, 107, 107, 107, 107, 113,
-    113, 113, 113, 118, 118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 120,
-    121, 121, 121, 121, 122, 122, 122, 122, 38,  38,  42,  42,  44,  44,  59,
-    59,  88,  88,  90,  90,  -1,  -1,  -1,  -1,  33,  33,  33,  33,  33,  33,
-    33,  33,  34,  34,  34,  34,  34,  34,  34,  34,  40,  40,  40,  40,  40,
-    40,  40,  40,  41,  41,  41,  41,  41,  41,  41,  41,  63,  63,  63,  63,
-    63,  63,  63,  63,  39,  39,  39,  39,  43,  43,  43,  43,  124, 124, 124,
-    124, 35,  35,  62,  62,  0,   36,  64,  91,  93,  126, -1,  -1,  94,  94,
-    94,  94,  94,  94,  94,  94,  125, 125, 125, 125, 125, 125, 125, 125, 60,
-    60,  60,  60,  96,  96,  96,  96,  123, 123, 123, 123, -1,  -1,  -1,  -1,
-    92,  92,  92,  92,  195, 195, 195, 195, 208, 208, 208, 208, 128, 128, 130,
-    130, 131, 131, 162, 162, 184, 184, 194, 194, 224, 224, 226, 226, 153, 161,
-    167, 172, 176, 177, 179, 209, 216, 217, 227, 229, 230, -1,  -1,  -1,  -1,
-    -1,  -1,  -1,  129, 129, 129, 129, 129, 129, 129, 129, 132, 132, 132, 132,
-    132, 132, 132, 132, 133, 133, 133, 133, 133, 133, 133, 133, 134, 134, 134,
-    134, 134, 134, 134, 134, 136, 136, 136, 136, 136, 136, 136, 136, 146, 146,
-    146, 146, 146, 146, 146, 146, 154, 154, 154, 154, 154, 154, 154, 154, 156,
-    156, 156, 156, 156, 156, 156, 156, 160, 160, 160, 160, 160, 160, 160, 160,
-    163, 163, 163, 163, 163, 163, 163, 163, 164, 164, 164, 164, 164, 164, 164,
-    164, 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170,
-    170, 170, 173, 173, 173, 173, 173, 173, 173, 173, 178, 178, 178, 178, 178,
-    178, 178, 178, 181, 181, 181, 181, 181, 181, 181, 181, 185, 185, 185, 185,
-    185, 185, 185, 185, 186, 186, 186, 186, 186, 186, 186, 186, 187, 187, 187,
-    187, 187, 187, 187, 187, 189, 189, 189, 189, 189, 189, 189, 189, 190, 190,
-    190, 190, 190, 190, 190, 190, 196, 196, 196, 196, 196, 196, 196, 196, 198,
-    198, 198, 198, 198, 198, 198, 198, 228, 228, 228, 228, 228, 228, 228, 228,
-    232, 232, 232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 233, 233, 233,
-    233, 1,   1,   1,   1,   135, 135, 135, 135, 137, 137, 137, 137, 138, 138,
-    138, 138, 139, 139, 139, 139, 140, 140, 140, 140, 141, 141, 141, 141, 143,
-    143, 143, 143, 147, 147, 147, 147, 149, 149, 149, 149, 150, 150, 150, 150,
-    151, 151, 151, 151, 152, 152, 152, 152, 155, 155, 155, 155, 157, 157, 157,
-    157, 158, 158, 158, 158, 165, 165, 165, 165, 166, 166, 166, 166, 168, 168,
-    168, 168, 174, 174, 174, 174, 175, 175, 175, 175, 180, 180, 180, 180, 182,
-    182, 182, 182, 183, 183, 183, 183, 188, 188, 188, 188, 191, 191, 191, 191,
-    197, 197, 197, 197, 231, 231, 231, 231, 239, 239, 239, 239, 9,   9,   142,
-    142, 144, 144, 145, 145, 148, 148, 159, 159, 171, 171, 206, 206, 215, 215,
-    225, 225, 236, 236, 237, 237, 199, 207, 234, 235, 192, 192, 192, 192, 192,
-    192, 192, 192, 193, 193, 193, 193, 193, 193, 193, 193, 200, 200, 200, 200,
-    200, 200, 200, 200, 201, 201, 201, 201, 201, 201, 201, 201, 202, 202, 202,
-    202, 202, 202, 202, 202, 205, 205, 205, 205, 205, 205, 205, 205, 210, 210,
-    210, 210, 210, 210, 210, 210, 213, 213, 213, 213, 213, 213, 213, 213, 218,
-    218, 218, 218, 218, 218, 218, 218, 219, 219, 219, 219, 219, 219, 219, 219,
-    238, 238, 238, 238, 238, 238, 238, 238, 240, 240, 240, 240, 240, 240, 240,
-    240, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243, 243, 243,
-    243, 243, 255, 255, 255, 255, 255, 255, 255, 255, 203, 203, 203, 203, 204,
-    204, 204, 204, 211, 211, 211, 211, 212, 212, 212, 212, 214, 214, 214, 214,
-    221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 241, 241, 241,
-    241, 244, 244, 244, 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, 247,
-    247, 247, 248, 248, 248, 248, 250, 250, 250, 250, 251, 251, 251, 251, 252,
-    252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 2,   2,   3,   3,
-    4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   11,  11,  12,  12,  14,
-    14,  15,  15,  16,  16,  17,  17,  18,  18,  19,  19,  20,  20,  21,  21,
-    23,  23,  24,  24,  25,  25,  26,  26,  27,  27,  28,  28,  29,  29,  30,
-    30,  31,  31,  127, 127, 220, 220, 249, 249, -1,  -1,  10,  10,  10,  10,
-    10,  10,  10,  10,  13,  13,  13,  13,  13,  13,  13,  13,  22,  22,  22,
-    22,  22,  22,  22,  22,  256, 256, 256, 256, 256, 256, 256, 256, 45,  45,
-    45,  45,  45,  45,  45,  45,  46,  46,  46,  46,  46,  46,  46,  46,  47,
-    47,  47,  47,  47,  47,  47,  47,  51,  51,  51,  51,  51,  51,  51,  51,
-    52,  52,  52,  52,  52,  52,  52,  52,  53,  53,  53,  53,  53,  53,  53,
-    53,  54,  54,  54,  54,  54,  54,  54,  54,  55,  55,  55,  55,  55,  55,
-    55,  55,  56,  56,  56,  56,  56,  56,  56,  56,  57,  57,  57,  57,  57,
-    57,  57,  57,  50,  50,  50,  50,  50,  50,  50,  50,  97,  97,  97,  97,
-    97,  97,  97,  97,  99,  99,  99,  99,  99,  99,  99,  99,  101, 101, 101,
-    101, 101, 101, 101, 101, 105, 105, 105, 105, 105, 105, 105, 105, 111, 111,
-    111, 111, 111, 111, 111, 111, 115, 115, 115, 115, 115, 115, 115, 115, 116,
-    116, 116, 116, 116, 116, 116, 116, 32,  32,  32,  32,  37,  37,  37,  37,
-    45,  45,  45,  45,  46,  46,  46,  46,  47,  47,  47,  47,  51,  51,  51,
-    51,  52,  52,  52,  52,  53,  53,  53,  53,  54,  54,  54,  54,  55,  55,
-    55,  55,  56,  56,  56,  56,  57,  57,  57,  57,  61,  61,  61,  61,  65,
-    65,  65,  65,  95,  95,  95,  95,  98,  98,  98,  98,  100, 100, 100, 100,
-    102, 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 104, 108, 108, 108,
-    108, 109, 109, 109, 109, 110, 110, 110, 110, 112, 112, 112, 112, 114, 114,
-    114, 114, 117, 117, 117, 117, 58,  58,  66,  66,  67,  67,  68,  68,  69,
-    69,  70,  70,  71,  71,  72,  72,  73,  73,  74,  74,  75,  75,  76,  76,
-    77,  77,  78,  78,  79,  79,  80,  80,  81,  81,  82,  82,  83,  83,  84,
-    84,  85,  85,  86,  86,  87,  87,  89,  89,  106, 106, 107, 107, 113, 113,
-    118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 38,  42,  44,  59,  88,
-    90,  -1,  -1,  33,  33,  33,  33,  34,  34,  34,  34,  40,  40,  40,  40,
-    41,  41,  41,  41,  63,  63,  63,  63,  39,  39,  43,  43,  124, 124, 35,
-    62,  -1,  -1,  -1,  -1,  0,   0,   0,   0,   0,   0,   0,   0,   36,  36,
-    36,  36,  36,  36,  36,  36,  64,  64,  64,  64,  64,  64,  64,  64,  91,
-    91,  91,  91,  91,  91,  91,  91,  93,  93,  93,  93,  93,  93,  93,  93,
-    126, 126, 126, 126, 126, 126, 126, 126, 94,  94,  94,  94,  125, 125, 125,
-    125, 60,  60,  96,  96,  123, 123, -1,  -1,  92,  92,  195, 195, 208, 208,
-    128, 130, 131, 162, 184, 194, 224, 226, -1,  -1,  153, 153, 153, 153, 153,
-    153, 153, 153, 161, 161, 161, 161, 161, 161, 161, 161, 167, 167, 167, 167,
-    167, 167, 167, 167, 172, 172, 172, 172, 172, 172, 172, 172, 176, 176, 176,
-    176, 176, 176, 176, 176, 177, 177, 177, 177, 177, 177, 177, 177, 179, 179,
-    179, 179, 179, 179, 179, 179, 209, 209, 209, 209, 209, 209, 209, 209, 216,
-    216, 216, 216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217, 217, 217,
-    227, 227, 227, 227, 227, 227, 227, 227, 229, 229, 229, 229, 229, 229, 229,
-    229, 230, 230, 230, 230, 230, 230, 230, 230, 129, 129, 129, 129, 132, 132,
-    132, 132, 133, 133, 133, 133, 134, 134, 134, 134, 136, 136, 136, 136, 146,
-    146, 146, 146, 154, 154, 154, 154, 156, 156, 156, 156, 160, 160, 160, 160,
-    163, 163, 163, 163, 164, 164, 164, 164, 169, 169, 169, 169, 170, 170, 170,
-    170, 173, 173, 173, 173, 178, 178, 178, 178, 181, 181, 181, 181, 185, 185,
-    185, 185, 186, 186, 186, 186, 187, 187, 187, 187, 189, 189, 189, 189, 190,
-    190, 190, 190, 196, 196, 196, 196, 198, 198, 198, 198, 228, 228, 228, 228,
-    232, 232, 232, 232, 233, 233, 233, 233, 1,   1,   135, 135, 137, 137, 138,
-    138, 139, 139, 140, 140, 141, 141, 143, 143, 147, 147, 149, 149, 150, 150,
-    151, 151, 152, 152, 155, 155, 157, 157, 158, 158, 165, 165, 166, 166, 168,
-    168, 174, 174, 175, 175, 180, 180, 182, 182, 183, 183, 188, 188, 191, 191,
-    197, 197, 231, 231, 239, 239, 9,   142, 144, 145, 148, 159, 171, 206, 215,
-    225, 236, 237, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  199, 199,
-    199, 199, 199, 199, 199, 199, 207, 207, 207, 207, 207, 207, 207, 207, 234,
-    234, 234, 234, 234, 234, 234, 234, 235, 235, 235, 235, 235, 235, 235, 235,
-    192, 192, 192, 192, 193, 193, 193, 193, 200, 200, 200, 200, 201, 201, 201,
-    201, 202, 202, 202, 202, 205, 205, 205, 205, 210, 210, 210, 210, 213, 213,
-    213, 213, 218, 218, 218, 218, 219, 219, 219, 219, 238, 238, 238, 238, 240,
-    240, 240, 240, 242, 242, 242, 242, 243, 243, 243, 243, 255, 255, 255, 255,
-    203, 203, 204, 204, 211, 211, 212, 212, 214, 214, 221, 221, 222, 222, 223,
-    223, 241, 241, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 250, 250,
-    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,
-};
-
-static const uint8_t inverse_base64[256] = {
-    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, 62,  255,
-    255, 255, 63,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  255, 255,
-    255, 64,  255, 255, 255, 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
-    10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
-    25,  255, 255, 255, 255, 255, 255, 26,  27,  28,  29,  30,  31,  32,  33,
-    34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
-    49,  50,  51,  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, 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, 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 int on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
-                  int add_to_table) {
-  if (add_to_table) {
-    if (!grpc_chttp2_hptbl_add(&p->table, md)) {
-      return 0;
-    }
-  }
-  p->on_header(p->on_header_user_data, md);
-  return 1;
-}
-
-static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
-                               grpc_chttp2_hpack_parser_string *str) {
-  grpc_mdstr *s = grpc_mdstr_from_buffer((uint8_t *)str->str, str->length);
-  str->length = 0;
-  return s;
-}
-
-/* jump to the next state */
-static int parse_next(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                      const uint8_t *end) {
-  p->state = *p->next_state++;
-  return p->state(p, cur, end);
-}
-
-/* begin parsing a header: all functionality is encoded into lookup tables
-   above */
-static int parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                       const uint8_t *end) {
-  if (cur == end) {
-    p->state = parse_begin;
-    return 1;
-  }
-
-  return first_byte_action[first_byte_lut[*cur]](p, cur, end);
-}
-
-/* stream dependency and prioritization data: we just skip it */
-static int parse_stream_weight(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                               const uint8_t *end) {
-  if (cur == end) {
-    p->state = parse_stream_weight;
-    return 1;
-  }
-
-  return p->after_prioritization(p, cur + 1, end);
-}
-
-static int parse_stream_dep3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                             const uint8_t *end) {
-  if (cur == end) {
-    p->state = parse_stream_dep3;
-    return 1;
-  }
-
-  return parse_stream_weight(p, cur + 1, end);
-}
-
-static int parse_stream_dep2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                             const uint8_t *end) {
-  if (cur == end) {
-    p->state = parse_stream_dep2;
-    return 1;
-  }
-
-  return parse_stream_dep3(p, cur + 1, end);
-}
-
-static int parse_stream_dep1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                             const uint8_t *end) {
-  if (cur == end) {
-    p->state = parse_stream_dep1;
-    return 1;
-  }
-
-  return parse_stream_dep2(p, cur + 1, end);
-}
-
-static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                             const uint8_t *end) {
-  if (cur == end) {
-    p->state = parse_stream_dep0;
-    return 1;
-  }
-
-  return parse_stream_dep1(p, cur + 1, end);
-}
-
-/* emit an indexed field; for now just logs it to console; jumps to
-   begin the next field on completion */
-static int finish_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                                const uint8_t *end) {
-  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
-  if (md == NULL) {
-    gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
-    return 0;
-  }
-  GRPC_MDELEM_REF(md);
-  return on_hdr(p, md, 0) && parse_begin(p, cur, end);
-}
-
-/* parse an indexed field with index < 127 */
-static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                               const uint8_t *end) {
-  p->dynamic_table_update_allowed = 0;
-  p->index = (*cur) & 0x7f;
-  return finish_indexed_field(p, cur + 1, end);
-}
-
-/* parse an indexed field with index >= 127 */
-static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end) {
-  static const grpc_chttp2_hpack_parser_state and_then[] = {
-      finish_indexed_field};
-  p->dynamic_table_update_allowed = 0;
-  p->next_state = and_then;
-  p->index = 0x7f;
-  p->parsing.value = &p->index;
-  return parse_value0(p, cur + 1, end);
-}
-
-/* finish a literal header with incremental indexing: just log, and jump to '
-   begin */
-static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                                const uint8_t *end) {
-  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
-  GPR_ASSERT(md != NULL); /* handled in string parsing */
-  return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
-                                                     take_string(p, &p->value)),
-                1) &&
-         parse_begin(p, cur, end);
-}
-
-/* finish a literal header with incremental indexing with no index */
-static int finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
-                                  const uint8_t *cur, const uint8_t *end) {
-  return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
-                                                     take_string(p, &p->value)),
-                1) &&
-         parse_begin(p, cur, end);
-}
-
-/* parse a literal header with incremental indexing; index < 63 */
-static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                               const uint8_t *end) {
-  static const grpc_chttp2_hpack_parser_state and_then[] = {
-      parse_value_string_with_indexed_key, finish_lithdr_incidx};
-  p->dynamic_table_update_allowed = 0;
-  p->next_state = and_then;
-  p->index = (*cur) & 0x3f;
-  return parse_string_prefix(p, cur + 1, end);
-}
-
-/* parse a literal header with incremental indexing; index >= 63 */
-static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end) {
-  static const grpc_chttp2_hpack_parser_state and_then[] = {
-      parse_string_prefix, parse_value_string_with_indexed_key,
-      finish_lithdr_incidx};
-  p->dynamic_table_update_allowed = 0;
-  p->next_state = and_then;
-  p->index = 0x3f;
-  p->parsing.value = &p->index;
-  return parse_value0(p, cur + 1, end);
-}
-
-/* parse a literal header with incremental indexing; index = 0 */
-static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end) {
-  static const grpc_chttp2_hpack_parser_state and_then[] = {
-      parse_key_string, parse_string_prefix,
-      parse_value_string_with_literal_key, finish_lithdr_incidx_v};
-  p->dynamic_table_update_allowed = 0;
-  p->next_state = and_then;
-  return parse_string_prefix(p, cur + 1, end);
-}
-
-/* finish a literal header without incremental indexing */
-static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                                const uint8_t *end) {
-  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
-  GPR_ASSERT(md != NULL); /* handled in string parsing */
-  return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
-                                                     take_string(p, &p->value)),
-                0) &&
-         parse_begin(p, cur, end);
-}
-
-/* finish a literal header without incremental indexing with index = 0 */
-static int finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
-                                  const uint8_t *cur, const uint8_t *end) {
-  return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
-                                                     take_string(p, &p->value)),
-                0) &&
-         parse_begin(p, cur, end);
-}
-
-/* parse a literal header without incremental indexing; index < 15 */
-static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                               const uint8_t *end) {
-  static const grpc_chttp2_hpack_parser_state and_then[] = {
-      parse_value_string_with_indexed_key, finish_lithdr_notidx};
-  p->dynamic_table_update_allowed = 0;
-  p->next_state = and_then;
-  p->index = (*cur) & 0xf;
-  return parse_string_prefix(p, cur + 1, end);
-}
-
-/* parse a literal header without incremental indexing; index >= 15 */
-static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end) {
-  static const grpc_chttp2_hpack_parser_state and_then[] = {
-      parse_string_prefix, parse_value_string_with_indexed_key,
-      finish_lithdr_notidx};
-  p->dynamic_table_update_allowed = 0;
-  p->next_state = and_then;
-  p->index = 0xf;
-  p->parsing.value = &p->index;
-  return parse_value0(p, cur + 1, end);
-}
-
-/* parse a literal header without incremental indexing; index == 0 */
-static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end) {
-  static const grpc_chttp2_hpack_parser_state and_then[] = {
-      parse_key_string, parse_string_prefix,
-      parse_value_string_with_literal_key, finish_lithdr_notidx_v};
-  p->dynamic_table_update_allowed = 0;
-  p->next_state = and_then;
-  return parse_string_prefix(p, cur + 1, end);
-}
-
-/* finish a literal header that is never indexed */
-static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                                const uint8_t *end) {
-  grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
-  GPR_ASSERT(md != NULL); /* handled in string parsing */
-  return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
-                                                     take_string(p, &p->value)),
-                0) &&
-         parse_begin(p, cur, end);
-}
-
-/* finish a literal header that is never indexed with an extra value */
-static int finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
-                                  const uint8_t *cur, const uint8_t *end) {
-  return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
-                                                     take_string(p, &p->value)),
-                0) &&
-         parse_begin(p, cur, end);
-}
-
-/* parse a literal header that is never indexed; index < 15 */
-static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                               const uint8_t *end) {
-  static const grpc_chttp2_hpack_parser_state and_then[] = {
-      parse_value_string_with_indexed_key, finish_lithdr_nvridx};
-  p->dynamic_table_update_allowed = 0;
-  p->next_state = and_then;
-  p->index = (*cur) & 0xf;
-  return parse_string_prefix(p, cur + 1, end);
-}
-
-/* parse a literal header that is never indexed; index >= 15 */
-static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end) {
-  static const grpc_chttp2_hpack_parser_state and_then[] = {
-      parse_string_prefix, parse_value_string_with_indexed_key,
-      finish_lithdr_nvridx};
-  p->dynamic_table_update_allowed = 0;
-  p->next_state = and_then;
-  p->index = 0xf;
-  p->parsing.value = &p->index;
-  return parse_value0(p, cur + 1, end);
-}
-
-/* parse a literal header that is never indexed; index == 0 */
-static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
-                                 const uint8_t *cur, const uint8_t *end) {
-  static const grpc_chttp2_hpack_parser_state and_then[] = {
-      parse_key_string, parse_string_prefix,
-      parse_value_string_with_literal_key, finish_lithdr_nvridx_v};
-  p->dynamic_table_update_allowed = 0;
-  p->next_state = and_then;
-  return parse_string_prefix(p, cur + 1, end);
-}
-
-/* finish parsing a max table size change */
-static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                               const uint8_t *end) {
-  gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
-  return grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index) &&
-         parse_begin(p, cur, end);
-}
-
-/* parse a max table size change, max size < 15 */
-static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                              const uint8_t *end) {
-  if (p->dynamic_table_update_allowed == 0) {
-    return 0;
-  }
-  p->dynamic_table_update_allowed--;
-  p->index = (*cur) & 0x1f;
-  return finish_max_tbl_size(p, cur + 1, end);
-}
-
-/* parse a max table size change, max size >= 15 */
-static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                                const uint8_t *end) {
-  static const grpc_chttp2_hpack_parser_state and_then[] = {
-      finish_max_tbl_size};
-  if (p->dynamic_table_update_allowed == 0) {
-    return 0;
-  }
-  p->dynamic_table_update_allowed--;
-  p->next_state = and_then;
-  p->index = 0x1f;
-  p->parsing.value = &p->index;
-  return parse_value0(p, cur + 1, end);
-}
-
-/* a parse error: jam the parse state into parse_error, and return error */
-static int parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                       const uint8_t *end) {
-  p->state = parse_error;
-  return 0;
-}
-
-static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                            const uint8_t *end) {
-  GPR_ASSERT(cur != end);
-  gpr_log(GPR_DEBUG, "Illegal hpack op code %d", *cur);
-  return parse_error(p, cur, end);
-}
-
-/* parse the 1st byte of a varint into p->parsing.value
-   no overflow is possible */
-static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                        const uint8_t *end) {
-  if (cur == end) {
-    p->state = parse_value0;
-    return 1;
-  }
-
-  *p->parsing.value += (*cur) & 0x7f;
-
-  if ((*cur) & 0x80) {
-    return parse_value1(p, cur + 1, end);
-  } else {
-    return parse_next(p, cur + 1, end);
-  }
-}
-
-/* parse the 2nd byte of a varint into p->parsing.value
-   no overflow is possible */
-static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                        const uint8_t *end) {
-  if (cur == end) {
-    p->state = parse_value1;
-    return 1;
-  }
-
-  *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 7;
-
-  if ((*cur) & 0x80) {
-    return parse_value2(p, cur + 1, end);
-  } else {
-    return parse_next(p, cur + 1, end);
-  }
-}
-
-/* parse the 3rd byte of a varint into p->parsing.value
-   no overflow is possible */
-static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                        const uint8_t *end) {
-  if (cur == end) {
-    p->state = parse_value2;
-    return 1;
-  }
-
-  *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 14;
-
-  if ((*cur) & 0x80) {
-    return parse_value3(p, cur + 1, end);
-  } else {
-    return parse_next(p, cur + 1, end);
-  }
-}
-
-/* parse the 4th byte of a varint into p->parsing.value
-   no overflow is possible */
-static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                        const uint8_t *end) {
-  if (cur == end) {
-    p->state = parse_value3;
-    return 1;
-  }
-
-  *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 21;
-
-  if ((*cur) & 0x80) {
-    return parse_value4(p, cur + 1, end);
-  } else {
-    return parse_next(p, cur + 1, end);
-  }
-}
-
-/* parse the 5th byte of a varint into p->parsing.value
-   depending on the byte, we may overflow, and care must be taken */
-static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                        const uint8_t *end) {
-  uint8_t c;
-  uint32_t cur_value;
-  uint32_t add_value;
-
-  if (cur == end) {
-    p->state = parse_value4;
-    return 1;
-  }
-
-  c = (*cur) & 0x7f;
-  if (c > 0xf) {
-    goto error;
-  }
-
-  cur_value = *p->parsing.value;
-  add_value = ((uint32_t)c) << 28;
-  if (add_value > 0xffffffffu - cur_value) {
-    goto error;
-  }
-
-  *p->parsing.value = cur_value + add_value;
-
-  if ((*cur) & 0x80) {
-    return parse_value5up(p, cur + 1, end);
-  } else {
-    return parse_next(p, cur + 1, end);
-  }
-
-error:
-  gpr_log(GPR_ERROR,
-          "integer overflow in hpack integer decoding: have 0x%08x, "
-          "got byte 0x%02x on byte 5",
-          *p->parsing.value, *cur);
-  return parse_error(p, cur, end);
-}
-
-/* parse any trailing bytes in a varint: it's possible to append an arbitrary
-   number of 0x80's and not affect the value - a zero will terminate - and
-   anything else will overflow */
-static int parse_value5up(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                          const uint8_t *end) {
-  while (cur != end && *cur == 0x80) {
-    ++cur;
-  }
-
-  if (cur == end) {
-    p->state = parse_value5up;
-    return 1;
-  }
-
-  if (*cur == 0) {
-    return parse_next(p, cur + 1, end);
-  }
-
-  gpr_log(GPR_ERROR,
-          "integer overflow in hpack integer decoding: have 0x%08x, "
-          "got byte 0x%02x sometime after byte 5",
-          *p->parsing.value, *cur);
-  return parse_error(p, cur, end);
-}
-
-/* parse a string prefix */
-static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                               const uint8_t *end) {
-  if (cur == end) {
-    p->state = parse_string_prefix;
-    return 1;
-  }
-
-  p->strlen = (*cur) & 0x7f;
-  p->huff = (*cur) >> 7;
-  if (p->strlen == 0x7f) {
-    p->parsing.value = &p->strlen;
-    return parse_value0(p, cur + 1, end);
-  } else {
-    return parse_next(p, cur + 1, end);
-  }
-}
-
-/* append some bytes to a string */
-static void append_bytes(grpc_chttp2_hpack_parser_string *str,
-                         const uint8_t *data, size_t length) {
-  if (length + str->length > str->capacity) {
-    GPR_ASSERT(str->length + length <= UINT32_MAX);
-    str->capacity = (uint32_t)(str->length + length);
-    str->str = gpr_realloc(str->str, str->capacity);
-  }
-  memcpy(str->str + str->length, data, length);
-  GPR_ASSERT(length <= UINT32_MAX - str->length);
-  str->length += (uint32_t)length;
-}
-
-static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                         const uint8_t *end) {
-  grpc_chttp2_hpack_parser_string *str = p->parsing.str;
-  uint32_t bits;
-  uint8_t decoded[3];
-  switch ((binary_state)p->binary) {
-    case NOT_BINARY:
-      append_bytes(str, cur, (size_t)(end - cur));
-      return 1;
-    b64_byte0:
-    case B64_BYTE0:
-      if (cur == end) {
-        p->binary = B64_BYTE0;
-        return 1;
-      }
-      bits = inverse_base64[*cur];
-      ++cur;
-      if (bits == 255)
-        return 0;
-      else if (bits == 64)
-        goto b64_byte0;
-      p->base64_buffer = bits << 18;
-    /* fallthrough */
-    b64_byte1:
-    case B64_BYTE1:
-      if (cur == end) {
-        p->binary = B64_BYTE1;
-        return 1;
-      }
-      bits = inverse_base64[*cur];
-      ++cur;
-      if (bits == 255)
-        return 0;
-      else if (bits == 64)
-        goto b64_byte1;
-      p->base64_buffer |= bits << 12;
-    /* fallthrough */
-    b64_byte2:
-    case B64_BYTE2:
-      if (cur == end) {
-        p->binary = B64_BYTE2;
-        return 1;
-      }
-      bits = inverse_base64[*cur];
-      ++cur;
-      if (bits == 255)
-        return 0;
-      else if (bits == 64)
-        goto b64_byte2;
-      p->base64_buffer |= bits << 6;
-    /* fallthrough */
-    b64_byte3:
-    case B64_BYTE3:
-      if (cur == end) {
-        p->binary = B64_BYTE3;
-        return 1;
-      }
-      bits = inverse_base64[*cur];
-      ++cur;
-      if (bits == 255)
-        return 0;
-      else if (bits == 64)
-        goto b64_byte3;
-      p->base64_buffer |= bits;
-      bits = p->base64_buffer;
-      decoded[0] = (uint8_t)(bits >> 16);
-      decoded[1] = (uint8_t)(bits >> 8);
-      decoded[2] = (uint8_t)(bits);
-      append_bytes(str, decoded, 3);
-      goto b64_byte0;
-  }
-  GPR_UNREACHABLE_CODE(return 1);
-}
-
-/* append a null terminator to a string */
-static int finish_str(grpc_chttp2_hpack_parser *p) {
-  uint8_t terminator = 0;
-  uint8_t decoded[2];
-  uint32_t bits;
-  grpc_chttp2_hpack_parser_string *str = p->parsing.str;
-  switch ((binary_state)p->binary) {
-    case NOT_BINARY:
-      break;
-    case B64_BYTE0:
-      break;
-    case B64_BYTE1:
-      gpr_log(GPR_ERROR, "illegal base64 encoding");
-      return 0; /* illegal encoding */
-    case B64_BYTE2:
-      bits = p->base64_buffer;
-      if (bits & 0xffff) {
-        gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%04x",
-                bits & 0xffff);
-        return 0;
-      }
-      decoded[0] = (uint8_t)(bits >> 16);
-      append_bytes(str, decoded, 1);
-      break;
-    case B64_BYTE3:
-      bits = p->base64_buffer;
-      if (bits & 0xff) {
-        gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%02x",
-                bits & 0xff);
-        return 0;
-      }
-      decoded[0] = (uint8_t)(bits >> 16);
-      decoded[1] = (uint8_t)(bits >> 8);
-      append_bytes(str, decoded, 2);
-      break;
-  }
-  append_bytes(str, &terminator, 1);
-  p->parsing.str->length--; /* don't actually count the null terminator */
-  return 1;
-}
-
-/* decode a nibble from a huffman encoded stream */
-static int huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t nibble) {
-  int16_t emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble];
-  int16_t next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble];
-  if (emit != -1) {
-    if (emit >= 0 && emit < 256) {
-      uint8_t c = (uint8_t)emit;
-      if (!append_string(p, &c, (&c) + 1)) return 0;
-    } else {
-      assert(emit == 256);
-    }
-  }
-  p->huff_state = next;
-  return 1;
-}
-
-/* decode full bytes from a huffman encoded stream */
-static int add_huff_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                          const uint8_t *end) {
-  for (; cur != end; ++cur) {
-    if (!huff_nibble(p, *cur >> 4) || !huff_nibble(p, *cur & 0xf)) return 0;
-  }
-  return 1;
-}
-
-/* decode some string bytes based on the current decoding mode
-   (huffman or not) */
-static int add_str_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                         const uint8_t *end) {
-  if (p->huff) {
-    return add_huff_bytes(p, cur, end);
-  } else {
-    return append_string(p, cur, end);
-  }
-}
-
-/* parse a string - tries to do large chunks at a time */
-static int parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                        const uint8_t *end) {
-  size_t remaining = p->strlen - p->strgot;
-  size_t given = (size_t)(end - cur);
-  if (remaining <= given) {
-    return add_str_bytes(p, cur, cur + remaining) && finish_str(p) &&
-           parse_next(p, cur + remaining, end);
-  } else {
-    if (!add_str_bytes(p, cur, cur + given)) return 0;
-    GPR_ASSERT(given <= UINT32_MAX - p->strgot);
-    p->strgot += (uint32_t)given;
-    p->state = parse_string;
-    return 1;
-  }
-}
-
-/* begin parsing a string - performs setup, calls parse_string */
-static int begin_parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                              const uint8_t *end, uint8_t binary,
-                              grpc_chttp2_hpack_parser_string *str) {
-  p->strgot = 0;
-  str->length = 0;
-  p->parsing.str = str;
-  p->huff_state = 0;
-  p->binary = binary;
-  return parse_string(p, cur, end);
-}
-
-/* parse the key string */
-static int parse_key_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                            const uint8_t *end) {
-  return begin_parse_string(p, cur, end, NOT_BINARY, &p->key);
-}
-
-/* check if a key represents a binary header or not */
-typedef enum { BINARY_HEADER, PLAINTEXT_HEADER, ERROR_HEADER } is_binary_header;
-
-static is_binary_header is_binary_literal_header(grpc_chttp2_hpack_parser *p) {
-  return grpc_is_binary_header(p->key.str, p->key.length) ? BINARY_HEADER
-                                                          : PLAINTEXT_HEADER;
-}
-
-static is_binary_header is_binary_indexed_header(grpc_chttp2_hpack_parser *p) {
-  grpc_mdelem *elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
-  if (!elem) {
-    gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
-    return ERROR_HEADER;
-  }
-  return grpc_is_binary_header(
-             (const char *)GPR_SLICE_START_PTR(elem->key->slice),
-             GPR_SLICE_LENGTH(elem->key->slice))
-             ? BINARY_HEADER
-             : PLAINTEXT_HEADER;
-}
-
-/* parse the value string */
-static int parse_value_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
-                              const uint8_t *end, is_binary_header type) {
-  switch (type) {
-    case BINARY_HEADER:
-      return begin_parse_string(p, cur, end, B64_BYTE0, &p->value);
-    case PLAINTEXT_HEADER:
-      return begin_parse_string(p, cur, end, NOT_BINARY, &p->value);
-    case ERROR_HEADER:
-      return 0;
-  }
-  /* Add code to prevent return without value error */
-  GPR_UNREACHABLE_CODE(return 0);
-}
-
-static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p,
-                                               const uint8_t *cur,
-                                               const uint8_t *end) {
-  return parse_value_string(p, cur, end, is_binary_indexed_header(p));
-}
-
-static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p,
-                                               const uint8_t *cur,
-                                               const uint8_t *end) {
-  return parse_value_string(p, cur, end, is_binary_literal_header(p));
-}
-
-/* PUBLIC INTERFACE */
-
-static void on_header_not_set(void *user_data, grpc_mdelem *md) {
-  GPR_UNREACHABLE_CODE(return );
-}
-
-void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) {
-  p->on_header = on_header_not_set;
-  p->on_header_user_data = NULL;
-  p->state = parse_begin;
-  p->key.str = NULL;
-  p->key.capacity = 0;
-  p->key.length = 0;
-  p->value.str = NULL;
-  p->value.capacity = 0;
-  p->value.length = 0;
-  p->dynamic_table_update_allowed = 2;
-  grpc_chttp2_hptbl_init(&p->table);
-}
-
-void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) {
-  p->after_prioritization = p->state;
-  p->state = parse_stream_dep0;
-}
-
-void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p) {
-  grpc_chttp2_hptbl_destroy(&p->table);
-  gpr_free(p->key.str);
-  gpr_free(p->value.str);
-}
-
-int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
-                                   const uint8_t *beg, const uint8_t *end) {
-  /* TODO(ctiller): limit the distance of end from beg, and perform multiple
-     steps in the event of a large chunk of data to limit
-     stack space usage when no tail call optimization is
-     available */
-  return p->state(p, beg, end);
-}
-
-grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
-    grpc_exec_ctx *exec_ctx, 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;
-  GPR_TIMER_BEGIN("grpc_chttp2_hpack_parser_parse", 0);
-  if (!grpc_chttp2_hpack_parser_parse(parser, GPR_SLICE_START_PTR(slice),
-                                      GPR_SLICE_END_PTR(slice))) {
-    GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
-    return GRPC_CHTTP2_CONNECTION_ERROR;
-  }
-  if (is_last) {
-    if (parser->is_boundary && parser->state != parse_begin) {
-      gpr_log(GPR_ERROR,
-              "end of header frame not aligned with a hpack record boundary");
-      GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
-      return GRPC_CHTTP2_CONNECTION_ERROR;
-    }
-    /* need to check for null stream: this can occur if we receive an invalid
-       stream id on a header */
-    if (stream_parsing != NULL) {
-      if (parser->is_boundary) {
-        stream_parsing
-            ->got_metadata_on_parse[stream_parsing->header_frames_received] = 1;
-        stream_parsing->header_frames_received++;
-        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;
-    parser->is_eof = 0xde;
-    parser->dynamic_table_update_allowed = 2;
-  }
-  GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
-  return GRPC_CHTTP2_PARSE_OK;
-}
diff --git a/src/core/transport/chttp2/hpack_parser.h b/src/core/transport/chttp2/hpack_parser.h
deleted file mode 100644
index 1ad0c64..0000000
--- a/src/core/transport/chttp2/hpack_parser.h
+++ /dev/null
@@ -1,116 +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_TRANSPORT_CHTTP2_HPACK_PARSER_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_PARSER_H
-
-#include <stddef.h>
-
-#include <grpc/support/port_platform.h>
-#include "src/core/iomgr/exec_ctx.h"
-#include "src/core/transport/chttp2/frame.h"
-#include "src/core/transport/chttp2/hpack_table.h"
-#include "src/core/transport/metadata.h"
-
-typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser;
-
-typedef int (*grpc_chttp2_hpack_parser_state)(grpc_chttp2_hpack_parser *p,
-                                              const uint8_t *beg,
-                                              const uint8_t *end);
-
-typedef struct {
-  char *str;
-  uint32_t length;
-  uint32_t capacity;
-} grpc_chttp2_hpack_parser_string;
-
-struct grpc_chttp2_hpack_parser {
-  /* user specified callback for each header output */
-  void (*on_header)(void *user_data, grpc_mdelem *md);
-  void *on_header_user_data;
-
-  /* current parse state - or a function that implements it */
-  grpc_chttp2_hpack_parser_state state;
-  /* future states dependent on the opening op code */
-  const grpc_chttp2_hpack_parser_state *next_state;
-  /* what to do after skipping prioritization data */
-  grpc_chttp2_hpack_parser_state after_prioritization;
-  /* the value we're currently parsing */
-  union {
-    uint32_t *value;
-    grpc_chttp2_hpack_parser_string *str;
-  } parsing;
-  /* string parameters for each chunk */
-  grpc_chttp2_hpack_parser_string key;
-  grpc_chttp2_hpack_parser_string value;
-  /* parsed index */
-  uint32_t index;
-  /* length of source bytes for the currently parsing string */
-  uint32_t strlen;
-  /* number of source bytes read for the currently parsing string */
-  uint32_t strgot;
-  /* huffman decoding state */
-  int16_t huff_state;
-  /* is the string being decoded binary? */
-  uint8_t binary;
-  /* is the current string huffman encoded? */
-  uint8_t huff;
-  /* is a dynamic table update allowed? */
-  uint8_t dynamic_table_update_allowed;
-  /* set by higher layers, used by grpc_chttp2_header_parser_parse to signal
-     it should append a metadata boundary at the end of frame */
-  uint8_t is_boundary;
-  uint8_t is_eof;
-  uint32_t base64_buffer;
-
-  /* hpack table */
-  grpc_chttp2_hptbl table;
-};
-
-void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p);
-void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p);
-
-void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p);
-
-/* returns 1 on success, 0 on error */
-int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
-                                   const uint8_t *beg, const uint8_t *end);
-
-/* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for
-   the transport */
-grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
-    grpc_exec_ctx *exec_ctx, 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 */
diff --git a/src/core/transport/chttp2/hpack_table.c b/src/core/transport/chttp2/hpack_table.c
deleted file mode 100644
index f1ce3b8..0000000
--- a/src/core/transport/chttp2/hpack_table.c
+++ /dev/null
@@ -1,361 +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/transport/chttp2/hpack_table.h"
-
-#include <assert.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/support/murmur_hash.h"
-
-static struct {
-  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", ""},
-};
-
-static uint32_t entries_for_bytes(uint32_t bytes) {
-  return (bytes + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) /
-         GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
-}
-
-void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl) {
-  size_t i;
-
-  memset(tbl, 0, sizeof(*tbl));
-  tbl->current_table_bytes = tbl->max_bytes =
-      GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
-  tbl->max_entries = tbl->cap_entries =
-      entries_for_bytes(tbl->current_table_bytes);
-  tbl->ents = gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries);
-  memset(tbl->ents, 0, sizeof(*tbl->ents) * tbl->cap_entries);
-  for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
-    tbl->static_ents[i - 1] =
-        grpc_mdelem_from_strings(static_table[i].key, static_table[i].value);
-  }
-}
-
-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]);
-  }
-  for (i = 0; i < tbl->num_ents; i++) {
-    GRPC_MDELEM_UNREF(tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]);
-  }
-  gpr_free(tbl->ents);
-}
-
-grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
-                                      uint32_t tbl_index) {
-  /* Static table comes first, just return an entry from it */
-  if (tbl_index <= GRPC_CHTTP2_LAST_STATIC_ENTRY) {
-    return tbl->static_ents[tbl_index - 1];
-  }
-  /* Otherwise, find the value in the list of valid entries */
-  tbl_index -= (GRPC_CHTTP2_LAST_STATIC_ENTRY + 1);
-  if (tbl_index < tbl->num_ents) {
-    uint32_t offset =
-        (tbl->num_ents - 1u - tbl_index + tbl->first_ent) % tbl->cap_entries;
-    return tbl->ents[offset];
-  }
-  /* Invalid entry: return error */
-  return NULL;
-}
-
-/* Evict one element from the table */
-static void evict1(grpc_chttp2_hptbl *tbl) {
-  grpc_mdelem *first_ent = tbl->ents[tbl->first_ent];
-  size_t elem_bytes = GPR_SLICE_LENGTH(first_ent->key->slice) +
-                      GPR_SLICE_LENGTH(first_ent->value->slice) +
-                      GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
-  GPR_ASSERT(elem_bytes <= tbl->mem_used);
-  tbl->mem_used -= (uint32_t)elem_bytes;
-  tbl->first_ent = ((tbl->first_ent + 1) % tbl->cap_entries);
-  tbl->num_ents--;
-  GRPC_MDELEM_UNREF(first_ent);
-}
-
-static void rebuild_ents(grpc_chttp2_hptbl *tbl, uint32_t new_cap) {
-  grpc_mdelem **ents = gpr_malloc(sizeof(*ents) * new_cap);
-  uint32_t i;
-
-  for (i = 0; i < tbl->num_ents; i++) {
-    ents[i] = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
-  }
-  gpr_free(tbl->ents);
-  tbl->ents = ents;
-  tbl->cap_entries = new_cap;
-  tbl->first_ent = 0;
-}
-
-void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
-                                     uint32_t max_bytes) {
-  if (tbl->max_bytes == max_bytes) {
-    return;
-  }
-  gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes);
-  while (tbl->mem_used > max_bytes) {
-    evict1(tbl);
-  }
-  tbl->max_bytes = max_bytes;
-}
-
-int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
-                                             uint32_t bytes) {
-  if (tbl->current_table_bytes == bytes) {
-    return 1;
-  }
-  if (bytes > tbl->max_bytes) {
-    gpr_log(GPR_ERROR,
-            "Attempt to make hpack table %d bytes when max is %d bytes", bytes,
-            tbl->max_bytes);
-    return 0;
-  }
-  gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes);
-  while (tbl->mem_used > bytes) {
-    evict1(tbl);
-  }
-  tbl->current_table_bytes = bytes;
-  tbl->max_entries = entries_for_bytes(bytes);
-  if (tbl->max_entries > tbl->cap_entries) {
-    rebuild_ents(tbl, GPR_MAX(tbl->max_entries, 2 * tbl->cap_entries));
-  } else if (tbl->max_entries < tbl->cap_entries / 3) {
-    uint32_t new_cap = GPR_MAX(tbl->max_entries, 16u);
-    if (new_cap != tbl->cap_entries) {
-      rebuild_ents(tbl, new_cap);
-    }
-  }
-  return 1;
-}
-
-int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
-  /* determine how many bytes of buffer this entry represents */
-  size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) +
-                      GPR_SLICE_LENGTH(md->value->slice) +
-                      GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
-
-  if (tbl->current_table_bytes > tbl->max_bytes) {
-    gpr_log(GPR_ERROR,
-            "HPACK max table size reduced to %d but not reflected by hpack "
-            "stream (still at %d)",
-            tbl->max_bytes, tbl->current_table_bytes);
-    return 0;
-  }
-
-  /* we can't add elements bigger than the max table size */
-  if (elem_bytes > tbl->current_table_bytes) {
-    /* HPACK draft 10 section 4.4 states:
-     * If the size of the new entry is less than or equal to the maximum
-     * size, that entry is added to the table.  It is not an error to
-     * attempt to add an entry that is larger than the maximum size; an
-     * attempt to add an entry larger than the entire table causes
-     * the table
-     * to be emptied of all existing entries, and results in an
-     * empty table.
-     */
-    while (tbl->num_ents) {
-      evict1(tbl);
-    }
-    return 1;
-  }
-
-  /* evict entries to ensure no overflow */
-  while (elem_bytes > (size_t)tbl->current_table_bytes - tbl->mem_used) {
-    evict1(tbl);
-  }
-
-  /* copy the finalized entry in */
-  tbl->ents[(tbl->first_ent + tbl->num_ents) % tbl->cap_entries] =
-      GRPC_MDELEM_REF(md);
-
-  /* update accounting values */
-  tbl->num_ents++;
-  tbl->mem_used += (uint32_t)elem_bytes;
-  return 1;
-}
-
-grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
-    const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
-  grpc_chttp2_hptbl_find_result r = {0, 0};
-  uint32_t i;
-
-  /* See if the string is in the static table */
-  for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
-    grpc_mdelem *ent = tbl->static_ents[i];
-    if (md->key != ent->key) continue;
-    r.index = i + 1u;
-    r.has_value = md->value == ent->value;
-    if (r.has_value) return r;
-  }
-
-  /* Scan the dynamic table */
-  for (i = 0; i < tbl->num_ents; i++) {
-    uint32_t idx =
-        (uint32_t)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
-    grpc_mdelem *ent = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
-    if (md->key != ent->key) continue;
-    r.index = idx;
-    r.has_value = md->value == ent->value;
-    if (r.has_value) return r;
-  }
-
-  return r;
-}
diff --git a/src/core/transport/chttp2/hpack_table.h b/src/core/transport/chttp2/hpack_table.h
deleted file mode 100644
index e743125..0000000
--- a/src/core/transport/chttp2/hpack_table.h
+++ /dev/null
@@ -1,108 +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_TRANSPORT_CHTTP2_HPACK_TABLE_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_TABLE_H
-
-#include "src/core/transport/metadata.h"
-#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-
-/* HPACK header table */
-
-/* last index in the static table */
-#define GRPC_CHTTP2_LAST_STATIC_ENTRY 61
-
-/* Initial table size as per the spec */
-#define GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE 4096
-/* Maximum table size that we'll use */
-#define GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE
-/* Per entry overhead bytes as per the spec */
-#define GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD 32
-#if 0
-/* Maximum number of entries we could possibly fit in the table, given defined
-   overheads */
-#define GRPC_CHTTP2_MAX_TABLE_COUNT                                            \
-  ((GRPC_CHTTP2_MAX_HPACK_TABLE_SIZE + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / \
-   GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD)
-#endif
-
-/* hpack decoder table */
-typedef struct {
-  /* the first used entry in ents */
-  uint32_t first_ent;
-  /* how many entries are in the table */
-  uint32_t num_ents;
-  /* the amount of memory used by the table, according to the hpack algorithm */
-  uint32_t mem_used;
-  /* the max memory allowed to be used by the table, according to the hpack
-     algorithm */
-  uint32_t max_bytes;
-  /* the currently agreed size of the table, according to the hpack algorithm */
-  uint32_t current_table_bytes;
-  /* Maximum number of entries we could possibly fit in the table, given defined
-     overheads */
-  uint32_t max_entries;
-  /* Number of entries allocated in ents */
-  uint32_t cap_entries;
-  /* a circular buffer of headers - this is stored in the opposite order to
-     what hpack specifies, in order to simplify table management a little...
-     meaning lookups need to SUBTRACT from the end position */
-  grpc_mdelem **ents;
-  grpc_mdelem *static_ents[GRPC_CHTTP2_LAST_STATIC_ENTRY];
-} grpc_chttp2_hptbl;
-
-/* initialize a hpack table */
-void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl);
-void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl);
-void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
-                                     uint32_t max_bytes);
-int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
-                                             uint32_t bytes);
-
-/* lookup a table entry based on its hpack index */
-grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
-                                      uint32_t index);
-/* add a table entry to the index */
-int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl,
-                          grpc_mdelem *md) GRPC_MUST_USE_RESULT;
-/* Find a key/value pair in the table... returns the index in the table of the
-   most similar entry, or 0 if the value was not found */
-typedef struct {
-  uint32_t index;
-  int has_value;
-} grpc_chttp2_hptbl_find_result;
-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 */
diff --git a/src/core/transport/chttp2/http2_errors.h b/src/core/transport/chttp2/http2_errors.h
deleted file mode 100644
index a4f309e..0000000
--- a/src/core/transport/chttp2/http2_errors.h
+++ /dev/null
@@ -1,56 +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_TRANSPORT_CHTTP2_HTTP2_ERRORS_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HTTP2_ERRORS_H
-
-/* error codes for RST_STREAM from http2 draft 14 section 7 */
-typedef enum {
-  GRPC_CHTTP2_NO_ERROR = 0x0,
-  GRPC_CHTTP2_PROTOCOL_ERROR = 0x1,
-  GRPC_CHTTP2_INTERNAL_ERROR = 0x2,
-  GRPC_CHTTP2_FLOW_CONTROL_ERROR = 0x3,
-  GRPC_CHTTP2_SETTINGS_TIMEOUT = 0x4,
-  GRPC_CHTTP2_STREAM_CLOSED = 0x5,
-  GRPC_CHTTP2_FRAME_SIZE_ERROR = 0x6,
-  GRPC_CHTTP2_REFUSED_STREAM = 0x7,
-  GRPC_CHTTP2_CANCEL = 0x8,
-  GRPC_CHTTP2_COMPRESSION_ERROR = 0x9,
-  GRPC_CHTTP2_CONNECT_ERROR = 0xa,
-  GRPC_CHTTP2_ENHANCE_YOUR_CALM = 0xb,
-  GRPC_CHTTP2_INADEQUATE_SECURITY = 0xc,
-  /* force use of a default clause */
-  GRPC_CHTTP2__ERROR_DO_NOT_USE = -1
-} grpc_chttp2_error_code;
-
-#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
deleted file mode 100644
index 7b138e9..0000000
--- a/src/core/transport/chttp2/huffsyms.c
+++ /dev/null
@@ -1,297 +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/transport/chttp2/huffsyms.h"
-
-/* Constants pulled from the HPACK spec, and converted to C using the vim
-   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},
-};
diff --git a/src/core/transport/chttp2/huffsyms.h b/src/core/transport/chttp2/huffsyms.h
deleted file mode 100644
index a3cdba8..0000000
--- a/src/core/transport/chttp2/huffsyms.h
+++ /dev/null
@@ -1,48 +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_TRANSPORT_CHTTP2_HUFFSYMS_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HUFFSYMS_H
-
-/* HPACK static huffman table */
-
-#define GRPC_CHTTP2_NUM_HUFFSYMS 257
-
-typedef struct {
-  unsigned bits;
-  unsigned length;
-} grpc_chttp2_huffsym;
-
-extern const grpc_chttp2_huffsym grpc_chttp2_huffsyms[GRPC_CHTTP2_NUM_HUFFSYMS];
-
-#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
deleted file mode 100644
index 315bc2f..0000000
--- a/src/core/transport/chttp2/incoming_metadata.c
+++ /dev/null
@@ -1,96 +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/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;
-  if (!buffer->published) {
-    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) {
-  GPR_ASSERT(!buffer->published);
-  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) {
-  GPR_ASSERT(!buffer->published);
-  buffer->deadline = deadline;
-}
-
-void grpc_chttp2_incoming_metadata_buffer_publish(
-    grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch) {
-  GPR_ASSERT(!buffer->published);
-  buffer->published = 1;
-  if (buffer->count > 0) {
-    size_t i;
-    for (i = 1; i < buffer->count; i++) {
-      buffer->elems[i].prev = &buffer->elems[i - 1];
-    }
-    for (i = 0; i < buffer->count - 1; i++) {
-      buffer->elems[i].next = &buffer->elems[i + 1];
-    }
-    buffer->elems[0].prev = NULL;
-    buffer->elems[buffer->count - 1].next = NULL;
-    batch->list.head = &buffer->elems[0];
-    batch->list.tail = &buffer->elems[buffer->count - 1];
-  } else {
-    batch->list.head = batch->list.tail = NULL;
-  }
-  batch->deadline = buffer->deadline;
-}
diff --git a/src/core/transport/chttp2/incoming_metadata.h b/src/core/transport/chttp2/incoming_metadata.h
deleted file mode 100644
index ea74cfc..0000000
--- a/src/core/transport/chttp2/incoming_metadata.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#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;
-  int published;
-} grpc_chttp2_incoming_metadata_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_publish(
-    grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch);
-
-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);
-
-#endif /* GRPC_INTERNAL_CORE_CHTTP2_INCOMING_METADATA_H */
diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h
deleted file mode 100644
index b720d1a..0000000
--- a/src/core/transport/chttp2/internal.h
+++ /dev/null
@@ -1,780 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CHTTP2_INTERNAL_H
-#define GRPC_INTERNAL_CORE_CHTTP2_INTERNAL_H
-
-#include <assert.h>
-#include <stdbool.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_encoder.h"
-#include "src/core/transport/chttp2/hpack_parser.h"
-#include "src/core/transport/chttp2/incoming_metadata.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_CHECK_READ_OPS,
-  GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE,
-  GRPC_CHTTP2_LIST_WRITABLE,
-  GRPC_CHTTP2_LIST_WRITING,
-  GRPC_CHTTP2_LIST_WRITTEN,
-  GRPC_CHTTP2_LIST_PARSING_SEEN,
-  GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING,
-  GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING,
-  GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT,
-  /* streams waiting for the outgoing window in the writing path, they will be
-   * merged to the stalled list or writable list under transport lock. */
-  GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT,
-  /** 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 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 {
-  uint8_t id[8];
-  grpc_closure *on_recv;
-  struct grpc_chttp2_outstanding_ping *next;
-  struct grpc_chttp2_outstanding_ping *prev;
-} grpc_chttp2_outstanding_ping;
-
-/* forward declared in frame_data.h */
-struct grpc_chttp2_incoming_byte_stream {
-  grpc_byte_stream base;
-  gpr_refcount refs;
-  struct grpc_chttp2_incoming_byte_stream *next_message;
-  int failed;
-
-  grpc_chttp2_transport *transport;
-  grpc_chttp2_stream *stream;
-  int is_tail;
-  gpr_slice_buffer slices;
-  grpc_closure *on_next;
-  gpr_slice *next;
-};
-
-typedef struct {
-  /** data to write next write */
-  gpr_slice_buffer qbuf;
-
-  /** window available for us to send to peer */
-  int64_t outgoing_window;
-  /** window available to announce to peer */
-  int64_t announce_incoming_window;
-  /** how much window would we like to have for incoming_window */
-  uint32_t connection_window_target;
-
-  /** have we seen a goaway */
-  uint8_t seen_goaway;
-  /** have we sent a goaway */
-  uint8_t sent_goaway;
-
-  /** is this transport a client? */
-  uint8_t is_client;
-  /** are the local settings dirty and need to be sent? */
-  uint8_t dirtied_local_settings;
-  /** have local settings been sent? */
-  uint8_t sent_local_settings;
-  /** bitmask of setting indexes to send out */
-  uint32_t force_send_settings;
-  /** settings values */
-  uint32_t 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 */
-  uint32_t next_stream_id;
-
-  /** how far to lookahead in a stream? */
-  uint32_t stream_lookahead;
-
-  /** last received stream id */
-  uint32_t last_incoming_stream_id;
-
-  /** pings awaiting responses */
-  grpc_chttp2_outstanding_ping pings;
-  /** next payload for an outgoing ping */
-  uint64_t ping_counter;
-
-  /** concurrent stream count: updated when not parsing,
-      so this is a strict over-estimation on the client */
-  uint32_t 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;
-  int64_t outgoing_window;
-  /** is this a client? */
-  uint8_t is_client;
-  /** callback for when writing is done */
-  grpc_closure done_cb;
-} grpc_chttp2_transport_writing;
-
-struct grpc_chttp2_transport_parsing {
-  /** is this transport a client? (boolean) */
-  uint8_t is_client;
-
-  /** were settings updated? */
-  uint8_t settings_updated;
-  /** was a settings ack received? */
-  uint8_t settings_ack_received;
-  /** was a goaway frame received? */
-  uint8_t goaway_received;
-
-  /** the last sent max_table_size setting */
-  uint32_t last_sent_max_table_size;
-
-  /** initial window change */
-  int64_t initial_window_update;
-
-  /** data to write later - after parsing */
-  gpr_slice_buffer qbuf;
-  /** 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 */
-  int64_t incoming_window;
-
-  /** next stream id available at the time of beginning parsing */
-  uint32_t next_stream_id;
-  uint32_t last_incoming_stream_id;
-
-  /* deframing */
-  grpc_chttp2_deframe_transport_state deframe_state;
-  uint8_t incoming_frame_type;
-  uint8_t incoming_frame_flags;
-  uint8_t header_eof;
-  uint32_t expect_continuation_stream_id;
-  uint32_t incoming_frame_size;
-  uint32_t incoming_stream_id;
-
-  /* active parser */
-  void *parser_data;
-  grpc_chttp2_stream_parsing *incoming_stream;
-  grpc_chttp2_parse_error (*parser)(
-      grpc_exec_ctx *exec_ctx, void *parser_user_data,
-      grpc_chttp2_transport_parsing *transport_parsing,
-      grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
-
-  /* received settings */
-  uint32_t settings[GRPC_CHTTP2_NUM_SETTINGS];
-
-  /* goaway data */
-  grpc_status_code goaway_error;
-  uint32_t goaway_last_stream_index;
-  gpr_slice goaway_text;
-
-  int64_t outgoing_window;
-};
-
-struct grpc_chttp2_transport {
-  grpc_transport base; /* must be first */
-  grpc_endpoint *ep;
-  gpr_refcount refs;
-  char *peer_string;
-
-  /** when this drops to zero it's safe to shutdown the endpoint */
-  gpr_refcount shutdown_ep_refs;
-
-  gpr_mu mu;
-
-  /** is the transport destroying itself? */
-  uint8_t destroying;
-  /** has the upper layer closed the transport? */
-  uint8_t closed;
-
-  /** is a thread currently writing */
-  uint8_t writing_active;
-  /** is a thread currently parsing */
-  uint8_t parsing_active;
-
-  /** is there a read request to the endpoint outstanding? */
-  uint8_t 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_closure writing_action;
-  /** closure to finish reading from the endpoint */
-  grpc_closure recv_data;
-
-  /** incoming read bytes */
-  gpr_slice_buffer read_buffer;
-
-  /** 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)(grpc_exec_ctx *exec_ctx, 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;
-
-  /** Transport op to be applied post-parsing */
-  grpc_transport_op *post_parsing_op;
-};
-
-typedef struct {
-  /** HTTP2 stream id for this stream, or zero if one has not been assigned */
-  uint32_t id;
-
-  /** window available for us to send to peer */
-  int64_t 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. */
-  uint32_t 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. */
-  uint32_t unannounced_incoming_window_for_parse;
-  uint32_t unannounced_incoming_window_for_writing;
-  /** things the upper layers would like to send */
-  grpc_metadata_batch *send_initial_metadata;
-  grpc_closure *send_initial_metadata_finished;
-  grpc_byte_stream *send_message;
-  grpc_closure *send_message_finished;
-  grpc_metadata_batch *send_trailing_metadata;
-  grpc_closure *send_trailing_metadata_finished;
-
-  grpc_metadata_batch *recv_initial_metadata;
-  grpc_closure *recv_initial_metadata_ready;
-  grpc_byte_stream **recv_message;
-  grpc_closure *recv_message_ready;
-  grpc_metadata_batch *recv_trailing_metadata;
-  grpc_closure *recv_trailing_metadata_finished;
-
-  /** 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' */
-  uint8_t write_closed;
-  /** is this stream reading half-closed (boolean) */
-  uint8_t read_closed;
-  /** is this stream in the stream map? (boolean) */
-  uint8_t in_stream_map;
-  /** has this stream seen an error? if 1, then pending incoming frames
-      can be thrown away */
-  uint8_t seen_error;
-
-  uint8_t published_initial_metadata;
-  uint8_t published_trailing_metadata;
-  uint8_t faked_trailing_metadata;
-
-  grpc_chttp2_incoming_metadata_buffer received_initial_metadata;
-  grpc_chttp2_incoming_metadata_buffer received_trailing_metadata;
-
-  grpc_chttp2_incoming_frame_queue incoming_frames;
-} grpc_chttp2_stream_global;
-
-typedef struct {
-  /** HTTP2 stream id for this stream, or zero if one has not been assigned */
-  uint32_t id;
-  uint8_t fetching;
-  bool sent_initial_metadata;
-  uint8_t sent_message;
-  uint8_t sent_trailing_metadata;
-  uint8_t read_closed;
-  /** send this initial metadata */
-  grpc_metadata_batch *send_initial_metadata;
-  grpc_byte_stream *send_message;
-  grpc_metadata_batch *send_trailing_metadata;
-  int64_t outgoing_window;
-  /** how much window should we announce? */
-  uint32_t announce_window;
-  gpr_slice_buffer flow_controlled_buffer;
-  gpr_slice fetching_slice;
-  size_t stream_fetched;
-  grpc_closure finished_fetch;
-} grpc_chttp2_stream_writing;
-
-struct grpc_chttp2_stream_parsing {
-  /** HTTP2 stream id for this stream, or zero if one has not been assigned */
-  uint32_t id;
-  /** has this stream received a close */
-  uint8_t received_close;
-  /** saw a rst_stream */
-  uint8_t saw_rst_stream;
-  /** how many header frames have we received? */
-  uint8_t header_frames_received;
-  /** which metadata did we get (on this parse) */
-  uint8_t got_metadata_on_parse[2];
-  /** should we raise the seen_error flag in transport_global */
-  uint8_t seen_error;
-  /** window available for peer to send to us */
-  int64_t incoming_window;
-  /** parsing state for data frames */
-  grpc_chttp2_data_parser data_parser;
-  /** reason give to rst_stream */
-  uint32_t rst_stream_reason;
-  /** amount of window given */
-  int64_t outgoing_window;
-  /** number of bytes received - reset at end of parse thread execution */
-  int64_t received_bytes;
-
-  /** incoming metadata */
-  grpc_chttp2_incoming_metadata_buffer metadata_buffer[2];
-};
-
-struct grpc_chttp2_stream {
-  grpc_stream_refcount *refcount;
-  grpc_chttp2_stream_global global;
-  grpc_chttp2_stream_writing writing;
-  grpc_chttp2_stream_parsing parsing;
-
-  grpc_chttp2_stream_link links[STREAM_LIST_COUNT];
-  uint8_t 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_exec_ctx *exec_ctx,
-                                       grpc_chttp2_transport_global *global,
-                                       grpc_chttp2_transport_writing *writing,
-                                       int is_parsing);
-void grpc_chttp2_perform_writes(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
-    grpc_endpoint *endpoint);
-void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
-                                   void *transport_writing, bool success);
-void grpc_chttp2_cleanup_writing(grpc_exec_ctx *exec_ctx,
-                                 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_exec_ctx *exec_ctx,
-                             grpc_chttp2_transport_parsing *transport_parsing,
-                             gpr_slice slice);
-void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx,
-                               grpc_chttp2_transport_global *global,
-                               grpc_chttp2_transport_parsing *parsing);
-
-bool grpc_chttp2_list_add_writable_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-/** Get a writable stream
-    returns non-zero if there was a stream available */
-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);
-bool grpc_chttp2_list_remove_writable_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) GRPC_MUST_USE_RESULT;
-
-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_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_check_read_ops(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-int grpc_chttp2_list_pop_check_read_ops(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global);
-
-void grpc_chttp2_list_add_writing_stalled_by_transport(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing *stream_writing);
-void grpc_chttp2_list_flush_writing_stalled_by_transport(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
-    bool is_window_available);
-
-void grpc_chttp2_list_add_stalled_by_transport(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing *stream_writing);
-int grpc_chttp2_list_pop_stalled_by_transport(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global);
-void grpc_chttp2_list_remove_stalled_by_transport(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-
-void grpc_chttp2_list_add_unannounced_incoming_window_available(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-void grpc_chttp2_list_remove_unannounced_incoming_window_available(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-int grpc_chttp2_list_pop_unannounced_incoming_window_available(
-    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_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_closed_waiting_for_writing(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-int grpc_chttp2_list_pop_closed_waiting_for_writing(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global);
-
-grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
-    grpc_chttp2_transport_parsing *transport_parsing, uint32_t id);
-grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    uint32_t id);
-
-void grpc_chttp2_add_incoming_goaway(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    uint32_t 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_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-
-void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
-                                       grpc_closure **pclosure, int success);
-
-#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
-
-typedef enum {
-  GRPC_CHTTP2_FLOWCTL_MOVE,
-  GRPC_CHTTP2_FLOWCTL_CREDIT,
-  GRPC_CHTTP2_FLOWCTL_DEBIT
-} grpc_chttp2_flowctl_op;
-
-#define GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, transport, id1, id2, dst_context, \
-                                     dst_var, src_context, src_var)           \
-  do {                                                                        \
-    assert(id1 == id2);                                                       \
-    if (grpc_flowctl_trace) {                                                 \
-      grpc_chttp2_flowctl_trace(                                              \
-          __FILE__, __LINE__, phase, GRPC_CHTTP2_FLOWCTL_MOVE, #dst_context,  \
-          #dst_var, #src_context, #src_var, transport->is_client, id1,        \
-          dst_context->dst_var, src_context->src_var);                        \
-    }                                                                         \
-    dst_context->dst_var += src_context->src_var;                             \
-    src_context->src_var = 0;                                                 \
-  } while (0)
-
-#define GRPC_CHTTP2_FLOW_MOVE_STREAM(phase, transport, dst_context, dst_var, \
-                                     src_context, src_var)                   \
-  GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, transport, dst_context->id,            \
-                               src_context->id, dst_context, dst_var,        \
-                               src_context, src_var)
-#define GRPC_CHTTP2_FLOW_MOVE_TRANSPORT(phase, dst_context, dst_var,           \
-                                        src_context, src_var)                  \
-  GRPC_CHTTP2_FLOW_MOVE_COMMON(phase, dst_context, 0, 0, dst_context, dst_var, \
-                               src_context, src_var)
-
-#define GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, transport, id, dst_context,      \
-                                       dst_var, amount)                        \
-  do {                                                                         \
-    if (grpc_flowctl_trace) {                                                  \
-      grpc_chttp2_flowctl_trace(__FILE__, __LINE__, phase,                     \
-                                GRPC_CHTTP2_FLOWCTL_CREDIT, #dst_context,      \
-                                #dst_var, NULL, #amount, transport->is_client, \
-                                id, dst_context->dst_var, amount);             \
-    }                                                                          \
-    dst_context->dst_var += amount;                                            \
-  } while (0)
-
-#define GRPC_CHTTP2_FLOW_CREDIT_STREAM(phase, transport, dst_context, dst_var, \
-                                       amount)                                 \
-  GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, transport, dst_context->id,            \
-                                 dst_context, dst_var, amount)
-#define GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT(phase, dst_context, dst_var, amount) \
-  GRPC_CHTTP2_FLOW_CREDIT_COMMON(phase, dst_context, 0, dst_context, dst_var,  \
-                                 amount)
-
-#define GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, transport, id, dst_context,       \
-                                      dst_var, amount)                         \
-  do {                                                                         \
-    if (grpc_flowctl_trace) {                                                  \
-      grpc_chttp2_flowctl_trace(__FILE__, __LINE__, phase,                     \
-                                GRPC_CHTTP2_FLOWCTL_DEBIT, #dst_context,       \
-                                #dst_var, NULL, #amount, transport->is_client, \
-                                id, dst_context->dst_var, amount);             \
-    }                                                                          \
-    dst_context->dst_var -= amount;                                            \
-  } while (0)
-
-#define GRPC_CHTTP2_FLOW_DEBIT_STREAM(phase, transport, dst_context, dst_var, \
-                                      amount)                                 \
-  GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, transport, dst_context->id,            \
-                                dst_context, dst_var, amount)
-#define GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT(phase, dst_context, dst_var, amount) \
-  GRPC_CHTTP2_FLOW_DEBIT_COMMON(phase, dst_context, 0, dst_context, dst_var,  \
-                                amount)
-
-void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
-                               grpc_chttp2_flowctl_op op, const char *context1,
-                               const char *var1, const char *context2,
-                               const char *var2, int is_client,
-                               uint32_t stream_id, int64_t val1, int64_t val2);
-
-void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
-                             grpc_chttp2_transport_global *transport_global,
-                             grpc_chttp2_stream_global *stream,
-                             grpc_status_code status, gpr_slice *details);
-void grpc_chttp2_mark_stream_closed(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, int close_reads,
-    int close_writes);
-void grpc_chttp2_start_writing(grpc_exec_ctx *exec_ctx,
-                               grpc_chttp2_transport_global *transport_global);
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-#define GRPC_CHTTP2_STREAM_REF(stream_global, reason) \
-  grpc_chttp2_stream_ref(stream_global, reason)
-#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, reason) \
-  grpc_chttp2_stream_unref(exec_ctx, stream_global, reason)
-void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global,
-                            const char *reason);
-void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
-                              grpc_chttp2_stream_global *stream_global,
-                              const char *reason);
-#else
-#define GRPC_CHTTP2_STREAM_REF(stream_global, reason) \
-  grpc_chttp2_stream_ref(stream_global)
-#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, reason) \
-  grpc_chttp2_stream_unref(exec_ctx, stream_global)
-void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global);
-void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
-                              grpc_chttp2_stream_global *stream_global);
-#endif
-
-grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size,
-    uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue);
-void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
-                                           grpc_chttp2_incoming_byte_stream *bs,
-                                           gpr_slice slice);
-void grpc_chttp2_incoming_byte_stream_finished(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
-    int from_parsing_thread);
-
-void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
-                          grpc_chttp2_transport_parsing *parsing,
-                          const uint8_t *opaque_8bytes);
-
-/** add a ref to the stream and add it to the writable list;
-    ref will be dropped in writing.c */
-void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
-                                 grpc_chttp2_stream_global *stream_global);
-
-#endif
diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c
deleted file mode 100644
index 0516f39..0000000
--- a/src/core/transport/chttp2/parsing.c
+++ /dev/null
@@ -1,866 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/transport/chttp2/internal.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/profiling/timers.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 "src/core/transport/static_metadata.h"
-
-static int init_frame_parser(grpc_exec_ctx *exec_ctx,
-                             grpc_chttp2_transport_parsing *transport_parsing);
-static int init_header_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    int is_continuation);
-static int init_data_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static int init_rst_stream_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static int init_settings_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static int init_window_update_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static int init_ping_parser(grpc_exec_ctx *exec_ctx,
-                            grpc_chttp2_transport_parsing *transport_parsing);
-static int init_goaway_parser(grpc_exec_ctx *exec_ctx,
-                              grpc_chttp2_transport_parsing *transport_parsing);
-static int init_skip_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    int is_header);
-
-static int parse_frame_slice(grpc_exec_ctx *exec_ctx,
-                             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;
-
-  GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0);
-
-  transport_parsing->next_stream_id = transport_global->next_stream_id;
-  transport_parsing->last_sent_max_table_size =
-      transport_global->settings[GRPC_SENT_SETTINGS]
-                                [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE];
-
-  /* update the parsing view of incoming window */
-  while (grpc_chttp2_list_pop_unannounced_incoming_window_available(
-      transport_global, transport_parsing, &stream_global, &stream_parsing)) {
-    GRPC_CHTTP2_FLOW_MOVE_STREAM("parse", transport_parsing, stream_parsing,
-                                 incoming_window, stream_global,
-                                 unannounced_incoming_window_for_parse);
-  }
-
-  GPR_TIMER_END("grpc_chttp2_prepare_to_read", 0);
-}
-
-void grpc_chttp2_publish_reads(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_parsing *transport_parsing) {
-  grpc_chttp2_stream_global *stream_global;
-  grpc_chttp2_stream_parsing *stream_parsing;
-  int was_zero;
-  int is_zero;
-
-  /* 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;
-  }
-
-  /* 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(uint32_t));
-    transport_parsing->settings_ack_received = 0;
-    transport_global->sent_local_settings = 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(exec_ctx, transport_global,
-                                    (uint32_t)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 */
-  was_zero = transport_global->outgoing_window <= 0;
-  GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("parsed", transport_global, outgoing_window,
-                                  transport_parsing, outgoing_window);
-  is_zero = transport_global->outgoing_window <= 0;
-  if (was_zero && !is_zero) {
-    while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
-                                                     &stream_global)) {
-      grpc_chttp2_become_writable(transport_global, stream_global);
-    }
-  }
-
-  if (transport_parsing->incoming_window <
-      transport_global->connection_window_target * 3 / 4) {
-    int64_t announce_bytes = transport_global->connection_window_target -
-                             transport_parsing->incoming_window;
-    GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_global,
-                                      announce_incoming_window, announce_bytes);
-    GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing,
-                                      incoming_window, announce_bytes);
-  }
-
-  /* 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)) {
-    if (stream_parsing->seen_error) {
-      stream_global->seen_error = 1;
-      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-    }
-
-    /* update outgoing flow control window */
-    was_zero = stream_global->outgoing_window <= 0;
-    GRPC_CHTTP2_FLOW_MOVE_STREAM("parsed", transport_global, stream_global,
-                                 outgoing_window, stream_parsing,
-                                 outgoing_window);
-    is_zero = stream_global->outgoing_window <= 0;
-    if (was_zero && !is_zero) {
-      grpc_chttp2_become_writable(transport_global, stream_global);
-    }
-
-    stream_global->max_recv_bytes -= (uint32_t)GPR_MIN(
-        stream_global->max_recv_bytes, stream_parsing->received_bytes);
-    stream_parsing->received_bytes = 0;
-
-    /* publish incoming stream ops */
-    if (stream_global->incoming_frames.tail != NULL) {
-      stream_global->incoming_frames.tail->is_tail = 0;
-    }
-    if (stream_parsing->data_parser.incoming_frames.head != NULL) {
-      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-    }
-    grpc_chttp2_incoming_frame_queue_merge(
-        &stream_global->incoming_frames,
-        &stream_parsing->data_parser.incoming_frames);
-    if (stream_global->incoming_frames.tail != NULL) {
-      stream_global->incoming_frames.tail->is_tail = 1;
-    }
-
-    if (!stream_global->published_initial_metadata &&
-        stream_parsing->got_metadata_on_parse[0]) {
-      stream_parsing->got_metadata_on_parse[0] = 0;
-      stream_global->published_initial_metadata = 1;
-      GPR_SWAP(grpc_chttp2_incoming_metadata_buffer,
-               stream_parsing->metadata_buffer[0],
-               stream_global->received_initial_metadata);
-      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-    }
-    if (!stream_global->published_trailing_metadata &&
-        stream_parsing->got_metadata_on_parse[1]) {
-      stream_parsing->got_metadata_on_parse[1] = 0;
-      stream_global->published_trailing_metadata = 1;
-      GPR_SWAP(grpc_chttp2_incoming_metadata_buffer,
-               stream_parsing->metadata_buffer[1],
-               stream_global->received_trailing_metadata);
-      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-    }
-
-    if (stream_parsing->saw_rst_stream) {
-      if (stream_parsing->rst_stream_reason != GRPC_CHTTP2_NO_ERROR) {
-        grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status(
-            (grpc_chttp2_error_code)stream_parsing->rst_stream_reason);
-        char *status_details;
-        gpr_slice slice_details;
-        gpr_asprintf(&status_details, "Received RST_STREAM err=%d",
-                     stream_parsing->rst_stream_reason);
-        slice_details = gpr_slice_from_copied_string(status_details);
-        gpr_free(status_details);
-        grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global,
-                                status_code, &slice_details);
-      }
-      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
-                                     1, 1);
-    }
-
-    if (stream_parsing->received_close) {
-      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
-                                     1, 0);
-    }
-  }
-}
-
-int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
-                             grpc_chttp2_transport_parsing *transport_parsing,
-                             gpr_slice slice) {
-  uint8_t *beg = GPR_SLICE_START_PTR(slice);
-  uint8_t *end = GPR_SLICE_END_PTR(slice);
-  uint8_t *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)(uint8_t)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 = ((uint32_t)*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 |= ((uint32_t)*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 = (((uint32_t)*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 |= ((uint32_t)*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 |= ((uint32_t)*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 |= ((uint32_t)*cur);
-      transport_parsing->deframe_state = GRPC_DTS_FRAME;
-      if (!init_frame_parser(exec_ctx, 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(exec_ctx, 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 ((uint32_t)(end - cur) == transport_parsing->incoming_frame_size) {
-        if (!parse_frame_slice(exec_ctx, transport_parsing,
-                               gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
-                                                    (size_t)(end - beg)),
-                               1)) {
-          return 0;
-        }
-        transport_parsing->deframe_state = GRPC_DTS_FH_0;
-        transport_parsing->incoming_stream = NULL;
-        return 1;
-      } else if ((uint32_t)(end - cur) >
-                 transport_parsing->incoming_frame_size) {
-        size_t cur_offset = (size_t)(cur - beg);
-        if (!parse_frame_slice(
-                exec_ctx, transport_parsing,
-                gpr_slice_sub_no_ref(
-                    slice, cur_offset,
-                    cur_offset + transport_parsing->incoming_frame_size),
-                1)) {
-          return 0;
-        }
-        cur += transport_parsing->incoming_frame_size;
-        transport_parsing->incoming_stream = NULL;
-        goto dts_fh_0; /* loop */
-      } else {
-        if (!parse_frame_slice(exec_ctx, transport_parsing,
-                               gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
-                                                    (size_t)(end - beg)),
-                               0)) {
-          return 0;
-        }
-        transport_parsing->incoming_frame_size -= (uint32_t)(end - cur);
-        return 1;
-      }
-      GPR_UNREACHABLE_CODE(return 0);
-  }
-
-  GPR_UNREACHABLE_CODE(return 0);
-}
-
-static int init_frame_parser(grpc_exec_ctx *exec_ctx,
-                             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(exec_ctx, transport_parsing, 1);
-  }
-  switch (transport_parsing->incoming_frame_type) {
-    case GRPC_CHTTP2_FRAME_DATA:
-      return init_data_frame_parser(exec_ctx, transport_parsing);
-    case GRPC_CHTTP2_FRAME_HEADER:
-      return init_header_frame_parser(exec_ctx, 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(exec_ctx, transport_parsing);
-    case GRPC_CHTTP2_FRAME_SETTINGS:
-      return init_settings_frame_parser(exec_ctx, transport_parsing);
-    case GRPC_CHTTP2_FRAME_WINDOW_UPDATE:
-      return init_window_update_frame_parser(exec_ctx, transport_parsing);
-    case GRPC_CHTTP2_FRAME_PING:
-      return init_ping_parser(exec_ctx, transport_parsing);
-    case GRPC_CHTTP2_FRAME_GOAWAY:
-      return init_goaway_parser(exec_ctx, transport_parsing);
-    default:
-      gpr_log(GPR_ERROR, "Unknown frame type %02x",
-              transport_parsing->incoming_frame_type);
-      return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
-  }
-}
-
-static grpc_chttp2_parse_error skip_parser(
-    grpc_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    int is_header) {
-  if (is_header) {
-    uint8_t 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 =
-        (uint8_t)(is_eoh ? transport_parsing->header_eof : 0);
-  } else {
-    transport_parsing->parser = skip_parser;
-  }
-  return 1;
-}
-
-void grpc_chttp2_parsing_become_skip_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
-  init_skip_frame_parser(
-      exec_ctx, transport_parsing,
-      transport_parsing->parser == grpc_chttp2_header_parser_parse);
-}
-
-static grpc_chttp2_parse_error update_incoming_window(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing) {
-  uint32_t incoming_frame_size = transport_parsing->incoming_frame_size;
-  if (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 (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_FLOW_DEBIT_TRANSPORT("parse", transport_parsing, incoming_window,
-                                   incoming_frame_size);
-  GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", transport_parsing, stream_parsing,
-                                incoming_window, incoming_frame_size);
-  stream_parsing->received_bytes += 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_exec_ctx *exec_ctx, 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(exec_ctx, transport_parsing, 0);
-  if (err == GRPC_CHTTP2_PARSE_OK) {
-    err = update_incoming_window(exec_ctx, 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(exec_ctx, transport_parsing, 0);
-    case GRPC_CHTTP2_CONNECTION_ERROR:
-      return 0;
-  }
-  GPR_UNREACHABLE_CODE(return 0);
-}
-
-static void free_timeout(void *p) { gpr_free(p); }
-
-static void on_initial_header(void *tp, grpc_mdelem *md) {
-  grpc_chttp2_transport_parsing *transport_parsing = tp;
-  grpc_chttp2_stream_parsing *stream_parsing =
-      transport_parsing->incoming_stream;
-
-  GPR_TIMER_BEGIN("on_initial_header", 0);
-
-  GPR_ASSERT(stream_parsing);
-
-  GRPC_CHTTP2_IF_TRACING(gpr_log(
-      GPR_INFO, "HTTP:%d:HDR:%s: %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 == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
-    /* TODO(ctiller): check for a status like " 0" */
-    stream_parsing->seen_error = 1;
-  }
-
-  if (md->key == GRPC_MDSTR_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_TIMESPAN);
-      }
-      grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
-    }
-    grpc_chttp2_incoming_metadata_buffer_set_deadline(
-        &stream_parsing->metadata_buffer[0],
-        gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout));
-    GRPC_MDELEM_UNREF(md);
-  } else {
-    grpc_chttp2_incoming_metadata_buffer_add(
-        &stream_parsing->metadata_buffer[0], md);
-  }
-
-  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
-
-  GPR_TIMER_END("on_initial_header", 0);
-}
-
-static void on_trailing_header(void *tp, grpc_mdelem *md) {
-  grpc_chttp2_transport_parsing *transport_parsing = tp;
-  grpc_chttp2_stream_parsing *stream_parsing =
-      transport_parsing->incoming_stream;
-
-  GPR_TIMER_BEGIN("on_trailing_header", 0);
-
-  GPR_ASSERT(stream_parsing);
-
-  GRPC_CHTTP2_IF_TRACING(gpr_log(
-      GPR_INFO, "HTTP:%d:TRL:%s: %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 == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
-    /* TODO(ctiller): check for a status like " 0" */
-    stream_parsing->seen_error = 1;
-  }
-
-  grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->metadata_buffer[1],
-                                           md);
-
-  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
-
-  GPR_TIMER_END("on_trailing_header", 0);
-}
-
-static int init_header_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    int is_continuation) {
-  uint8_t is_eoh = (transport_parsing->incoming_frame_flags &
-                    GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0;
-  int via_accept = 0;
-  grpc_chttp2_stream_parsing *stream_parsing;
-
-  /* TODO(ctiller): when to increment header_frames_received? */
-
-  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(exec_ctx, 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(exec_ctx, 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(exec_ctx, 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(exec_ctx, transport_parsing, 1);
-    }
-    stream_parsing = transport_parsing->incoming_stream =
-        grpc_chttp2_parsing_accept_stream(
-            exec_ctx, 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(exec_ctx, 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(exec_ctx, transport_parsing, 1);
-  }
-  transport_parsing->parser = grpc_chttp2_header_parser_parse;
-  transport_parsing->parser_data = &transport_parsing->hpack_parser;
-  switch (stream_parsing->header_frames_received) {
-    case 0:
-      transport_parsing->hpack_parser.on_header = on_initial_header;
-      break;
-    case 1:
-      transport_parsing->hpack_parser.on_header = on_trailing_header;
-      break;
-    case 2:
-      gpr_log(GPR_ERROR, "too many header frames received");
-      return init_skip_frame_parser(exec_ctx, transport_parsing, 1);
-  }
-  transport_parsing->hpack_parser.on_header_user_data = transport_parsing;
-  transport_parsing->hpack_parser.is_boundary = is_eoh;
-  transport_parsing->hpack_parser.is_eof =
-      (uint8_t)(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_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx,
-                            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_exec_ctx *exec_ctx, 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(exec_ctx, 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_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx, 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;
-    grpc_chttp2_hptbl_set_max_bytes(
-        &transport_parsing->hpack_parser.table,
-        transport_parsing->last_sent_max_table_size);
-  }
-  transport_parsing->parser = grpc_chttp2_settings_parser_parse;
-  transport_parsing->parser_data = &transport_parsing->simple.settings;
-  return ok;
-}
-
-/*
-static int is_window_update_legal(int64_t window_update, int64_t window) {
-  return window + window_update < MAX_WINDOW;
-}
-*/
-
-static int parse_frame_slice(grpc_exec_ctx *exec_ctx,
-                             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(exec_ctx, 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(exec_ctx, 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_UNREACHABLE_CODE(return 0);
-}
diff --git a/src/core/transport/chttp2/status_conversion.c b/src/core/transport/chttp2/status_conversion.c
deleted file mode 100644
index bf214b0..0000000
--- a/src/core/transport/chttp2/status_conversion.c
+++ /dev/null
@@ -1,109 +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/transport/chttp2/status_conversion.h"
-
-int grpc_chttp2_grpc_status_to_http2_error(grpc_status_code status) {
-  switch (status) {
-    case GRPC_STATUS_OK:
-      return GRPC_CHTTP2_NO_ERROR;
-    case GRPC_STATUS_CANCELLED:
-      return GRPC_CHTTP2_CANCEL;
-    case GRPC_STATUS_RESOURCE_EXHAUSTED:
-      return GRPC_CHTTP2_ENHANCE_YOUR_CALM;
-    case GRPC_STATUS_PERMISSION_DENIED:
-      return GRPC_CHTTP2_INADEQUATE_SECURITY;
-    case GRPC_STATUS_UNAVAILABLE:
-      return GRPC_CHTTP2_REFUSED_STREAM;
-    default:
-      return GRPC_CHTTP2_INTERNAL_ERROR;
-  }
-}
-
-grpc_status_code grpc_chttp2_http2_error_to_grpc_status(
-    grpc_chttp2_error_code error) {
-  switch (error) {
-    case GRPC_CHTTP2_NO_ERROR:
-      /* should never be received */
-      return GRPC_STATUS_INTERNAL;
-    case GRPC_CHTTP2_CANCEL:
-      return GRPC_STATUS_CANCELLED;
-    case GRPC_CHTTP2_ENHANCE_YOUR_CALM:
-      return GRPC_STATUS_RESOURCE_EXHAUSTED;
-    case GRPC_CHTTP2_INADEQUATE_SECURITY:
-      return GRPC_STATUS_PERMISSION_DENIED;
-    case GRPC_CHTTP2_REFUSED_STREAM:
-      return GRPC_STATUS_UNAVAILABLE;
-    default:
-      return GRPC_STATUS_INTERNAL;
-  }
-}
-
-grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status) {
-  switch (status) {
-    /* these HTTP2 status codes are called out explicitly in status.proto */
-    case 200:
-      return GRPC_STATUS_OK;
-    case 400:
-      return GRPC_STATUS_INVALID_ARGUMENT;
-    case 401:
-      return GRPC_STATUS_UNAUTHENTICATED;
-    case 403:
-      return GRPC_STATUS_PERMISSION_DENIED;
-    case 404:
-      return GRPC_STATUS_NOT_FOUND;
-    case 409:
-      return GRPC_STATUS_ABORTED;
-    case 412:
-      return GRPC_STATUS_FAILED_PRECONDITION;
-    case 429:
-      return GRPC_STATUS_RESOURCE_EXHAUSTED;
-    case 499:
-      return GRPC_STATUS_CANCELLED;
-    case 500:
-      return GRPC_STATUS_UNKNOWN;
-    case 501:
-      return GRPC_STATUS_UNIMPLEMENTED;
-    case 503:
-      return GRPC_STATUS_UNAVAILABLE;
-    case 504:
-      return GRPC_STATUS_DEADLINE_EXCEEDED;
-    /* everything else is unknown */
-    default:
-      return GRPC_STATUS_UNKNOWN;
-  }
-}
-
-int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status) {
-  return 200;
-}
diff --git a/src/core/transport/chttp2/status_conversion.h b/src/core/transport/chttp2/status_conversion.h
deleted file mode 100644
index 0ec5b56..0000000
--- a/src/core/transport/chttp2/status_conversion.h
+++ /dev/null
@@ -1,50 +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_TRANSPORT_CHTTP2_STATUS_CONVERSION_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STATUS_CONVERSION_H
-
-#include <grpc/grpc.h>
-#include "src/core/transport/chttp2/http2_errors.h"
-
-/* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */
-grpc_chttp2_error_code grpc_chttp2_grpc_status_to_http2_error(
-    grpc_status_code status);
-grpc_status_code grpc_chttp2_http2_error_to_grpc_status(
-    grpc_chttp2_error_code error);
-
-/* Conversion of HTTP status codes (:status) to grpc status codes */
-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 */
diff --git a/src/core/transport/chttp2/stream_lists.c b/src/core/transport/chttp2/stream_lists.c
deleted file mode 100644
index 60fe735..0000000
--- a/src/core/transport/chttp2/stream_lists.c
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "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 bool 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);
-    return true;
-  } else {
-    return false;
-  }
-}
-
-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 {
-    t->lists[id].head = s;
-  }
-  t->lists[id].tail = s;
-  s->included[id] = 1;
-}
-
-static bool stream_list_add(grpc_chttp2_transport *t, grpc_chttp2_stream *s,
-                            grpc_chttp2_stream_list_id id) {
-  if (s->included[id]) {
-    return false;
-  }
-  stream_list_add_tail(t, s, id);
-  return true;
-}
-
-/* wrappers for specializations */
-
-bool grpc_chttp2_list_add_writable_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  GPR_ASSERT(stream_global->id != 0);
-  return 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);
-  if (r != 0) {
-    *stream_global = &stream->global;
-    *stream_writing = &stream->writing;
-  }
-  return r;
-}
-
-bool grpc_chttp2_list_remove_writable_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
-                                  STREAM_FROM_GLOBAL(stream_global),
-                                  GRPC_CHTTP2_LIST_WRITABLE);
-}
-
-void grpc_chttp2_list_add_writing_stream(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing *stream_writing) {
-  GPR_ASSERT(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);
-  if (r != 0) {
-    *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);
-  if (r != 0) {
-    *stream_global = &stream->global;
-    *stream_writing = &stream->writing;
-  }
-  return r;
-}
-
-void grpc_chttp2_list_add_unannounced_incoming_window_available(
-    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_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE);
-}
-
-void grpc_chttp2_list_remove_unannounced_incoming_window_available(
-    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_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE);
-}
-
-int grpc_chttp2_list_pop_unannounced_incoming_window_available(
-    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_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE);
-  if (r != 0) {
-    *stream_global = &stream->global;
-    *stream_parsing = &stream->parsing;
-  }
-  return r;
-}
-
-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);
-  if (r != 0) {
-    *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);
-  if (r != 0) {
-    *stream_global = &stream->global;
-  }
-  return r;
-}
-
-void grpc_chttp2_list_add_check_read_ops(
-    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_CHECK_READ_OPS);
-}
-
-int grpc_chttp2_list_pop_check_read_ops(
-    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_CHECK_READ_OPS);
-  if (r != 0) {
-    *stream_global = &stream->global;
-  }
-  return r;
-}
-
-void grpc_chttp2_list_add_writing_stalled_by_transport(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing *stream_writing) {
-  grpc_chttp2_stream *stream = STREAM_FROM_WRITING(stream_writing);
-  if (!stream->included[GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT]) {
-    GRPC_CHTTP2_STREAM_REF(&stream->global, "chttp2_writing_stalled");
-  }
-  stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), stream,
-                  GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT);
-}
-
-void grpc_chttp2_list_flush_writing_stalled_by_transport(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
-    bool is_window_available) {
-  grpc_chttp2_stream *stream;
-  grpc_chttp2_transport *transport = TRANSPORT_FROM_WRITING(transport_writing);
-  while (stream_list_pop(transport, &stream,
-                         GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) {
-    if (is_window_available) {
-      grpc_chttp2_become_writable(&transport->global, &stream->global);
-    } else {
-      grpc_chttp2_list_add_stalled_by_transport(transport_writing,
-                                                &stream->writing);
-    }
-    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &stream->global,
-                             "chttp2_writing_stalled");
-  }
-}
-
-void grpc_chttp2_list_add_stalled_by_transport(
-    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_STALLED_BY_TRANSPORT);
-}
-
-int grpc_chttp2_list_pop_stalled_by_transport(
-    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_STALLED_BY_TRANSPORT);
-  if (r != 0) {
-    *stream_global = &stream->global;
-  }
-  return r;
-}
-
-void grpc_chttp2_list_remove_stalled_by_transport(
-    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_STALLED_BY_TRANSPORT);
-}
-
-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);
-  if (r != 0) {
-    *stream_global = &stream->global;
-  }
-  return r;
-}
-
-void grpc_chttp2_list_add_closed_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_CLOSED_WAITING_FOR_WRITING);
-}
-
-int grpc_chttp2_list_pop_closed_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_CLOSED_WAITING_FOR_WRITING);
-  if (r != 0) {
-    *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
deleted file mode 100644
index 555a16f..0000000
--- a/src/core/transport/chttp2/stream_map.c
+++ /dev/null
@@ -1,197 +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/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) {
-  GPR_ASSERT(initial_capacity > 1);
-  map->keys = gpr_malloc(sizeof(uint32_t) * initial_capacity);
-  map->values = gpr_malloc(sizeof(void *) * initial_capacity);
-  map->count = 0;
-  map->free = 0;
-  map->capacity = initial_capacity;
-}
-
-void grpc_chttp2_stream_map_destroy(grpc_chttp2_stream_map *map) {
-  gpr_free(map->keys);
-  gpr_free(map->values);
-}
-
-static size_t compact(uint32_t *keys, void **values, size_t count) {
-  size_t i, out;
-
-  for (i = 0, out = 0; i < count; i++) {
-    if (values[i]) {
-      keys[out] = keys[i];
-      values[out] = values[i];
-      out++;
-    }
-  }
-
-  return out;
-}
-
-void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, uint32_t key,
-                                void *value) {
-  size_t count = map->count;
-  size_t capacity = map->capacity;
-  uint32_t *keys = map->keys;
-  void **values = map->values;
-
-  GPR_ASSERT(count == 0 || keys[count - 1] < key);
-  GPR_ASSERT(value);
-
-  if (count == capacity) {
-    if (map->free > capacity / 4) {
-      count = compact(keys, values, count);
-      map->free = 0;
-    } else {
-      /* resize when less than 25% of the table is free, because compaction
-         won't help much */
-      map->capacity = capacity = 3 * capacity / 2;
-      map->keys = keys = gpr_realloc(keys, capacity * sizeof(uint32_t));
-      map->values = values = gpr_realloc(values, capacity * sizeof(void *));
-    }
-  }
-
-  keys[count] = key;
-  values[count] = value;
-  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(uint32_t));
-    dst->values = gpr_realloc(dst->values, dst->capacity * sizeof(void *));
-  }
-  memcpy(dst->keys + dst->count, src->keys, src->count * sizeof(uint32_t));
-  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, uint32_t key) {
-  size_t min_idx = 0;
-  size_t max_idx = map->count;
-  size_t mid_idx;
-  uint32_t *keys = map->keys;
-  void **values = map->values;
-  uint32_t mid_key;
-
-  if (max_idx == 0) return NULL;
-
-  while (min_idx < max_idx) {
-    /* find the midpoint, avoiding overflow */
-    mid_idx = min_idx + ((max_idx - min_idx) / 2);
-    mid_key = keys[mid_idx];
-
-    if (mid_key < key) {
-      min_idx = mid_idx + 1;
-    } else if (mid_key > key) {
-      max_idx = mid_idx;
-    } else /* mid_key == key */
-    {
-      return &values[mid_idx];
-    }
-  }
-
-  return NULL;
-}
-
-void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, uint32_t key) {
-  void **pvalue = find(map, key);
-  void *out = NULL;
-  if (pvalue != NULL) {
-    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;
-}
-
-void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, uint32_t key) {
-  void **pvalue = find(map, key);
-  return pvalue != NULL ? *pvalue : NULL;
-}
-
-size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map) {
-  return map->count - map->free;
-}
-
-void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map,
-                                     void (*f)(void *user_data, uint32_t key,
-                                               void *value),
-                                     void *user_data) {
-  size_t i;
-
-  for (i = 0; i < map->count; i++) {
-    if (map->values[i]) {
-      f(user_data, map->keys[i], map->values[i]);
-    }
-  }
-}
diff --git a/src/core/transport/chttp2/stream_map.h b/src/core/transport/chttp2/stream_map.h
deleted file mode 100644
index 7a0e45f..0000000
--- a/src/core/transport/chttp2/stream_map.h
+++ /dev/null
@@ -1,84 +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_TRANSPORT_CHTTP2_STREAM_MAP_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_STREAM_MAP_H
-
-#include <grpc/support/port_platform.h>
-
-#include <stddef.h>
-
-/* Data structure to map a uint32_t to a data object (represented by a void*)
-
-   Represented as a sorted array of keys, and a corresponding array of values.
-   Lookups are performed with binary search.
-   Adds are restricted to strictly higher keys than previously seen (this is
-   guaranteed by http2). */
-typedef struct {
-  uint32_t *keys;
-  void **values;
-  size_t count;
-  size_t free;
-  size_t capacity;
-} grpc_chttp2_stream_map;
-
-void grpc_chttp2_stream_map_init(grpc_chttp2_stream_map *map,
-                                 size_t initial_capacity);
-void grpc_chttp2_stream_map_destroy(grpc_chttp2_stream_map *map);
-
-/* Add a new key: given http2 semantics, new keys must always be greater than
-   existing keys - this is asserted */
-void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, uint32_t key,
-                                void *value);
-
-/* Delete an existing key - returns the previous value of the key if it existed,
-   or NULL otherwise */
-void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, uint32_t 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, uint32_t key);
-
-/* How many (populated) entries are in the stream map? */
-size_t grpc_chttp2_stream_map_size(grpc_chttp2_stream_map *map);
-
-/* Callback on each stream */
-void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map,
-                                     void (*f)(void *user_data, uint32_t key,
-                                               void *value),
-                                     void *user_data);
-
-#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
deleted file mode 100644
index a6f7081..0000000
--- a/src/core/transport/chttp2/timeout_encoding.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/transport/chttp2/timeout_encoding.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include <grpc/support/port_platform.h>
-#include "src/core/support/string.h"
-
-static int64_t round_up(int64_t x, int64_t divisor) {
-  return (x / divisor + (x % divisor != 0)) * divisor;
-}
-
-/* round an integer up to the next value with three significant figures */
-static int64_t round_up_to_three_sig_figs(int64_t x) {
-  if (x < 1000) return x;
-  if (x < 10000) return round_up(x, 10);
-  if (x < 100000) return round_up(x, 100);
-  if (x < 1000000) return round_up(x, 1000);
-  if (x < 10000000) return round_up(x, 10000);
-  if (x < 100000000) return round_up(x, 100000);
-  if (x < 1000000000) return round_up(x, 1000000);
-  return round_up(x, 10000000);
-}
-
-/* encode our minimum viable timeout value */
-static void enc_tiny(char *buffer) { memcpy(buffer, "1n", 3); }
-
-static void enc_ext(char *buffer, int64_t value, char ext) {
-  int n = int64_ttoa(value, buffer);
-  buffer[n] = ext;
-  buffer[n + 1] = 0;
-}
-
-static void enc_seconds(char *buffer, int64_t sec) {
-  if (sec % 3600 == 0) {
-    enc_ext(buffer, sec / 3600, 'H');
-  } else if (sec % 60 == 0) {
-    enc_ext(buffer, sec / 60, 'M');
-  } else {
-    enc_ext(buffer, sec, 'S');
-  }
-}
-
-static void enc_nanos(char *buffer, int64_t x) {
-  x = round_up_to_three_sig_figs(x);
-  if (x < 100000) {
-    if (x % 1000 == 0) {
-      enc_ext(buffer, x / 1000, 'u');
-    } else {
-      enc_ext(buffer, x, 'n');
-    }
-  } else if (x < 100000000) {
-    if (x % 1000000 == 0) {
-      enc_ext(buffer, x / 1000000, 'm');
-    } else {
-      enc_ext(buffer, x / 1000, 'u');
-    }
-  } else if (x < 1000000000) {
-    enc_ext(buffer, x / 1000000, 'm');
-  } else {
-    /* note that this is only ever called with times of less than one second,
-       so if we reach here the time must have been rounded up to a whole second
-       (and no more) */
-    memcpy(buffer, "1S", 3);
-  }
-}
-
-static void enc_micros(char *buffer, int64_t x) {
-  x = round_up_to_three_sig_figs(x);
-  if (x < 100000) {
-    if (x % 1000 == 0) {
-      enc_ext(buffer, x / 1000, 'm');
-    } else {
-      enc_ext(buffer, x, 'u');
-    }
-  } else if (x < 100000000) {
-    if (x % 1000000 == 0) {
-      enc_ext(buffer, x / 1000000, 'S');
-    } else {
-      enc_ext(buffer, x / 1000, 'm');
-    }
-  } else {
-    enc_ext(buffer, x / 1000000, 'S');
-  }
-}
-
-void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer) {
-  if (timeout.tv_sec < 0) {
-    enc_tiny(buffer);
-  } else if (timeout.tv_sec == 0) {
-    enc_nanos(buffer, timeout.tv_nsec);
-  } else if (timeout.tv_sec < 1000 && timeout.tv_nsec != 0) {
-    enc_micros(buffer,
-               (int64_t)(timeout.tv_sec * 1000000) +
-                   (timeout.tv_nsec / 1000 + (timeout.tv_nsec % 1000 != 0)));
-  } else {
-    enc_seconds(buffer, timeout.tv_sec + (timeout.tv_nsec != 0));
-  }
-}
-
-static int is_all_whitespace(const char *p) {
-  while (*p == ' ') p++;
-  return *p == 0;
-}
-
-int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout) {
-  int32_t x = 0;
-  const uint8_t *p = (const uint8_t *)buffer;
-  int have_digit = 0;
-  /* skip whitespace */
-  for (; *p == ' '; p++)
-    ;
-  /* decode numeric part */
-  for (; *p >= '0' && *p <= '9'; p++) {
-    int32_t digit = (int32_t)(*p - (uint8_t)'0');
-    have_digit = 1;
-    /* spec allows max. 8 digits, but we allow values up to 1,000,000,000 */
-    if (x >= (100 * 1000 * 1000)) {
-      if (x != (100 * 1000 * 1000) || digit != 0) {
-        *timeout = gpr_inf_future(GPR_CLOCK_REALTIME);
-        return 1;
-      }
-    }
-    x = x * 10 + digit;
-  }
-  if (!have_digit) return 0;
-  /* skip whitespace */
-  for (; *p == ' '; p++)
-    ;
-  /* decode unit specifier */
-  switch (*p) {
-    case 'n':
-      *timeout = gpr_time_from_nanos(x, GPR_TIMESPAN);
-      break;
-    case 'u':
-      *timeout = gpr_time_from_micros(x, GPR_TIMESPAN);
-      break;
-    case 'm':
-      *timeout = gpr_time_from_millis(x, GPR_TIMESPAN);
-      break;
-    case 'S':
-      *timeout = gpr_time_from_seconds(x, GPR_TIMESPAN);
-      break;
-    case 'M':
-      *timeout = gpr_time_from_minutes(x, GPR_TIMESPAN);
-      break;
-    case 'H':
-      *timeout = gpr_time_from_hours(x, GPR_TIMESPAN);
-      break;
-    default:
-      return 0;
-  }
-  p++;
-  return is_all_whitespace((const char *)p);
-}
diff --git a/src/core/transport/chttp2/timeout_encoding.h b/src/core/transport/chttp2/timeout_encoding.h
deleted file mode 100644
index 9d8756e..0000000
--- a/src/core/transport/chttp2/timeout_encoding.h
+++ /dev/null
@@ -1,47 +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_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H
-
-#include "src/core/support/string.h"
-#include <grpc/support/time.h>
-
-#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
-
-/* Encode/decode timeouts to the GRPC over HTTP2 format;
-   encoding may round up arbitrarily */
-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 */
diff --git a/src/core/transport/chttp2/varint.c b/src/core/transport/chttp2/varint.c
deleted file mode 100644
index 1cc235e..0000000
--- a/src/core/transport/chttp2/varint.c
+++ /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.
- *
- */
-
-#include "src/core/transport/chttp2/varint.h"
-
-uint32_t grpc_chttp2_hpack_varint_length(uint32_t tail_value) {
-  if (tail_value < (1 << 7)) {
-    return 2;
-  } else if (tail_value < (1 << 14)) {
-    return 3;
-  } else if (tail_value < (1 << 21)) {
-    return 4;
-  } else if (tail_value < (1 << 28)) {
-    return 5;
-  } else {
-    return 6;
-  }
-}
-
-void grpc_chttp2_hpack_write_varint_tail(uint32_t tail_value, uint8_t* target,
-                                         uint32_t tail_length) {
-  switch (tail_length) {
-    case 5:
-      target[4] = (uint8_t)((tail_value >> 28) | 0x80);
-    case 4:
-      target[3] = (uint8_t)((tail_value >> 21) | 0x80);
-    case 3:
-      target[2] = (uint8_t)((tail_value >> 14) | 0x80);
-    case 2:
-      target[1] = (uint8_t)((tail_value >> 7) | 0x80);
-    case 1:
-      target[0] = (uint8_t)((tail_value) | 0x80);
-  }
-  target[tail_length - 1] &= 0x7f;
-}
diff --git a/src/core/transport/chttp2/varint.h b/src/core/transport/chttp2/varint.h
deleted file mode 100644
index 2d92b66..0000000
--- a/src/core/transport/chttp2/varint.h
+++ /dev/null
@@ -1,75 +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_TRANSPORT_CHTTP2_VARINT_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_VARINT_H
-
-#include <grpc/support/port_platform.h>
-
-/* Helpers for hpack varint encoding */
-
-/* length of a value that needs varint tail encoding (it's bigger than can be
-   bitpacked into the opcode byte) - returned value includes the length of the
-   opcode byte */
-uint32_t grpc_chttp2_hpack_varint_length(uint32_t tail_value);
-
-void grpc_chttp2_hpack_write_varint_tail(uint32_t tail_value, uint8_t* target,
-                                         uint32_t tail_length);
-
-/* maximum value that can be bitpacked with the opcode if the opcode has a
-   prefix
-   of length prefix_bits */
-#define GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits) \
-  ((uint32_t)((1 << (8 - (prefix_bits))) - 1))
-
-/* length required to bitpack a value */
-#define GRPC_CHTTP2_VARINT_LENGTH(n, prefix_bits) \
-  ((n) < GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits)   \
-       ? 1u                                       \
-       : grpc_chttp2_hpack_varint_length(         \
-             (n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits)))
-
-#define GRPC_CHTTP2_WRITE_VARINT(n, prefix_bits, prefix_or, target, length)   \
-  do {                                                                        \
-    uint8_t* tgt = target;                                                    \
-    if ((length) == 1u) {                                                     \
-      (tgt)[0] = (uint8_t)((prefix_or) | (n));                                \
-    } else {                                                                  \
-      (tgt)[0] =                                                              \
-          (prefix_or) | (uint8_t)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 */
diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c
deleted file mode 100644
index 107725c..0000000
--- a/src/core/transport/chttp2/writing.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/transport/chttp2/internal.h"
-
-#include <limits.h>
-
-#include <grpc/support/log.h>
-
-#include "src/core/profiling/timers.h"
-#include "src/core/transport/chttp2/http2_errors.h"
-
-static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
-                            grpc_chttp2_transport_writing *transport_writing);
-
-int grpc_chttp2_unlocking_check_writes(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_writing *transport_writing, int is_parsing) {
-  grpc_chttp2_stream_global *stream_global;
-  grpc_chttp2_stream_writing *stream_writing;
-
-  GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0);
-
-  /* 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);
-
-  grpc_chttp2_hpack_compressor_set_max_table_size(
-      &transport_writing->hpack_compressor,
-      transport_global->settings[GRPC_PEER_SETTINGS]
-                                [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
-
-  if (transport_global->dirtied_local_settings &&
-      !transport_global->sent_local_settings && !is_parsing) {
-    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;
-  }
-
-  GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
-                                  transport_global, outgoing_window);
-  bool is_window_available = transport_writing->outgoing_window > 0;
-  grpc_chttp2_list_flush_writing_stalled_by_transport(
-      exec_ctx, transport_writing, is_window_available);
-
-  /* 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)) {
-    bool sent_initial_metadata = stream_writing->sent_initial_metadata;
-    bool become_writable = false;
-
-    stream_writing->id = stream_global->id;
-    stream_writing->read_closed = stream_global->read_closed;
-
-    GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_writing, stream_writing,
-                                 outgoing_window, stream_global,
-                                 outgoing_window);
-
-    if (!sent_initial_metadata && stream_global->send_initial_metadata) {
-      stream_writing->send_initial_metadata =
-          stream_global->send_initial_metadata;
-      stream_global->send_initial_metadata = NULL;
-      become_writable = true;
-      sent_initial_metadata = true;
-    }
-    if (sent_initial_metadata) {
-      if (stream_global->send_message != NULL) {
-        gpr_slice hdr = gpr_slice_malloc(5);
-        uint8_t *p = GPR_SLICE_START_PTR(hdr);
-        uint32_t len = stream_global->send_message->length;
-        GPR_ASSERT(stream_writing->send_message == NULL);
-        p[0] = (stream_global->send_message->flags &
-                GRPC_WRITE_INTERNAL_COMPRESS) != 0;
-        p[1] = (uint8_t)(len >> 24);
-        p[2] = (uint8_t)(len >> 16);
-        p[3] = (uint8_t)(len >> 8);
-        p[4] = (uint8_t)(len);
-        gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, hdr);
-        if (stream_global->send_message->length > 0) {
-          stream_writing->send_message = stream_global->send_message;
-        } else {
-          stream_writing->send_message = NULL;
-        }
-        stream_writing->stream_fetched = 0;
-        stream_global->send_message = NULL;
-      }
-      if ((stream_writing->send_message != NULL ||
-           stream_writing->flow_controlled_buffer.length > 0) &&
-          stream_writing->outgoing_window > 0) {
-        if (transport_writing->outgoing_window > 0) {
-          become_writable = true;
-        } else {
-          grpc_chttp2_list_add_stalled_by_transport(transport_writing,
-                                                    stream_writing);
-        }
-      }
-      if (stream_global->send_trailing_metadata) {
-        stream_writing->send_trailing_metadata =
-            stream_global->send_trailing_metadata;
-        stream_global->send_trailing_metadata = NULL;
-        become_writable = true;
-      }
-    }
-
-    if (!stream_global->read_closed &&
-        stream_global->unannounced_incoming_window_for_writing > 1024) {
-      GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing,
-                                   announce_window, stream_global,
-                                   unannounced_incoming_window_for_writing);
-      become_writable = true;
-    }
-
-    if (become_writable) {
-      grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
-    } else {
-      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_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->announce_incoming_window > 0) {
-    uint32_t announced = (uint32_t)GPR_MIN(
-        transport_global->announce_incoming_window, UINT32_MAX);
-    GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_global,
-                                     announce_incoming_window, announced);
-    gpr_slice_buffer_add(&transport_writing->outbuf,
-                         grpc_chttp2_window_update_create(0, announced));
-  }
-
-  GPR_TIMER_END("grpc_chttp2_unlocking_check_writes", 0);
-
-  return transport_writing->outbuf.count > 0 ||
-         grpc_chttp2_list_have_writing_streams(transport_writing);
-}
-
-void grpc_chttp2_perform_writes(
-    grpc_exec_ctx *exec_ctx, 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(exec_ctx, transport_writing);
-
-  GPR_ASSERT(endpoint);
-
-  if (transport_writing->outbuf.count > 0) {
-    grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf,
-                        &transport_writing->done_cb);
-  } else {
-    grpc_exec_ctx_enqueue(exec_ctx, &transport_writing->done_cb, true, NULL);
-  }
-}
-
-static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
-                            grpc_chttp2_transport_writing *transport_writing) {
-  grpc_chttp2_stream_writing *stream_writing;
-
-  GPR_TIMER_BEGIN("finalize_outbuf", 0);
-
-  while (
-      grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) {
-    uint32_t max_outgoing =
-        (uint32_t)GPR_MIN(GRPC_CHTTP2_MAX_PAYLOAD_LENGTH,
-                          GPR_MIN(stream_writing->outgoing_window,
-                                  transport_writing->outgoing_window));
-    /* send initial metadata if it's available */
-    if (stream_writing->send_initial_metadata != NULL) {
-      grpc_chttp2_encode_header(
-          &transport_writing->hpack_compressor, stream_writing->id,
-          stream_writing->send_initial_metadata, 0, &transport_writing->outbuf);
-      stream_writing->send_initial_metadata = NULL;
-      stream_writing->sent_initial_metadata = 1;
-    }
-    /* send any window updates */
-    if (stream_writing->announce_window > 0 &&
-        stream_writing->send_initial_metadata == NULL) {
-      uint32_t announce = stream_writing->announce_window;
-      gpr_slice_buffer_add(
-          &transport_writing->outbuf,
-          grpc_chttp2_window_update_create(stream_writing->id,
-                                           stream_writing->announce_window));
-      GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing, stream_writing,
-                                    announce_window, announce);
-      stream_writing->announce_window = 0;
-    }
-    /* fetch any body bytes */
-    while (!stream_writing->fetching && stream_writing->send_message &&
-           stream_writing->flow_controlled_buffer.length < max_outgoing &&
-           stream_writing->stream_fetched <
-               stream_writing->send_message->length) {
-      if (grpc_byte_stream_next(exec_ctx, stream_writing->send_message,
-                                &stream_writing->fetching_slice, max_outgoing,
-                                &stream_writing->finished_fetch)) {
-        stream_writing->stream_fetched +=
-            GPR_SLICE_LENGTH(stream_writing->fetching_slice);
-        if (stream_writing->stream_fetched ==
-            stream_writing->send_message->length) {
-          stream_writing->send_message = NULL;
-        }
-        gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer,
-                             stream_writing->fetching_slice);
-      } else {
-        stream_writing->fetching = 1;
-      }
-    }
-    /* send any body bytes */
-    if (stream_writing->flow_controlled_buffer.length > 0) {
-      if (max_outgoing > 0) {
-        uint32_t send_bytes = (uint32_t)GPR_MIN(
-            max_outgoing, stream_writing->flow_controlled_buffer.length);
-        int is_last_data_frame =
-            stream_writing->send_message == NULL &&
-            send_bytes == stream_writing->flow_controlled_buffer.length;
-        int is_last_frame = is_last_data_frame &&
-                            stream_writing->send_trailing_metadata != NULL &&
-                            grpc_metadata_batch_is_empty(
-                                stream_writing->send_trailing_metadata);
-        grpc_chttp2_encode_data(
-            stream_writing->id, &stream_writing->flow_controlled_buffer,
-            send_bytes, is_last_frame, &transport_writing->outbuf);
-        GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing,
-                                      stream_writing, outgoing_window,
-                                      send_bytes);
-        GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_writing,
-                                         outgoing_window, send_bytes);
-        if (is_last_frame) {
-          stream_writing->send_trailing_metadata = NULL;
-          stream_writing->sent_trailing_metadata = 1;
-        }
-        if (is_last_data_frame) {
-          GPR_ASSERT(stream_writing->send_message == NULL);
-          stream_writing->sent_message = 1;
-        }
-      } else if (transport_writing->outgoing_window == 0) {
-        grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
-                                                          stream_writing);
-        grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
-      }
-    }
-    /* send trailing metadata if it's available and we're ready for it */
-    if (stream_writing->send_message == NULL &&
-        stream_writing->flow_controlled_buffer.length == 0 &&
-        stream_writing->send_trailing_metadata != NULL) {
-      if (grpc_metadata_batch_is_empty(
-              stream_writing->send_trailing_metadata)) {
-        grpc_chttp2_encode_data(stream_writing->id,
-                                &stream_writing->flow_controlled_buffer, 0, 1,
-                                &transport_writing->outbuf);
-      } else {
-        grpc_chttp2_encode_header(&transport_writing->hpack_compressor,
-                                  stream_writing->id,
-                                  stream_writing->send_trailing_metadata, 1,
-                                  &transport_writing->outbuf);
-      }
-      if (!transport_writing->is_client && !stream_writing->read_closed) {
-        gpr_slice_buffer_add(&transport_writing->outbuf,
-                             grpc_chttp2_rst_stream_create(
-                                 stream_writing->id, GRPC_CHTTP2_NO_ERROR));
-      }
-      stream_writing->send_trailing_metadata = NULL;
-      stream_writing->sent_trailing_metadata = 1;
-    }
-    /* if there's more to write, then loop, otherwise prepare to finish the
-     * write */
-    if ((stream_writing->flow_controlled_buffer.length > 0 ||
-         (stream_writing->send_message && !stream_writing->fetching)) &&
-        stream_writing->outgoing_window > 0) {
-      if (transport_writing->outgoing_window > 0) {
-        grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
-      } else {
-        grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
-                                                          stream_writing);
-        grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
-      }
-    } else {
-      grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
-    }
-  }
-
-  GPR_TIMER_END("finalize_outbuf", 0);
-}
-
-void grpc_chttp2_cleanup_writing(
-    grpc_exec_ctx *exec_ctx, 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_writing->sent_initial_metadata) {
-      grpc_chttp2_complete_closure_step(
-          exec_ctx, &stream_global->send_initial_metadata_finished, 1);
-    }
-    if (stream_writing->sent_message) {
-      GPR_ASSERT(stream_writing->send_message == NULL);
-      grpc_chttp2_complete_closure_step(
-          exec_ctx, &stream_global->send_message_finished, 1);
-      stream_writing->sent_message = 0;
-    }
-    if (stream_writing->sent_trailing_metadata) {
-      grpc_chttp2_complete_closure_step(
-          exec_ctx, &stream_global->send_trailing_metadata_finished, 1);
-    }
-    if (stream_writing->sent_trailing_metadata) {
-      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
-                                     !transport_global->is_client, 1);
-    }
-    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
-  }
-  gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf);
-}
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
deleted file mode 100644
index 1926525..0000000
--- a/src/core/transport/chttp2_transport.c
+++ /dev/null
@@ -1,1776 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/transport/chttp2_transport.h"
-
-#include <math.h>
-#include <stdio.h>
-#include <string.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/static_metadata.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
-
-int grpc_http_trace = 0;
-int grpc_flowctl_trace = 0;
-
-#define TRANSPORT_FROM_WRITING(tw)                                        \
-  ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
-                                                   writing)))
-
-#define TRANSPORT_FROM_PARSING(tw)                                        \
-  ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
-                                                   parsing)))
-
-#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 STREAM_FROM_PARSING(sg) \
-  ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, parsing)))
-
-static const grpc_transport_vtable vtable;
-
-static void lock(grpc_chttp2_transport *t);
-static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
-
-/* forward declarations of various callbacks that we'll build closures around */
-static void writing_action(grpc_exec_ctx *exec_ctx, void *t,
-                           bool 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,
-                         uint32_t value);
-
-/** Endpoint callback to process incoming data */
-static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success);
-
-/** Start disconnection chain */
-static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
-
-/** Perform a transport_op */
-static void perform_stream_op_locked(
-    grpc_exec_ctx *exec_ctx, 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_exec_ctx *exec_ctx,
-                            grpc_chttp2_transport_global *transport_global,
-                            grpc_chttp2_stream_global *stream_global,
-                            grpc_status_code status);
-
-static void close_from_api(grpc_exec_ctx *exec_ctx,
-                           grpc_chttp2_transport_global *transport_global,
-                           grpc_chttp2_stream_global *stream_global,
-                           grpc_status_code status,
-                           gpr_slice *optional_message);
-
-/** Add endpoint from this transport to pollset */
-static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t,
-                                  grpc_pollset *pollset);
-static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
-                                      grpc_chttp2_transport *t,
-                                      grpc_pollset_set *pollset_set);
-
-/** Start new streams that have been created if we can */
-static void maybe_start_some_streams(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global);
-
-static void connectivity_state_set(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_connectivity_state state, const char *reason);
-
-static void check_read_ops(grpc_exec_ctx *exec_ctx,
-                           grpc_chttp2_transport_global *transport_global);
-
-static void incoming_byte_stream_update_flow_control(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
-    size_t have_already);
-
-static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
-                                grpc_chttp2_stream_global *stream_global);
-
-/*******************************************************************************
- * CONSTRUCTION/DESTRUCTION/REFCOUNTING
- */
-
-static void destruct_transport(grpc_exec_ctx *exec_ctx,
-                               grpc_chttp2_transport *t) {
-  size_t i;
-
-  gpr_mu_lock(&t->mu);
-
-  GPR_ASSERT(t->ep == NULL);
-
-  gpr_slice_buffer_destroy(&t->global.qbuf);
-
-  gpr_slice_buffer_destroy(&t->writing.outbuf);
-  grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor);
-
-  gpr_slice_buffer_destroy(&t->parsing.qbuf);
-  gpr_slice_buffer_destroy(&t->read_buffer);
-  grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser);
-  grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser);
-
-  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->parsing_stream_map) == 0);
-  GPR_ASSERT(grpc_chttp2_stream_map_size(&t->new_stream_map) == 0);
-
-  grpc_chttp2_stream_map_destroy(&t->parsing_stream_map);
-  grpc_chttp2_stream_map_destroy(&t->new_stream_map);
-  grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker);
-
-  gpr_mu_unlock(&t->mu);
-  gpr_mu_destroy(&t->mu);
-
-  /* callback remaining pings: they're not allowed to call into the transpot,
-     and maybe they hold resources that need to be freed */
-  while (t->global.pings.next != &t->global.pings) {
-    grpc_chttp2_outstanding_ping *ping = t->global.pings.next;
-    grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, false, NULL);
-    ping->next->prev = ping->prev;
-    ping->prev->next = ping->next;
-    gpr_free(ping);
-  }
-
-  gpr_free(t->peer_string);
-  gpr_free(t);
-}
-
-#ifdef REFCOUNTING_DEBUG
-#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__)
-#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t, r, __FILE__, __LINE__)
-static void unref_transport(grpc_exec_ctx *exec_ctx, 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(exec_ctx, t);
-}
-
-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(cl, t, r) unref_transport(cl, t)
-static void unref_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
-  if (!gpr_unref(&t->refs)) return;
-  destruct_transport(exec_ctx, t);
-}
-
-static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
-#endif
-
-static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
-                           const grpc_channel_args *channel_args,
-                           grpc_endpoint *ep, uint8_t is_client) {
-  size_t i;
-  int j;
-
-  GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) ==
-             GRPC_CHTTP2_CLIENT_CONNECT_STRLEN);
-
-  memset(t, 0, sizeof(*t));
-
-  t->base.vtable = &vtable;
-  t->ep = ep;
-  /* one ref is for destroy, the other for when ep becomes NULL */
-  gpr_ref_init(&t->refs, 2);
-  /* ref is dropped at transport close() */
-  gpr_ref_init(&t->shutdown_ep_refs, 1);
-  gpr_mu_init(&t->mu);
-  t->peer_string = grpc_endpoint_get_peer(ep);
-  t->endpoint_reading = 1;
-  t->global.next_stream_id = is_client ? 1 : 2;
-  t->global.is_client = is_client;
-  t->writing.outgoing_window = DEFAULT_WINDOW;
-  t->parsing.incoming_window = DEFAULT_WINDOW;
-  t->global.stream_lookahead = 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.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,
-      is_client ? "client_transport" : "server_transport");
-
-  gpr_slice_buffer_init(&t->global.qbuf);
-
-  gpr_slice_buffer_init(&t->writing.outbuf);
-  grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor);
-  grpc_closure_init(&t->writing_action, writing_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);
-
-  grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing,
-                    &t->writing);
-  grpc_closure_init(&t->recv_data, recv_data, t);
-  gpr_slice_buffer_init(&t->read_buffer);
-
-  if (is_client) {
-    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->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 < 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->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->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 (is_client) {
-    push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
-    push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
-  }
-  push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW);
-
-  if (channel_args) {
-    for (i = 0; i < channel_args->num_args; i++) {
-      if (0 ==
-          strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) {
-        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) {
-          gpr_log(GPR_ERROR, "%s: must be an integer",
-                  GRPC_ARG_MAX_CONCURRENT_STREAMS);
-        } else {
-          push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
-                       (uint32_t)channel_args->args[i].value.integer);
-        }
-      } else if (0 == strcmp(channel_args->args[i].key,
-                             GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) {
-        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->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->global.next_stream_id & 1,
-                  is_client ? "client" : "server");
-        } else {
-          t->global.next_stream_id =
-              (uint32_t)channel_args->args[i].value.integer;
-        }
-      } else if (0 == strcmp(channel_args->args[i].key,
-                             GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES)) {
-        if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
-          gpr_log(GPR_ERROR, "%s: must be an integer",
-                  GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
-        } else if (channel_args->args[i].value.integer <= 5) {
-          gpr_log(GPR_ERROR, "%s: must be at least 5",
-                  GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
-        } else {
-          t->global.stream_lookahead =
-              (uint32_t)channel_args->args[i].value.integer;
-        }
-      } else if (0 == strcmp(channel_args->args[i].key,
-                             GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER)) {
-        if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
-          gpr_log(GPR_ERROR, "%s: must be an integer",
-                  GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
-        } else if (channel_args->args[i].value.integer < 0) {
-          gpr_log(GPR_ERROR, "%s: must be non-negative",
-                  GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
-        } else {
-          push_setting(t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
-                       (uint32_t)channel_args->args[i].value.integer);
-        }
-      } else if (0 == strcmp(channel_args->args[i].key,
-                             GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) {
-        if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
-          gpr_log(GPR_ERROR, "%s: must be an integer",
-                  GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
-        } else if (channel_args->args[i].value.integer < 0) {
-          gpr_log(GPR_ERROR, "%s: must be non-negative",
-                  GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
-        } else {
-          grpc_chttp2_hpack_compressor_set_max_usable_size(
-              &t->writing.hpack_compressor,
-              (uint32_t)channel_args->args[i].value.integer);
-        }
-      }
-    }
-  }
-}
-
-static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
-  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-
-  lock(t);
-  t->destroying = 1;
-  drop_connection(exec_ctx, t);
-  unlock(exec_ctx, t);
-
-  UNREF_TRANSPORT(exec_ctx, t, "destroy");
-}
-
-/** block grpc_endpoint_shutdown being called until a paired
-    allow_endpoint_shutdown is made */
-static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) {
-  GPR_ASSERT(t->ep);
-  gpr_ref(&t->shutdown_ep_refs);
-}
-
-static void allow_endpoint_shutdown_locked(grpc_exec_ctx *exec_ctx,
-                                           grpc_chttp2_transport *t) {
-  if (gpr_unref(&t->shutdown_ep_refs)) {
-    if (t->ep) {
-      grpc_endpoint_shutdown(exec_ctx, t->ep);
-    }
-  }
-}
-
-static void allow_endpoint_shutdown_unlocked(grpc_exec_ctx *exec_ctx,
-                                             grpc_chttp2_transport *t) {
-  if (gpr_unref(&t->shutdown_ep_refs)) {
-    gpr_mu_lock(&t->mu);
-    if (t->ep) {
-      grpc_endpoint_shutdown(exec_ctx, t->ep);
-    }
-    gpr_mu_unlock(&t->mu);
-  }
-}
-
-static void destroy_endpoint(grpc_exec_ctx *exec_ctx,
-                             grpc_chttp2_transport *t) {
-  grpc_endpoint_destroy(exec_ctx, t->ep);
-  t->ep = NULL;
-  /* safe because we'll still have the ref for write */
-  UNREF_TRANSPORT(exec_ctx, t, "disconnect");
-}
-
-static void close_transport_locked(grpc_exec_ctx *exec_ctx,
-                                   grpc_chttp2_transport *t) {
-  if (!t->closed) {
-    t->closed = 1;
-    connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_FATAL_FAILURE,
-                           "close_transport");
-    if (t->ep) {
-      allow_endpoint_shutdown_locked(exec_ctx, t);
-    }
-
-    /* flush writable stream list to avoid dangling references */
-    grpc_chttp2_stream_global *stream_global;
-    grpc_chttp2_stream_writing *stream_writing;
-    while (grpc_chttp2_list_pop_writable_stream(
-        &t->global, &t->writing, &stream_global, &stream_writing)) {
-      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
-    }
-  }
-}
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global,
-                            const char *reason) {
-  grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount, reason);
-}
-void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
-                              grpc_chttp2_stream_global *stream_global,
-                              const char *reason) {
-  grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount,
-                    reason);
-}
-#else
-void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global) {
-  grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount);
-}
-void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
-                              grpc_chttp2_stream_global *stream_global) {
-  grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount);
-}
-#endif
-
-static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                       grpc_stream *gs, grpc_stream_refcount *refcount,
-                       const void *server_data) {
-  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-  grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
-
-  memset(s, 0, sizeof(*s));
-
-  s->refcount = refcount;
-  GRPC_CHTTP2_STREAM_REF(&s->global, "chttp2");
-
-  grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[0]);
-  grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[1]);
-  grpc_chttp2_incoming_metadata_buffer_init(
-      &s->global.received_initial_metadata);
-  grpc_chttp2_incoming_metadata_buffer_init(
-      &s->global.received_trailing_metadata);
-  grpc_chttp2_data_parser_init(&s->parsing.data_parser);
-  gpr_slice_buffer_init(&s->writing.flow_controlled_buffer);
-
-  REF_TRANSPORT(t, "stream");
-
-  lock(t);
-  grpc_chttp2_register_stream(t, s);
-  if (server_data) {
-    GPR_ASSERT(t->parsing_active);
-    s->global.id = (uint32_t)(uintptr_t)server_data;
-    s->parsing.id = s->global.id;
-    s->global.outgoing_window =
-        t->global.settings[GRPC_PEER_SETTINGS]
-                          [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
-    s->parsing.incoming_window = s->global.max_recv_bytes =
-        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;
-  }
-  unlock(exec_ctx, t);
-
-  return 0;
-}
-
-static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                           grpc_stream *gs) {
-  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-  grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
-  int i;
-  grpc_byte_stream *bs;
-
-  GPR_TIMER_BEGIN("destroy_stream", 0);
-
-  gpr_mu_lock(&t->mu);
-
-  GPR_ASSERT((s->global.write_closed && s->global.read_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(exec_ctx, t);
-  }
-  if (!t->parsing_active && s->global.id) {
-    GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
-                                           s->global.id) == NULL);
-  }
-
-  grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global,
-                                                                &s->global);
-  grpc_chttp2_list_remove_stalled_by_transport(&t->global, &s->global);
-
-  gpr_mu_unlock(&t->mu);
-
-  for (i = 0; i < STREAM_LIST_COUNT; i++) {
-    if (s->included[i]) {
-      gpr_log(GPR_ERROR, "%s stream %d still included in list %d",
-              t->global.is_client ? "client" : "server", s->global.id, i);
-      abort();
-    }
-  }
-
-  while (
-      (bs = grpc_chttp2_incoming_frame_queue_pop(&s->global.incoming_frames))) {
-    grpc_byte_stream_destroy(exec_ctx, bs);
-  }
-
-  GPR_ASSERT(s->global.send_initial_metadata_finished == NULL);
-  GPR_ASSERT(s->global.send_message_finished == NULL);
-  GPR_ASSERT(s->global.send_trailing_metadata_finished == NULL);
-  GPR_ASSERT(s->global.recv_initial_metadata_ready == NULL);
-  GPR_ASSERT(s->global.recv_message_ready == NULL);
-  GPR_ASSERT(s->global.recv_trailing_metadata_finished == NULL);
-  grpc_chttp2_data_parser_destroy(exec_ctx, &s->parsing.data_parser);
-  grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[0]);
-  grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[1]);
-  grpc_chttp2_incoming_metadata_buffer_destroy(
-      &s->global.received_initial_metadata);
-  grpc_chttp2_incoming_metadata_buffer_destroy(
-      &s->global.received_trailing_metadata);
-  gpr_slice_buffer_destroy(&s->writing.flow_controlled_buffer);
-
-  UNREF_TRANSPORT(exec_ctx, t, "stream");
-
-  GPR_TIMER_END("destroy_stream", 0);
-}
-
-grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
-    grpc_chttp2_transport_parsing *transport_parsing, uint32_t 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;
-}
-
-grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    uint32_t 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(exec_ctx,
-                                    t->channel_callback.accept_stream_user_data,
-                                    &t->base, (void *)(uintptr_t)id);
-  t->accepting_stream = NULL;
-  return &accepting->parsing;
-}
-
-/*******************************************************************************
- * LOCK MANAGEMENT
- */
-
-/* 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(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
-
-static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
-  GPR_TIMER_BEGIN("unlock", 0);
-  if (!t->writing_active && !t->closed &&
-      grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing,
-                                         t->parsing_active)) {
-    t->writing_active = 1;
-    REF_TRANSPORT(t, "writing");
-    grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL);
-    prevent_endpoint_shutdown(t);
-  }
-  check_read_ops(exec_ctx, &t->global);
-
-  gpr_mu_unlock(&t->mu);
-  GPR_TIMER_END("unlock", 0);
-}
-
-/*******************************************************************************
- * OUTPUT PROCESSING
- */
-
-void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
-                                 grpc_chttp2_stream_global *stream_global) {
-  if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed &&
-      grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) {
-    GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
-  }
-}
-
-static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
-                         uint32_t value) {
-  const grpc_chttp2_setting_parameters *sp =
-      &grpc_chttp2_settings_parameters[id];
-  uint32_t use_value = GPR_CLAMP(value, sp->min_value, sp->max_value);
-  if (use_value != value) {
-    gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name,
-            value, use_value);
-  }
-  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;
-  }
-}
-
-void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
-                                   void *transport_writing_ptr, bool success) {
-  grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr;
-  grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
-  grpc_chttp2_stream_global *stream_global;
-
-  GPR_TIMER_BEGIN("grpc_chttp2_terminate_writing", 0);
-
-  lock(t);
-
-  allow_endpoint_shutdown_locked(exec_ctx, t);
-
-  if (!success) {
-    drop_connection(exec_ctx, t);
-  }
-
-  grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
-
-  while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
-                                                         &stream_global)) {
-    fail_pending_writes(exec_ctx, stream_global);
-    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
-  }
-
-  /* leave the writing flag up on shutdown to prevent further writes in unlock()
-     from starting */
-  t->writing_active = 0;
-  if (t->ep && !t->endpoint_reading) {
-    destroy_endpoint(exec_ctx, t);
-  }
-
-  unlock(exec_ctx, t);
-
-  UNREF_TRANSPORT(exec_ctx, t, "writing");
-
-  GPR_TIMER_END("grpc_chttp2_terminate_writing", 0);
-}
-
-static void writing_action(grpc_exec_ctx *exec_ctx, void *gt,
-                           bool iomgr_success_ignored) {
-  grpc_chttp2_transport *t = gt;
-  GPR_TIMER_BEGIN("writing_action", 0);
-  grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep);
-  GPR_TIMER_END("writing_action", 0);
-}
-
-void grpc_chttp2_add_incoming_goaway(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    uint32_t 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(exec_ctx, transport_global, GRPC_CHANNEL_FATAL_FAILURE,
-                         "got_goaway");
-}
-
-static void maybe_start_some_streams(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global) {
-  grpc_chttp2_stream_global *stream_global;
-  uint32_t stream_incoming_window;
-  /* 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)) {
-    /* safe since we can't (legally) be parsing this stream yet */
-    grpc_chttp2_stream_parsing *stream_parsing =
-        &STREAM_FROM_GLOBAL(stream_global)->parsing;
-    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 = stream_parsing->id = transport_global->next_stream_id;
-    transport_global->next_stream_id += 2;
-
-    if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
-      connectivity_state_set(exec_ctx, transport_global,
-                             GRPC_CHANNEL_TRANSIENT_FAILURE,
-                             "no_more_stream_ids");
-    }
-
-    stream_global->outgoing_window =
-        transport_global->settings[GRPC_PEER_SETTINGS]
-                                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
-    stream_parsing->incoming_window = stream_incoming_window =
-        transport_global->settings[GRPC_SENT_SETTINGS]
-                                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
-    stream_global->max_recv_bytes =
-        GPR_MAX(stream_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_become_writable(transport_global, stream_global);
-  }
-  /* cancel out streams that will never be started */
-  while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
-         grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
-                                                      &stream_global)) {
-    cancel_from_api(exec_ctx, transport_global, stream_global,
-                    GRPC_STATUS_UNAVAILABLE);
-  }
-}
-
-static grpc_closure *add_closure_barrier(grpc_closure *closure) {
-  closure->final_data += 2;
-  return closure;
-}
-
-void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
-                                       grpc_closure **pclosure, int success) {
-  grpc_closure *closure = *pclosure;
-  if (closure == NULL) {
-    return;
-  }
-  closure->final_data -= 2;
-  if (!success) {
-    closure->final_data |= 1;
-  }
-  if (closure->final_data < 2) {
-    grpc_exec_ctx_enqueue(exec_ctx, closure, closure->final_data == 0, NULL);
-  }
-  *pclosure = NULL;
-}
-
-static int contains_non_ok_status(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_metadata_batch *batch) {
-  grpc_linked_mdelem *l;
-  for (l = batch->list.head; l; l = l->next) {
-    if (l->md->key == GRPC_MDSTR_GRPC_STATUS &&
-        l->md != GRPC_MDELEM_GRPC_STATUS_0) {
-      return 1;
-    }
-  }
-  return 0;
-}
-
-static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {}
-
-static void perform_stream_op_locked(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
-  grpc_closure *on_complete;
-
-  GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
-
-  on_complete = op->on_complete;
-  if (on_complete == NULL) {
-    on_complete = grpc_closure_create(do_nothing, NULL);
-  }
-  /* use final_data as a barrier until enqueue time; the inital counter is
-     dropped at the end of this function */
-  on_complete->final_data = 2;
-
-  if (op->cancel_with_status != GRPC_STATUS_OK) {
-    cancel_from_api(exec_ctx, transport_global, stream_global,
-                    op->cancel_with_status);
-  }
-
-  if (op->close_with_status != GRPC_STATUS_OK) {
-    close_from_api(exec_ctx, transport_global, stream_global,
-                   op->close_with_status, op->optional_close_message);
-  }
-
-  if (op->send_initial_metadata != NULL) {
-    GPR_ASSERT(stream_global->send_initial_metadata_finished == NULL);
-    stream_global->send_initial_metadata_finished =
-        add_closure_barrier(on_complete);
-    stream_global->send_initial_metadata = op->send_initial_metadata;
-    if (contains_non_ok_status(transport_global, op->send_initial_metadata)) {
-      stream_global->seen_error = 1;
-      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-    }
-    if (!stream_global->write_closed) {
-      if (transport_global->is_client) {
-        GPR_ASSERT(stream_global->id == 0);
-        grpc_chttp2_list_add_waiting_for_concurrency(transport_global,
-                                                     stream_global);
-        maybe_start_some_streams(exec_ctx, transport_global);
-      } else {
-        GPR_ASSERT(stream_global->id != 0);
-        grpc_chttp2_become_writable(transport_global, stream_global);
-      }
-    } else {
-      grpc_chttp2_complete_closure_step(
-          exec_ctx, &stream_global->send_initial_metadata_finished, 0);
-    }
-  }
-
-  if (op->send_message != NULL) {
-    GPR_ASSERT(stream_global->send_message_finished == NULL);
-    GPR_ASSERT(stream_global->send_message == NULL);
-    stream_global->send_message_finished = add_closure_barrier(on_complete);
-    if (stream_global->write_closed) {
-      grpc_chttp2_complete_closure_step(
-          exec_ctx, &stream_global->send_message_finished, 0);
-    } else if (stream_global->id != 0) {
-      stream_global->send_message = op->send_message;
-      grpc_chttp2_become_writable(transport_global, stream_global);
-    }
-  }
-
-  if (op->send_trailing_metadata != NULL) {
-    GPR_ASSERT(stream_global->send_trailing_metadata_finished == NULL);
-    stream_global->send_trailing_metadata_finished =
-        add_closure_barrier(on_complete);
-    stream_global->send_trailing_metadata = op->send_trailing_metadata;
-    if (contains_non_ok_status(transport_global, op->send_trailing_metadata)) {
-      stream_global->seen_error = 1;
-      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-    }
-    if (stream_global->write_closed) {
-      grpc_chttp2_complete_closure_step(
-          exec_ctx, &stream_global->send_trailing_metadata_finished,
-          grpc_metadata_batch_is_empty(op->send_trailing_metadata));
-    } else if (stream_global->id != 0) {
-      /* TODO(ctiller): check if there's flow control for any outstanding
-         bytes before going writable */
-      grpc_chttp2_become_writable(transport_global, stream_global);
-    }
-  }
-
-  if (op->recv_initial_metadata != NULL) {
-    GPR_ASSERT(stream_global->recv_initial_metadata_ready == NULL);
-    stream_global->recv_initial_metadata_ready =
-        op->recv_initial_metadata_ready;
-    stream_global->recv_initial_metadata = op->recv_initial_metadata;
-    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-  }
-
-  if (op->recv_message != NULL) {
-    GPR_ASSERT(stream_global->recv_message_ready == NULL);
-    stream_global->recv_message_ready = op->recv_message_ready;
-    stream_global->recv_message = op->recv_message;
-    if (stream_global->id != 0 &&
-        (stream_global->incoming_frames.head == NULL ||
-         stream_global->incoming_frames.head->is_tail)) {
-      incoming_byte_stream_update_flow_control(
-          transport_global, stream_global, transport_global->stream_lookahead,
-          0);
-    }
-    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-  }
-
-  if (op->recv_trailing_metadata != NULL) {
-    GPR_ASSERT(stream_global->recv_trailing_metadata_finished == NULL);
-    stream_global->recv_trailing_metadata_finished =
-        add_closure_barrier(on_complete);
-    stream_global->recv_trailing_metadata = op->recv_trailing_metadata;
-    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-  }
-
-  grpc_chttp2_complete_closure_step(exec_ctx, &on_complete, 1);
-
-  GPR_TIMER_END("perform_stream_op_locked", 0);
-}
-
-static void perform_stream_op(grpc_exec_ctx *exec_ctx, 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(exec_ctx, &t->global, &s->global, op);
-  unlock(exec_ctx, t);
-}
-
-static void send_ping_locked(grpc_chttp2_transport *t, grpc_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] = (uint8_t)((t->global.ping_counter >> 56) & 0xff);
-  p->id[1] = (uint8_t)((t->global.ping_counter >> 48) & 0xff);
-  p->id[2] = (uint8_t)((t->global.ping_counter >> 40) & 0xff);
-  p->id[3] = (uint8_t)((t->global.ping_counter >> 32) & 0xff);
-  p->id[4] = (uint8_t)((t->global.ping_counter >> 24) & 0xff);
-  p->id[5] = (uint8_t)((t->global.ping_counter >> 16) & 0xff);
-  p->id[6] = (uint8_t)((t->global.ping_counter >> 8) & 0xff);
-  p->id[7] = (uint8_t)(t->global.ping_counter & 0xff);
-  p->on_recv = on_recv;
-  gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
-}
-
-void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
-                          grpc_chttp2_transport_parsing *transport_parsing,
-                          const uint8_t *opaque_8bytes) {
-  grpc_chttp2_outstanding_ping *ping;
-  grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
-  grpc_chttp2_transport_global *transport_global = &t->global;
-  lock(t);
-  for (ping = transport_global->pings.next; ping != &transport_global->pings;
-       ping = ping->next) {
-    if (0 == memcmp(opaque_8bytes, ping->id, 8)) {
-      grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, true, NULL);
-      ping->next->prev = ping->prev;
-      ping->prev->next = ping->next;
-      gpr_free(ping);
-      break;
-    }
-  }
-  unlock(exec_ctx, t);
-}
-
-static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
-                                        grpc_chttp2_transport *t,
-                                        grpc_transport_op *op) {
-  bool close_transport = false;
-
-  grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
-
-  if (op->on_connectivity_state_change != NULL) {
-    grpc_connectivity_state_notify_on_state_change(
-        exec_ctx, &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,
-        (uint32_t)grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
-        gpr_slice_ref(*op->goaway_message), &t->global.qbuf);
-    close_transport = !grpc_chttp2_has_streams(t);
-  }
-
-  if (op->set_accept_stream) {
-    t->channel_callback.accept_stream = op->set_accept_stream_fn;
-    t->channel_callback.accept_stream_user_data =
-        op->set_accept_stream_user_data;
-  }
-
-  if (op->bind_pollset) {
-    add_to_pollset_locked(exec_ctx, t, op->bind_pollset);
-  }
-
-  if (op->bind_pollset_set) {
-    add_to_pollset_set_locked(exec_ctx, t, op->bind_pollset_set);
-  }
-
-  if (op->send_ping) {
-    send_ping_locked(t, op->send_ping);
-  }
-
-  if (op->disconnect) {
-    close_transport_locked(exec_ctx, t);
-  }
-
-  if (close_transport) {
-    close_transport_locked(exec_ctx, t);
-  }
-}
-
-static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                                 grpc_transport_op *op) {
-  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-
-  lock(t);
-
-  /* If there's a set_accept_stream ensure that we're not parsing
-     to avoid changing things out from underneath */
-  if (t->parsing_active && op->set_accept_stream) {
-    GPR_ASSERT(t->post_parsing_op == NULL);
-    t->post_parsing_op = gpr_malloc(sizeof(*op));
-    memcpy(t->post_parsing_op, op, sizeof(*op));
-  } else {
-    perform_transport_op_locked(exec_ctx, t, op);
-  }
-
-  unlock(exec_ctx, t);
-}
-
-/*******************************************************************************
- * INPUT PROCESSING
- */
-
-static void check_read_ops(grpc_exec_ctx *exec_ctx,
-                           grpc_chttp2_transport_global *transport_global) {
-  grpc_chttp2_stream_global *stream_global;
-  grpc_byte_stream *bs;
-  while (
-      grpc_chttp2_list_pop_check_read_ops(transport_global, &stream_global)) {
-    if (stream_global->recv_initial_metadata_ready != NULL &&
-        stream_global->published_initial_metadata) {
-      grpc_chttp2_incoming_metadata_buffer_publish(
-          &stream_global->received_initial_metadata,
-          stream_global->recv_initial_metadata);
-      grpc_exec_ctx_enqueue(
-          exec_ctx, stream_global->recv_initial_metadata_ready, true, NULL);
-      stream_global->recv_initial_metadata_ready = NULL;
-    }
-    if (stream_global->recv_message_ready != NULL) {
-      while (stream_global->seen_error &&
-             (bs = grpc_chttp2_incoming_frame_queue_pop(
-                  &stream_global->incoming_frames)) != NULL) {
-        grpc_byte_stream_destroy(exec_ctx, bs);
-      }
-      if (stream_global->incoming_frames.head != NULL) {
-        *stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop(
-            &stream_global->incoming_frames);
-        GPR_ASSERT(*stream_global->recv_message != NULL);
-        grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true,
-                              NULL);
-        stream_global->recv_message_ready = NULL;
-      } else if (stream_global->published_trailing_metadata) {
-        *stream_global->recv_message = NULL;
-        grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true,
-                              NULL);
-        stream_global->recv_message_ready = NULL;
-      }
-    }
-    if (stream_global->recv_trailing_metadata_finished != NULL &&
-        stream_global->read_closed && stream_global->write_closed) {
-      while (stream_global->seen_error &&
-             (bs = grpc_chttp2_incoming_frame_queue_pop(
-                  &stream_global->incoming_frames)) != NULL) {
-        grpc_byte_stream_destroy(exec_ctx, bs);
-      }
-      if (stream_global->incoming_frames.head == NULL) {
-        grpc_chttp2_incoming_metadata_buffer_publish(
-            &stream_global->received_trailing_metadata,
-            stream_global->recv_trailing_metadata);
-        grpc_chttp2_complete_closure_step(
-            exec_ctx, &stream_global->recv_trailing_metadata_finished, 1);
-      }
-    }
-  }
-}
-
-static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
-                          uint32_t 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);
-  }
-  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(exec_ctx, &t->parsing);
-  }
-  if (s->parsing.data_parser.parsing_frame != NULL) {
-    grpc_chttp2_incoming_byte_stream_finished(
-        exec_ctx, s->parsing.data_parser.parsing_frame, 0, 0);
-    s->parsing.data_parser.parsing_frame = NULL;
-  }
-
-  if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
-    close_transport_locked(exec_ctx, t);
-  }
-  if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) {
-    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing");
-  }
-
-  new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) +
-                     grpc_chttp2_stream_map_size(&t->new_stream_map);
-  GPR_ASSERT(new_stream_count <= UINT32_MAX);
-  if (new_stream_count != t->global.concurrent_stream_count) {
-    t->global.concurrent_stream_count = (uint32_t)new_stream_count;
-    maybe_start_some_streams(exec_ctx, &t->global);
-  }
-}
-
-static void cancel_from_api(grpc_exec_ctx *exec_ctx,
-                            grpc_chttp2_transport_global *transport_global,
-                            grpc_chttp2_stream_global *stream_global,
-                            grpc_status_code status) {
-  if (stream_global->id != 0) {
-    gpr_slice_buffer_add(
-        &transport_global->qbuf,
-        grpc_chttp2_rst_stream_create(
-            stream_global->id,
-            (uint32_t)grpc_chttp2_grpc_status_to_http2_error(status)));
-  }
-  grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status,
-                          NULL);
-  grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
-                                 1);
-}
-
-void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
-                             grpc_chttp2_transport_global *transport_global,
-                             grpc_chttp2_stream_global *stream_global,
-                             grpc_status_code status, gpr_slice *slice) {
-  if (status != GRPC_STATUS_OK) {
-    stream_global->seen_error = 1;
-    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-  }
-  /* stream_global->recv_trailing_metadata_finished gives us a
-     last chance replacement: we've received trailing metadata,
-     but something more important has become available to signal
-     to the upper layers - drop what we've got, and then publish
-     what we want - which is safe because we haven't told anyone
-     about the metadata yet */
-  if (!stream_global->published_trailing_metadata ||
-      stream_global->recv_trailing_metadata_finished != NULL) {
-    char status_string[GPR_LTOA_MIN_BUFSIZE];
-    gpr_ltoa(status, status_string);
-    grpc_chttp2_incoming_metadata_buffer_add(
-        &stream_global->received_trailing_metadata,
-        grpc_mdelem_from_metadata_strings(
-            GRPC_MDSTR_GRPC_STATUS, grpc_mdstr_from_string(status_string)));
-    if (slice) {
-      grpc_chttp2_incoming_metadata_buffer_add(
-          &stream_global->received_trailing_metadata,
-          grpc_mdelem_from_metadata_strings(
-              GRPC_MDSTR_GRPC_MESSAGE,
-              grpc_mdstr_from_slice(gpr_slice_ref(*slice))));
-    }
-    stream_global->published_trailing_metadata = 1;
-    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-  }
-  if (slice) {
-    gpr_slice_unref(*slice);
-  }
-}
-
-static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
-                                grpc_chttp2_stream_global *stream_global) {
-  grpc_chttp2_complete_closure_step(
-      exec_ctx, &stream_global->send_initial_metadata_finished, 0);
-  grpc_chttp2_complete_closure_step(
-      exec_ctx, &stream_global->send_trailing_metadata_finished, 0);
-  grpc_chttp2_complete_closure_step(exec_ctx,
-                                    &stream_global->send_message_finished, 0);
-}
-
-void grpc_chttp2_mark_stream_closed(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, int close_reads,
-    int close_writes) {
-  if (stream_global->read_closed && stream_global->write_closed) {
-    /* already closed */
-    return;
-  }
-  grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-  if (close_reads && !stream_global->read_closed) {
-    stream_global->read_closed = 1;
-    stream_global->published_initial_metadata = 1;
-    stream_global->published_trailing_metadata = 1;
-  }
-  if (close_writes && !stream_global->write_closed) {
-    stream_global->write_closed = 1;
-    if (TRANSPORT_FROM_GLOBAL(transport_global)->writing_active) {
-      GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes");
-      grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
-                                                      stream_global);
-    } else {
-      fail_pending_writes(exec_ctx, stream_global);
-    }
-  }
-  if (stream_global->read_closed && stream_global->write_closed) {
-    if (stream_global->id != 0 &&
-        TRANSPORT_FROM_GLOBAL(transport_global)->parsing_active) {
-      grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
-                                                      stream_global);
-    } else {
-      if (stream_global->id != 0) {
-        remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global),
-                      stream_global->id);
-      }
-      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
-    }
-  }
-}
-
-static void close_from_api(grpc_exec_ctx *exec_ctx,
-                           grpc_chttp2_transport_global *transport_global,
-                           grpc_chttp2_stream_global *stream_global,
-                           grpc_status_code status,
-                           gpr_slice *optional_message) {
-  gpr_slice hdr;
-  gpr_slice status_hdr;
-  gpr_slice message_pfx;
-  uint8_t *p;
-  uint32_t len = 0;
-
-  GPR_ASSERT(status >= 0 && (int)status < 100);
-
-  GPR_ASSERT(stream_global->id != 0);
-
-  /* Hand roll a header block.
-     This is unnecessarily ugly - at some point we should find a more elegant
-     solution.
-     It's complicated by the fact that our send machinery would be dead by the
-     time we got around to sending this, so instead we ignore HPACK compression
-     and just write the uncompressed bytes onto the wire. */
-  status_hdr = gpr_slice_malloc(15 + (status >= 10));
-  p = GPR_SLICE_START_PTR(status_hdr);
-  *p++ = 0x40; /* literal header */
-  *p++ = 11;   /* len(grpc-status) */
-  *p++ = 'g';
-  *p++ = 'r';
-  *p++ = 'p';
-  *p++ = 'c';
-  *p++ = '-';
-  *p++ = 's';
-  *p++ = 't';
-  *p++ = 'a';
-  *p++ = 't';
-  *p++ = 'u';
-  *p++ = 's';
-  if (status < 10) {
-    *p++ = 1;
-    *p++ = (uint8_t)('0' + status);
-  } else {
-    *p++ = 2;
-    *p++ = (uint8_t)('0' + (status / 10));
-    *p++ = (uint8_t)('0' + (status % 10));
-  }
-  GPR_ASSERT(p == GPR_SLICE_END_PTR(status_hdr));
-  len += (uint32_t)GPR_SLICE_LENGTH(status_hdr);
-
-  if (optional_message) {
-    GPR_ASSERT(GPR_SLICE_LENGTH(*optional_message) < 127);
-    message_pfx = gpr_slice_malloc(15);
-    p = GPR_SLICE_START_PTR(message_pfx);
-    *p++ = 0x40;
-    *p++ = 12; /* len(grpc-message) */
-    *p++ = 'g';
-    *p++ = 'r';
-    *p++ = 'p';
-    *p++ = 'c';
-    *p++ = '-';
-    *p++ = 'm';
-    *p++ = 'e';
-    *p++ = 's';
-    *p++ = 's';
-    *p++ = 'a';
-    *p++ = 'g';
-    *p++ = 'e';
-    *p++ = (uint8_t)GPR_SLICE_LENGTH(*optional_message);
-    GPR_ASSERT(p == GPR_SLICE_END_PTR(message_pfx));
-    len += (uint32_t)GPR_SLICE_LENGTH(message_pfx);
-    len += (uint32_t)GPR_SLICE_LENGTH(*optional_message);
-  }
-
-  hdr = gpr_slice_malloc(9);
-  p = GPR_SLICE_START_PTR(hdr);
-  *p++ = (uint8_t)(len >> 16);
-  *p++ = (uint8_t)(len >> 8);
-  *p++ = (uint8_t)(len);
-  *p++ = GRPC_CHTTP2_FRAME_HEADER;
-  *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS;
-  *p++ = (uint8_t)(stream_global->id >> 24);
-  *p++ = (uint8_t)(stream_global->id >> 16);
-  *p++ = (uint8_t)(stream_global->id >> 8);
-  *p++ = (uint8_t)(stream_global->id);
-  GPR_ASSERT(p == GPR_SLICE_END_PTR(hdr));
-
-  gpr_slice_buffer_add(&transport_global->qbuf, hdr);
-  gpr_slice_buffer_add(&transport_global->qbuf, status_hdr);
-  if (optional_message) {
-    gpr_slice_buffer_add(&transport_global->qbuf, message_pfx);
-    gpr_slice_buffer_add(&transport_global->qbuf,
-                         gpr_slice_ref(*optional_message));
-  }
-
-  gpr_slice_buffer_add(
-      &transport_global->qbuf,
-      grpc_chttp2_rst_stream_create(stream_global->id, GRPC_CHTTP2_NO_ERROR));
-
-  if (optional_message) {
-    gpr_slice_ref(*optional_message);
-  }
-  grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status,
-                          optional_message);
-  grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
-                                 1);
-}
-
-static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global,
-                             void *user_data,
-                             grpc_chttp2_stream_global *stream_global) {
-  cancel_from_api(user_data, transport_global, stream_global,
-                  GRPC_STATUS_UNAVAILABLE);
-}
-
-static void end_all_the_calls(grpc_exec_ctx *exec_ctx,
-                              grpc_chttp2_transport *t) {
-  grpc_chttp2_for_all_streams(&t->global, exec_ctx, cancel_stream_cb);
-}
-
-static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
-  close_transport_locked(exec_ctx, t);
-  end_all_the_calls(exec_ctx, t);
-}
-
-/** update window from a settings change */
-static void update_global_window(void *args, uint32_t 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;
-  int64_t initial_window_update = t->parsing.initial_window_update;
-
-  was_zero = stream_global->outgoing_window <= 0;
-  GRPC_CHTTP2_FLOW_CREDIT_STREAM("settings", transport_global, stream_global,
-                                 outgoing_window, initial_window_update);
-  is_zero = stream_global->outgoing_window <= 0;
-
-  if (was_zero && !is_zero) {
-    grpc_chttp2_become_writable(transport_global, stream_global);
-  }
-}
-
-static void read_error_locked(grpc_exec_ctx *exec_ctx,
-                              grpc_chttp2_transport *t) {
-  t->endpoint_reading = 0;
-  if (!t->writing_active && t->ep) {
-    destroy_endpoint(exec_ctx, t);
-  }
-}
-
-/* tcp read callback */
-static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
-  size_t i;
-  int keep_reading = 0;
-  grpc_chttp2_transport *t = tp;
-  grpc_chttp2_transport_global *transport_global = &t->global;
-  grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
-  grpc_chttp2_stream_global *stream_global;
-
-  GPR_TIMER_BEGIN("recv_data", 0);
-
-  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(transport_global, transport_parsing);
-    gpr_mu_unlock(&t->mu);
-    GPR_TIMER_BEGIN("recv_data.parse", 0);
-    for (; i < t->read_buffer.count &&
-               grpc_chttp2_perform_read(exec_ctx, transport_parsing,
-                                        t->read_buffer.slices[i]);
-         i++)
-      ;
-    GPR_TIMER_END("recv_data.parse", 0);
-    gpr_mu_lock(&t->mu);
-    /* copy parsing qbuf to global qbuf */
-    gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
-    if (i != t->read_buffer.count) {
-      unlock(exec_ctx, t);
-      lock(t);
-      drop_connection(exec_ctx, t);
-    }
-    /* merge stream lists */
-    grpc_chttp2_stream_map_move_into(&t->new_stream_map,
-                                     &t->parsing_stream_map);
-    transport_global->concurrent_stream_count =
-        (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map);
-    if (transport_parsing->initial_window_update != 0) {
-      grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
-                                      update_global_window, t);
-      transport_parsing->initial_window_update = 0;
-    }
-    /* handle higher level things */
-    grpc_chttp2_publish_reads(exec_ctx, transport_global, transport_parsing);
-    t->parsing_active = 0;
-    /* handle delayed transport ops (if there is one) */
-    if (t->post_parsing_op) {
-      grpc_transport_op *op = t->post_parsing_op;
-      t->post_parsing_op = NULL;
-      perform_transport_op_locked(exec_ctx, t, op);
-      gpr_free(op);
-    }
-    /* 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_closed);
-      GPR_ASSERT(stream_global->read_closed);
-      remove_stream(exec_ctx, t, stream_global->id);
-      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
-    }
-  }
-  if (!success || i != t->read_buffer.count || t->closed) {
-    drop_connection(exec_ctx, t);
-    read_error_locked(exec_ctx, t);
-  } else if (!t->closed) {
-    keep_reading = 1;
-    REF_TRANSPORT(t, "keep_reading");
-    prevent_endpoint_shutdown(t);
-  }
-  gpr_slice_buffer_reset_and_unref(&t->read_buffer);
-  unlock(exec_ctx, t);
-
-  if (keep_reading) {
-    grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->recv_data);
-    allow_endpoint_shutdown_unlocked(exec_ctx, t);
-    UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
-  } else {
-    UNREF_TRANSPORT(exec_ctx, t, "recv_data");
-  }
-
-  GPR_TIMER_END("recv_data", 0);
-}
-
-/*******************************************************************************
- * CALLBACK LOOP
- */
-
-static void connectivity_state_set(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_connectivity_state state, const char *reason) {
-  GRPC_CHTTP2_IF_TRACING(
-      gpr_log(GPR_DEBUG, "set connectivity_state=%d", state));
-  grpc_connectivity_state_set(exec_ctx, &TRANSPORT_FROM_GLOBAL(transport_global)
-                                             ->channel_callback.state_tracker,
-                              state, reason);
-}
-
-/*******************************************************************************
- * POLLSET STUFF
- */
-
-static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t,
-                                  grpc_pollset *pollset) {
-  if (t->ep) {
-    grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset);
-  }
-}
-
-static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
-                                      grpc_chttp2_transport *t,
-                                      grpc_pollset_set *pollset_set) {
-  if (t->ep) {
-    grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set);
-  }
-}
-
-static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                        grpc_stream *gs, grpc_pollset *pollset) {
-  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-  lock(t);
-  add_to_pollset_locked(exec_ctx, t, pollset);
-  unlock(exec_ctx, t);
-}
-
-/*******************************************************************************
- * BYTE STREAM
- */
-
-static void incoming_byte_stream_update_flow_control(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
-    size_t have_already) {
-  uint32_t max_recv_bytes;
-
-  /* clamp max recv hint to an allowable size */
-  if (max_size_hint >= UINT32_MAX - transport_global->stream_lookahead) {
-    max_recv_bytes = UINT32_MAX - transport_global->stream_lookahead;
-  } else {
-    max_recv_bytes = (uint32_t)max_size_hint;
-  }
-
-  /* account for bytes already received but unknown to higher layers */
-  if (max_recv_bytes >= have_already) {
-    max_recv_bytes -= (uint32_t)have_already;
-  } else {
-    max_recv_bytes = 0;
-  }
-
-  /* add some small lookahead to keep pipelines flowing */
-  GPR_ASSERT(max_recv_bytes <= UINT32_MAX - transport_global->stream_lookahead);
-  max_recv_bytes += transport_global->stream_lookahead;
-  if (stream_global->max_recv_bytes < max_recv_bytes) {
-    uint32_t add_max_recv_bytes =
-        max_recv_bytes - stream_global->max_recv_bytes;
-    GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global,
-                                   max_recv_bytes, add_max_recv_bytes);
-    GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global,
-                                   unannounced_incoming_window_for_parse,
-                                   add_max_recv_bytes);
-    GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global,
-                                   unannounced_incoming_window_for_writing,
-                                   add_max_recv_bytes);
-    grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global,
-                                                               stream_global);
-    grpc_chttp2_become_writable(transport_global, stream_global);
-  }
-}
-
-static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
-                                     grpc_byte_stream *byte_stream,
-                                     gpr_slice *slice, size_t max_size_hint,
-                                     grpc_closure *on_complete) {
-  grpc_chttp2_incoming_byte_stream *bs =
-      (grpc_chttp2_incoming_byte_stream *)byte_stream;
-  grpc_chttp2_transport_global *transport_global = &bs->transport->global;
-  grpc_chttp2_stream_global *stream_global = &bs->stream->global;
-
-  lock(bs->transport);
-  if (bs->is_tail) {
-    incoming_byte_stream_update_flow_control(transport_global, stream_global,
-                                             max_size_hint, bs->slices.length);
-  }
-  if (bs->slices.count > 0) {
-    *slice = gpr_slice_buffer_take_first(&bs->slices);
-    unlock(exec_ctx, bs->transport);
-    return 1;
-  } else if (bs->failed) {
-    grpc_exec_ctx_enqueue(exec_ctx, on_complete, false, NULL);
-    unlock(exec_ctx, bs->transport);
-    return 0;
-  } else {
-    bs->on_next = on_complete;
-    bs->next = slice;
-    unlock(exec_ctx, bs->transport);
-    return 0;
-  }
-}
-
-static void incoming_byte_stream_unref(grpc_chttp2_incoming_byte_stream *bs) {
-  if (gpr_unref(&bs->refs)) {
-    gpr_slice_buffer_destroy(&bs->slices);
-    gpr_free(bs);
-  }
-}
-
-static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
-                                         grpc_byte_stream *byte_stream) {
-  incoming_byte_stream_unref((grpc_chttp2_incoming_byte_stream *)byte_stream);
-}
-
-void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
-                                           grpc_chttp2_incoming_byte_stream *bs,
-                                           gpr_slice slice) {
-  gpr_mu_lock(&bs->transport->mu);
-  if (bs->on_next != NULL) {
-    *bs->next = slice;
-    grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, true, NULL);
-    bs->on_next = NULL;
-  } else {
-    gpr_slice_buffer_add(&bs->slices, slice);
-  }
-  gpr_mu_unlock(&bs->transport->mu);
-}
-
-void grpc_chttp2_incoming_byte_stream_finished(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
-    int from_parsing_thread) {
-  if (!success) {
-    if (from_parsing_thread) {
-      gpr_mu_lock(&bs->transport->mu);
-    }
-    grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL);
-    bs->on_next = NULL;
-    bs->failed = 1;
-    if (from_parsing_thread) {
-      gpr_mu_unlock(&bs->transport->mu);
-    }
-  } else {
-#ifndef NDEBUG
-    if (from_parsing_thread) {
-      gpr_mu_lock(&bs->transport->mu);
-    }
-    GPR_ASSERT(bs->on_next == NULL);
-    if (from_parsing_thread) {
-      gpr_mu_unlock(&bs->transport->mu);
-    }
-#endif
-  }
-  incoming_byte_stream_unref(bs);
-}
-
-grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size,
-    uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue) {
-  grpc_chttp2_incoming_byte_stream *incoming_byte_stream =
-      gpr_malloc(sizeof(*incoming_byte_stream));
-  incoming_byte_stream->base.length = frame_size;
-  incoming_byte_stream->base.flags = flags;
-  incoming_byte_stream->base.next = incoming_byte_stream_next;
-  incoming_byte_stream->base.destroy = incoming_byte_stream_destroy;
-  gpr_ref_init(&incoming_byte_stream->refs, 2);
-  incoming_byte_stream->next_message = NULL;
-  incoming_byte_stream->transport = TRANSPORT_FROM_PARSING(transport_parsing);
-  incoming_byte_stream->stream = STREAM_FROM_PARSING(stream_parsing);
-  gpr_slice_buffer_init(&incoming_byte_stream->slices);
-  incoming_byte_stream->on_next = NULL;
-  incoming_byte_stream->is_tail = 1;
-  incoming_byte_stream->failed = 0;
-  if (add_to_queue->head == NULL) {
-    add_to_queue->head = incoming_byte_stream;
-  } else {
-    add_to_queue->tail->is_tail = 0;
-    add_to_queue->tail->next_message = incoming_byte_stream;
-  }
-  add_to_queue->tail = incoming_byte_stream;
-  return incoming_byte_stream;
-}
-
-/*******************************************************************************
- * TRACING
- */
-
-static char *format_flowctl_context_var(const char *context, const char *var,
-                                        int64_t val, uint32_t id,
-                                        char **scope) {
-  char *underscore_pos;
-  char *result;
-  if (context == NULL) {
-    *scope = NULL;
-    gpr_asprintf(&result, "%s(%lld)", var, val);
-    return result;
-  }
-  underscore_pos = strchr(context, '_');
-  *scope = gpr_strdup(context);
-  (*scope)[underscore_pos - context] = 0;
-  if (id != 0) {
-    char *tmp = *scope;
-    gpr_asprintf(scope, "%s[%d]", tmp, id);
-    gpr_free(tmp);
-  }
-  gpr_asprintf(&result, "%s.%s(%lld)", underscore_pos + 1, var, val);
-  return result;
-}
-
-static int samestr(char *a, char *b) {
-  if (a == NULL) {
-    return b == NULL;
-  }
-  if (b == NULL) {
-    return 0;
-  }
-  return 0 == strcmp(a, b);
-}
-
-void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
-                               grpc_chttp2_flowctl_op op, const char *context1,
-                               const char *var1, const char *context2,
-                               const char *var2, int is_client,
-                               uint32_t stream_id, int64_t val1, int64_t val2) {
-  char *scope1;
-  char *scope2;
-  char *label1 =
-      format_flowctl_context_var(context1, var1, val1, stream_id, &scope1);
-  char *label2 =
-      format_flowctl_context_var(context2, var2, val2, stream_id, &scope2);
-  char *clisvr = is_client ? "client" : "server";
-  char *prefix;
-
-  gpr_asprintf(&prefix, "FLOW % 8s: %s % 11s ", phase, clisvr, scope1);
-
-  switch (op) {
-    case GRPC_CHTTP2_FLOWCTL_MOVE:
-      GPR_ASSERT(samestr(scope1, scope2));
-      if (val2 != 0) {
-        gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-                "%sMOVE   % 40s <- % 40s giving %d", prefix, label1, label2,
-                val1 + val2);
-      }
-      break;
-    case GRPC_CHTTP2_FLOWCTL_CREDIT:
-      GPR_ASSERT(val2 >= 0);
-      if (val2 != 0) {
-        gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-                "%sCREDIT % 40s by % 40s giving %d", prefix, label1, label2,
-                val1 + val2);
-      }
-      break;
-    case GRPC_CHTTP2_FLOWCTL_DEBIT:
-      GPR_ASSERT(val2 >= 0);
-      if (val2 != 0) {
-        gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-                "%sDEBIT  % 40s by % 40s giving %d", prefix, label1, label2,
-                val1 - val2);
-      }
-      break;
-  }
-
-  gpr_free(scope1);
-  gpr_free(scope2);
-  gpr_free(label1);
-  gpr_free(label2);
-  gpr_free(prefix);
-}
-
-/*******************************************************************************
- * INTEGRATION GLUE
- */
-
-static char *chttp2_get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *t) {
-  return gpr_strdup(((grpc_chttp2_transport *)t)->peer_string);
-}
-
-static const grpc_transport_vtable vtable = {
-    sizeof(grpc_chttp2_stream), init_stream, set_pollset, perform_stream_op,
-    perform_transport_op, destroy_stream, destroy_transport, chttp2_get_peer};
-
-grpc_transport *grpc_create_chttp2_transport(
-    grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args,
-    grpc_endpoint *ep, int is_client) {
-  grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport));
-  init_transport(exec_ctx, t, channel_args, ep, is_client != 0);
-  return &t->base;
-}
-
-void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
-                                         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 */
-  gpr_slice_buffer_addn(&t->read_buffer, slices, nslices);
-  recv_data(exec_ctx, t, 1);
-}
diff --git a/src/core/transport/chttp2_transport.h b/src/core/transport/chttp2_transport.h
deleted file mode 100644
index 9552050..0000000
--- a/src/core/transport/chttp2_transport.h
+++ /dev/null
@@ -1,51 +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_TRANSPORT_CHTTP2_TRANSPORT_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TRANSPORT_H
-
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/transport/transport.h"
-
-extern int grpc_http_trace;
-extern int grpc_flowctl_trace;
-
-grpc_transport *grpc_create_chttp2_transport(
-    grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args,
-    grpc_endpoint *ep, int is_client);
-
-void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
-                                         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
deleted file mode 100644
index 87765b9..0000000
--- a/src/core/transport/connectivity_state.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/transport/connectivity_state.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-int grpc_connectivity_state_trace = 0;
-
-const char *grpc_connectivity_state_name(grpc_connectivity_state state) {
-  switch (state) {
-    case GRPC_CHANNEL_IDLE:
-      return "IDLE";
-    case GRPC_CHANNEL_CONNECTING:
-      return "CONNECTING";
-    case GRPC_CHANNEL_READY:
-      return "READY";
-    case GRPC_CHANNEL_TRANSIENT_FAILURE:
-      return "TRANSIENT_FAILURE";
-    case GRPC_CHANNEL_FATAL_FAILURE:
-      return "FATAL_FAILURE";
-  }
-  GPR_UNREACHABLE_CODE(return "UNKNOWN");
-}
-
-void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
-                                  grpc_connectivity_state init_state,
-                                  const char *name) {
-  tracker->current_state = init_state;
-  tracker->watchers = NULL;
-  tracker->name = gpr_strdup(name);
-}
-
-void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx,
-                                     grpc_connectivity_state_tracker *tracker) {
-  int success;
-  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;
-      success = 1;
-    } else {
-      success = 0;
-    }
-    grpc_exec_ctx_enqueue(exec_ctx, w->notify, success, NULL);
-    gpr_free(w);
-  }
-  gpr_free(tracker->name);
-}
-
-grpc_connectivity_state grpc_connectivity_state_check(
-    grpc_connectivity_state_tracker *tracker) {
-  if (grpc_connectivity_state_trace) {
-    gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
-            grpc_connectivity_state_name(tracker->current_state));
-  }
-  return tracker->current_state;
-}
-
-int grpc_connectivity_state_notify_on_state_change(
-    grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
-    grpc_connectivity_state *current, grpc_closure *notify) {
-  if (grpc_connectivity_state_trace) {
-    if (current == NULL) {
-      gpr_log(GPR_DEBUG, "CONWATCH: %p %s: unsubscribe notify=%p", tracker,
-              tracker->name, notify);
-    } else {
-      gpr_log(GPR_DEBUG, "CONWATCH: %p %s: from %s [cur=%s] notify=%p", tracker,
-              tracker->name, grpc_connectivity_state_name(*current),
-              grpc_connectivity_state_name(tracker->current_state), notify);
-    }
-  }
-  if (current == NULL) {
-    grpc_connectivity_state_watcher *w = tracker->watchers;
-    if (w != NULL && w->notify == notify) {
-      grpc_exec_ctx_enqueue(exec_ctx, notify, false, NULL);
-      tracker->watchers = w->next;
-      gpr_free(w);
-      return 0;
-    }
-    while (w != NULL) {
-      grpc_connectivity_state_watcher *rm_candidate = w->next;
-      if (rm_candidate != NULL && rm_candidate->notify == notify) {
-        grpc_exec_ctx_enqueue(exec_ctx, notify, false, NULL);
-        w->next = w->next->next;
-        gpr_free(rm_candidate);
-        return 0;
-      }
-      w = w->next;
-    }
-    return 0;
-  } else {
-    if (tracker->current_state != *current) {
-      *current = tracker->current_state;
-      grpc_exec_ctx_enqueue(exec_ctx, notify, true, NULL);
-    } 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(grpc_exec_ctx *exec_ctx,
-                                 grpc_connectivity_state_tracker *tracker,
-                                 grpc_connectivity_state state,
-                                 const char *reason) {
-  grpc_connectivity_state_watcher *w;
-  if (grpc_connectivity_state_trace) {
-    gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s]", tracker, tracker->name,
-            grpc_connectivity_state_name(tracker->current_state),
-            grpc_connectivity_state_name(state), reason);
-  }
-  if (tracker->current_state == state) {
-    return;
-  }
-  GPR_ASSERT(tracker->current_state != GRPC_CHANNEL_FATAL_FAILURE);
-  tracker->current_state = state;
-  while ((w = tracker->watchers) != NULL) {
-    *w->current = tracker->current_state;
-    tracker->watchers = w->next;
-    grpc_exec_ctx_enqueue(exec_ctx, w->notify, true, NULL);
-    gpr_free(w);
-  }
-}
diff --git a/src/core/transport/connectivity_state.h b/src/core/transport/connectivity_state.h
deleted file mode 100644
index a4eb665..0000000
--- a/src/core/transport/connectivity_state.h
+++ /dev/null
@@ -1,85 +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_TRANSPORT_CONNECTIVITY_STATE_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H
-
-#include <grpc/grpc.h>
-#include "src/core/iomgr/exec_ctx.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_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;
-  /** a name to help debugging */
-  char *name;
-} grpc_connectivity_state_tracker;
-
-extern int grpc_connectivity_state_trace;
-
-const char *grpc_connectivity_state_name(grpc_connectivity_state state);
-
-void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
-                                  grpc_connectivity_state init_state,
-                                  const char *name);
-void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx,
-                                     grpc_connectivity_state_tracker *tracker);
-
-/** Set connectivity state; not thread safe; access must be serialized with an
- * external lock */
-void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
-                                 grpc_connectivity_state_tracker *tracker,
-                                 grpc_connectivity_state state,
-                                 const char *reason);
-
-grpc_connectivity_state grpc_connectivity_state_check(
-    grpc_connectivity_state_tracker *tracker);
-
-/** Return 1 if the channel should start connecting, 0 otherwise.
-    If current==NULL cancel notify if it is already queued (success==0 in that
-    case) */
-int grpc_connectivity_state_notify_on_state_change(
-    grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
-    grpc_connectivity_state *current, grpc_closure *notify);
-
-#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H */
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
deleted file mode 100644
index 807ae07..0000000
--- a/src/core/transport/metadata.c
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/transport/metadata.h"
-
-#include <assert.h>
-#include <stddef.h>
-#include <string.h>
-
-#include <grpc/compression.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/atm.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/time.h>
-
-#include "src/core/profiling/timers.h"
-#include "src/core/support/murmur_hash.h"
-#include "src/core/support/string.h"
-#include "src/core/transport/chttp2/bin_encoder.h"
-#include "src/core/transport/static_metadata.h"
-#include "src/core/iomgr/iomgr_internal.h"
-
-/* There are two kinds of mdelem and mdstr instances.
- * Static instances are declared in static_metadata.{h,c} and
- * are initialized by grpc_mdctx_global_init().
- * Dynamic instances are stored in hash tables on grpc_mdctx, and are backed
- * by internal_string and internal_element structures.
- * Internal helper functions here-in (is_mdstr_static, is_mdelem_static) are
- * used to determine which kind of element a pointer refers to.
- */
-
-#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 REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s), __FILE__, __LINE__)
-#else
-#define DEBUG_ARGS
-#define FWD_DEBUG_ARGS
-#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s))
-#endif
-
-#define TABLE_IDX(hash, log2_shards, capacity) \
-  (((hash) >> (log2_shards)) % (capacity))
-#define SHARD_IDX(hash, log2_shards) ((hash) & ((1 << (log2_shards)) - 1))
-
-typedef void (*destroy_user_data_func)(void *user_data);
-
-/* Shadow structure for grpc_mdstr for non-static values */
-typedef struct internal_string {
-  /* must be byte compatible with grpc_mdstr */
-  gpr_slice slice;
-  uint32_t hash;
-
-  /* private only data */
-  gpr_atm refcnt;
-
-  uint8_t has_base64_and_huffman_encoded;
-  gpr_slice_refcount refcount;
-
-  gpr_slice base64_and_huffman;
-
-  struct internal_string *bucket_next;
-} internal_string;
-
-/* Shadow structure for grpc_mdelem for non-static elements */
-typedef struct internal_metadata {
-  /* must be byte compatible with grpc_mdelem */
-  internal_string *key;
-  internal_string *value;
-
-  /* private only data */
-  gpr_atm refcnt;
-
-  gpr_mu mu_user_data;
-  gpr_atm destroy_user_data;
-  gpr_atm user_data;
-
-  struct internal_metadata *bucket_next;
-} internal_metadata;
-
-typedef struct strtab_shard {
-  gpr_mu mu;
-  internal_string **strs;
-  size_t count;
-  size_t capacity;
-} strtab_shard;
-
-typedef struct mdtab_shard {
-  gpr_mu mu;
-  internal_metadata **elems;
-  size_t count;
-  size_t capacity;
-  size_t free;
-} mdtab_shard;
-
-#define LOG2_STRTAB_SHARD_COUNT 5
-#define LOG2_MDTAB_SHARD_COUNT 4
-#define STRTAB_SHARD_COUNT ((size_t)(1 << LOG2_STRTAB_SHARD_COUNT))
-#define MDTAB_SHARD_COUNT ((size_t)(1 << LOG2_MDTAB_SHARD_COUNT))
-
-/* hash seed: decided at initialization time */
-static uint32_t g_hash_seed;
-static int g_forced_hash_seed = 0;
-
-/* linearly probed hash tables for static element lookup */
-static grpc_mdstr *g_static_strtab[GRPC_STATIC_MDSTR_COUNT * 2];
-static grpc_mdelem *g_static_mdtab[GRPC_STATIC_MDELEM_COUNT * 2];
-static size_t g_static_strtab_maxprobe;
-static size_t g_static_mdtab_maxprobe;
-
-static strtab_shard g_strtab_shard[STRTAB_SHARD_COUNT];
-static mdtab_shard g_mdtab_shard[MDTAB_SHARD_COUNT];
-
-static void gc_mdtab(mdtab_shard *shard);
-
-void grpc_test_only_set_metadata_hash_seed(uint32_t seed) {
-  g_hash_seed = seed;
-  g_forced_hash_seed = 1;
-}
-
-void grpc_mdctx_global_init(void) {
-  size_t i, j;
-  if (!g_forced_hash_seed) {
-    g_hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
-  }
-  g_static_strtab_maxprobe = 0;
-  g_static_mdtab_maxprobe = 0;
-  /* build static tables */
-  memset(g_static_mdtab, 0, sizeof(g_static_mdtab));
-  memset(g_static_strtab, 0, sizeof(g_static_strtab));
-  for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
-    grpc_mdstr *elem = &grpc_static_mdstr_table[i];
-    const char *str = grpc_static_metadata_strings[i];
-    uint32_t hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed);
-    *(gpr_slice *)&elem->slice = gpr_slice_from_static_string(str);
-    *(uint32_t *)&elem->hash = hash;
-    for (j = 0;; j++) {
-      size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_strtab);
-      if (g_static_strtab[idx] == NULL) {
-        g_static_strtab[idx] = &grpc_static_mdstr_table[i];
-        break;
-      }
-    }
-    if (j > g_static_strtab_maxprobe) {
-      g_static_strtab_maxprobe = j;
-    }
-  }
-  for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) {
-    grpc_mdelem *elem = &grpc_static_mdelem_table[i];
-    grpc_mdstr *key =
-        &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 0]];
-    grpc_mdstr *value =
-        &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 1]];
-    uint32_t hash = GRPC_MDSTR_KV_HASH(key->hash, value->hash);
-    *(grpc_mdstr **)&elem->key = key;
-    *(grpc_mdstr **)&elem->value = value;
-    for (j = 0;; j++) {
-      size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_mdtab);
-      if (g_static_mdtab[idx] == NULL) {
-        g_static_mdtab[idx] = elem;
-        break;
-      }
-    }
-    if (j > g_static_mdtab_maxprobe) {
-      g_static_mdtab_maxprobe = j;
-    }
-  }
-  /* initialize shards */
-  for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
-    strtab_shard *shard = &g_strtab_shard[i];
-    gpr_mu_init(&shard->mu);
-    shard->count = 0;
-    shard->capacity = INITIAL_STRTAB_CAPACITY;
-    shard->strs = gpr_malloc(sizeof(*shard->strs) * shard->capacity);
-    memset(shard->strs, 0, sizeof(*shard->strs) * shard->capacity);
-  }
-  for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
-    mdtab_shard *shard = &g_mdtab_shard[i];
-    gpr_mu_init(&shard->mu);
-    shard->count = 0;
-    shard->free = 0;
-    shard->capacity = INITIAL_MDTAB_CAPACITY;
-    shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity);
-    memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity);
-  }
-}
-
-void grpc_mdctx_global_shutdown(void) {
-  size_t i;
-  for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
-    mdtab_shard *shard = &g_mdtab_shard[i];
-    gpr_mu_destroy(&shard->mu);
-    gc_mdtab(shard);
-    /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
-    if (shard->count != 0) {
-      gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked",
-              shard->count);
-      if (grpc_iomgr_abort_on_leaks()) {
-        abort();
-      }
-    }
-    gpr_free(shard->elems);
-  }
-  for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
-    strtab_shard *shard = &g_strtab_shard[i];
-    gpr_mu_destroy(&shard->mu);
-    /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
-    if (shard->count != 0) {
-      gpr_log(GPR_DEBUG, "WARNING: %d metadata strings were leaked",
-              shard->count);
-      if (grpc_iomgr_abort_on_leaks()) {
-        abort();
-      }
-    }
-    gpr_free(shard->strs);
-  }
-}
-
-static int is_mdstr_static(grpc_mdstr *s) {
-  return s >= &grpc_static_mdstr_table[0] &&
-         s < &grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
-}
-
-static int is_mdelem_static(grpc_mdelem *e) {
-  return e >= &grpc_static_mdelem_table[0] &&
-         e < &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
-}
-
-static void ref_md_locked(mdtab_shard *shard,
-                          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, 2)) {
-    shard->free--;
-  } else {
-    GPR_ASSERT(1 != gpr_atm_no_barrier_fetch_add(&md->refcnt, -1));
-  }
-}
-
-static void grow_strtab(strtab_shard *shard) {
-  size_t capacity = shard->capacity * 2;
-  size_t i;
-  internal_string **strtab;
-  internal_string *s, *next;
-
-  GPR_TIMER_BEGIN("grow_strtab", 0);
-
-  strtab = gpr_malloc(sizeof(internal_string *) * capacity);
-  memset(strtab, 0, sizeof(internal_string *) * capacity);
-
-  for (i = 0; i < shard->capacity; i++) {
-    for (s = shard->strs[i]; s; s = next) {
-      size_t idx = TABLE_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT, capacity);
-      next = s->bucket_next;
-      s->bucket_next = strtab[idx];
-      strtab[idx] = s;
-    }
-  }
-
-  gpr_free(shard->strs);
-  shard->strs = strtab;
-  shard->capacity = capacity;
-
-  GPR_TIMER_END("grow_strtab", 0);
-}
-
-static void internal_destroy_string(strtab_shard *shard, internal_string *is) {
-  internal_string **prev_next;
-  internal_string *cur;
-  GPR_TIMER_BEGIN("internal_destroy_string", 0);
-  if (is->has_base64_and_huffman_encoded) {
-    gpr_slice_unref(is->base64_and_huffman);
-  }
-  for (prev_next = &shard->strs[TABLE_IDX(is->hash, LOG2_STRTAB_SHARD_COUNT,
-                                          shard->capacity)],
-      cur = *prev_next;
-       cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next)
-    ;
-  *prev_next = cur->bucket_next;
-  shard->count--;
-  gpr_free(is);
-  GPR_TIMER_END("internal_destroy_string", 0);
-}
-
-static void slice_ref(void *p) {
-  internal_string *is =
-      (internal_string *)((char *)p - offsetof(internal_string, refcount));
-  GRPC_MDSTR_REF((grpc_mdstr *)(is));
-}
-
-static void slice_unref(void *p) {
-  internal_string *is =
-      (internal_string *)((char *)p - offsetof(internal_string, refcount));
-  GRPC_MDSTR_UNREF((grpc_mdstr *)(is));
-}
-
-grpc_mdstr *grpc_mdstr_from_string(const char *str) {
-  return grpc_mdstr_from_buffer((const uint8_t *)str, strlen(str));
-}
-
-grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice) {
-  grpc_mdstr *result = grpc_mdstr_from_buffer(GPR_SLICE_START_PTR(slice),
-                                              GPR_SLICE_LENGTH(slice));
-  gpr_slice_unref(slice);
-  return result;
-}
-
-grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *buf, size_t length) {
-  uint32_t hash = gpr_murmur_hash3(buf, length, g_hash_seed);
-  internal_string *s;
-  strtab_shard *shard =
-      &g_strtab_shard[SHARD_IDX(hash, LOG2_STRTAB_SHARD_COUNT)];
-  size_t i;
-  size_t idx;
-
-  GPR_TIMER_BEGIN("grpc_mdstr_from_buffer", 0);
-
-  /* search for a static string */
-  for (i = 0; i <= g_static_strtab_maxprobe; i++) {
-    grpc_mdstr *ss;
-    idx = (hash + i) % GPR_ARRAY_SIZE(g_static_strtab);
-    ss = g_static_strtab[idx];
-    if (ss == NULL) break;
-    if (ss->hash == hash && GPR_SLICE_LENGTH(ss->slice) == length &&
-        0 == memcmp(buf, GPR_SLICE_START_PTR(ss->slice), length)) {
-      GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
-      return ss;
-    }
-  }
-
-  gpr_mu_lock(&shard->mu);
-
-  /* search for an existing string */
-  idx = TABLE_IDX(hash, LOG2_STRTAB_SHARD_COUNT, shard->capacity);
-  for (s = shard->strs[idx]; 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)) {
-      GRPC_MDSTR_REF((grpc_mdstr *)s);
-      gpr_mu_unlock(&shard->mu);
-      GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
-      return (grpc_mdstr *)s;
-    }
-  }
-
-  /* not found: create a new string */
-  if (length + 1 < GPR_SLICE_INLINED_SIZE) {
-    /* string data goes directly into the slice */
-    s = gpr_malloc(sizeof(internal_string));
-    gpr_atm_rel_store(&s->refcnt, 2);
-    s->slice.refcount = NULL;
-    memcpy(s->slice.data.inlined.bytes, buf, length);
-    s->slice.data.inlined.bytes[length] = 0;
-    s->slice.data.inlined.length = (uint8_t)length;
-  } else {
-    /* string data goes after the internal_string header, and we +1 for null
-       terminator */
-    s = gpr_malloc(sizeof(internal_string) + length + 1);
-    gpr_atm_rel_store(&s->refcnt, 2);
-    s->refcount.ref = slice_ref;
-    s->refcount.unref = slice_unref;
-    s->slice.refcount = &s->refcount;
-    s->slice.data.refcounted.bytes = (uint8_t *)(s + 1);
-    s->slice.data.refcounted.length = length;
-    memcpy(s->slice.data.refcounted.bytes, buf, length);
-    /* add a null terminator for cheap c string conversion when desired */
-    s->slice.data.refcounted.bytes[length] = 0;
-  }
-  s->has_base64_and_huffman_encoded = 0;
-  s->hash = hash;
-  s->bucket_next = shard->strs[idx];
-  shard->strs[idx] = s;
-
-  shard->count++;
-
-  if (shard->count > shard->capacity * 2) {
-    grow_strtab(shard);
-  }
-
-  gpr_mu_unlock(&shard->mu);
-  GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
-
-  return (grpc_mdstr *)s;
-}
-
-static void gc_mdtab(mdtab_shard *shard) {
-  size_t i;
-  internal_metadata **prev_next;
-  internal_metadata *md, *next;
-
-  GPR_TIMER_BEGIN("gc_mdtab", 0);
-  for (i = 0; i < shard->capacity; i++) {
-    prev_next = &shard->elems[i];
-    for (md = shard->elems[i]; md; md = next) {
-      void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data);
-      next = md->bucket_next;
-      if (gpr_atm_acq_load(&md->refcnt) == 0) {
-        GRPC_MDSTR_UNREF((grpc_mdstr *)md->key);
-        GRPC_MDSTR_UNREF((grpc_mdstr *)md->value);
-        if (md->user_data) {
-          ((destroy_user_data_func)gpr_atm_no_barrier_load(
-              &md->destroy_user_data))(user_data);
-        }
-        gpr_free(md);
-        *prev_next = next;
-        shard->free--;
-        shard->count--;
-      } else {
-        prev_next = &md->bucket_next;
-      }
-    }
-  }
-  GPR_TIMER_END("gc_mdtab", 0);
-}
-
-static void grow_mdtab(mdtab_shard *shard) {
-  size_t capacity = shard->capacity * 2;
-  size_t i;
-  internal_metadata **mdtab;
-  internal_metadata *md, *next;
-  uint32_t hash;
-
-  GPR_TIMER_BEGIN("grow_mdtab", 0);
-
-  mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity);
-  memset(mdtab, 0, sizeof(internal_metadata *) * capacity);
-
-  for (i = 0; i < shard->capacity; i++) {
-    for (md = shard->elems[i]; md; md = next) {
-      size_t idx;
-      hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
-      next = md->bucket_next;
-      idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, capacity);
-      md->bucket_next = mdtab[idx];
-      mdtab[idx] = md;
-    }
-  }
-
-  gpr_free(shard->elems);
-  shard->elems = mdtab;
-  shard->capacity = capacity;
-
-  GPR_TIMER_END("grow_mdtab", 0);
-}
-
-static void rehash_mdtab(mdtab_shard *shard) {
-  if (shard->free > shard->capacity / 4) {
-    gc_mdtab(shard);
-  } else {
-    grow_mdtab(shard);
-  }
-}
-
-grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *mkey,
-                                               grpc_mdstr *mvalue) {
-  internal_string *key = (internal_string *)mkey;
-  internal_string *value = (internal_string *)mvalue;
-  uint32_t hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash);
-  internal_metadata *md;
-  mdtab_shard *shard = &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
-  size_t i;
-  size_t idx;
-
-  GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0);
-
-  if (is_mdstr_static(mkey) && is_mdstr_static(mvalue)) {
-    for (i = 0; i <= g_static_mdtab_maxprobe; i++) {
-      grpc_mdelem *smd;
-      idx = (hash + i) % GPR_ARRAY_SIZE(g_static_mdtab);
-      smd = g_static_mdtab[idx];
-      if (smd == NULL) break;
-      if (smd->key == mkey && smd->value == mvalue) {
-        GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
-        return smd;
-      }
-    }
-  }
-
-  gpr_mu_lock(&shard->mu);
-
-  idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, shard->capacity);
-  /* search for an existing pair */
-  for (md = shard->elems[idx]; md; md = md->bucket_next) {
-    if (md->key == key && md->value == value) {
-      REF_MD_LOCKED(shard, md);
-      GRPC_MDSTR_UNREF((grpc_mdstr *)key);
-      GRPC_MDSTR_UNREF((grpc_mdstr *)value);
-      gpr_mu_unlock(&shard->mu);
-      GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
-      return (grpc_mdelem *)md;
-    }
-  }
-
-  /* not found: create a new pair */
-  md = gpr_malloc(sizeof(internal_metadata));
-  gpr_atm_rel_store(&md->refcnt, 2);
-  md->key = key;
-  md->value = value;
-  md->user_data = 0;
-  md->destroy_user_data = 0;
-  md->bucket_next = shard->elems[idx];
-  shard->elems[idx] = md;
-  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
-  shard->count++;
-
-  if (shard->count > shard->capacity * 2) {
-    rehash_mdtab(shard);
-  }
-
-  gpr_mu_unlock(&shard->mu);
-
-  GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
-
-  return (grpc_mdelem *)md;
-}
-
-grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value) {
-  return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_string(key),
-                                           grpc_mdstr_from_string(value));
-}
-
-grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value) {
-  return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_slice(key),
-                                           grpc_mdstr_from_slice(value));
-}
-
-grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
-                                                const uint8_t *value,
-                                                size_t value_length) {
-  return grpc_mdelem_from_metadata_strings(
-      grpc_mdstr_from_string(key), grpc_mdstr_from_buffer(value, value_length));
-}
-
-grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
-  internal_metadata *md = (internal_metadata *)gmd;
-  if (is_mdelem_static(gmd)) return 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 */
-  /* use C assert to have this removed in opt builds */
-  assert(gpr_atm_no_barrier_load(&md->refcnt) >= 2);
-  gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
-  return gmd;
-}
-
-void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
-  internal_metadata *md = (internal_metadata *)gmd;
-  if (!md) return;
-  if (is_mdelem_static(gmd)) return;
-#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
-  if (2 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
-    uint32_t hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
-    mdtab_shard *shard =
-        &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
-    GPR_TIMER_BEGIN("grpc_mdelem_unref.to_zero", 0);
-    gpr_mu_lock(&shard->mu);
-    if (1 == gpr_atm_no_barrier_load(&md->refcnt)) {
-      shard->free++;
-      gpr_atm_no_barrier_store(&md->refcnt, 0);
-    }
-    gpr_mu_unlock(&shard->mu);
-    GPR_TIMER_END("grpc_mdelem_unref.to_zero", 0);
-  }
-}
-
-const char *grpc_mdstr_as_c_string(grpc_mdstr *s) {
-  return (const char *)GPR_SLICE_START_PTR(s->slice);
-}
-
-grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
-  internal_string *s = (internal_string *)gs;
-  if (is_mdstr_static(gs)) return gs;
-  GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) != 0);
-  return gs;
-}
-
-void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
-  internal_string *s = (internal_string *)gs;
-  if (is_mdstr_static(gs)) return;
-  if (2 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
-    strtab_shard *shard =
-        &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
-    gpr_mu_lock(&shard->mu);
-    if (1 == gpr_atm_no_barrier_load(&s->refcnt)) {
-      internal_destroy_string(shard, s);
-    }
-    gpr_mu_unlock(&shard->mu);
-  }
-}
-
-void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) {
-  internal_metadata *im = (internal_metadata *)md;
-  void *result;
-  if (is_mdelem_static(md)) {
-    return (void *)grpc_static_mdelem_user_data[md - grpc_static_mdelem_table];
-  }
-  if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) {
-    return (void *)gpr_atm_no_barrier_load(&im->user_data);
-  } else {
-    return NULL;
-  }
-  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(!is_mdelem_static(md));
-  GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
-  gpr_mu_lock(&im->mu_user_data);
-  if (gpr_atm_no_barrier_load(&im->destroy_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;
-  }
-  gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data);
-  gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func);
-  gpr_mu_unlock(&im->mu_user_data);
-}
-
-gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
-  internal_string *s = (internal_string *)gs;
-  gpr_slice slice;
-  strtab_shard *shard =
-      &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
-  gpr_mu_lock(&shard->mu);
-  if (!s->has_base64_and_huffman_encoded) {
-    s->base64_and_huffman =
-        grpc_chttp2_base64_encode_and_huffman_compress(s->slice);
-    s->has_base64_and_huffman_encoded = 1;
-  }
-  slice = s->base64_and_huffman;
-  gpr_mu_unlock(&shard->mu);
-  return slice;
-}
diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h
deleted file mode 100644
index 8742846..0000000
--- a/src/core/transport/metadata.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H
-
-#include <grpc/support/slice.h>
-#include <grpc/support/useful.h>
-
-/* This file provides a mechanism for tracking metadata through the grpc stack.
-   It's not intended for consumption outside of the library.
-
-   Metadata is tracked in the context of a grpc_mdctx. For the time being there
-   is one of these per-channel, avoiding cross channel interference with memory
-   use and lock contention.
-
-   The context tracks unique strings (grpc_mdstr) and pairs of strings
-   (grpc_mdelem). Any of these objects can be checked for equality by comparing
-   their pointers. These objects are reference counted.
-
-   grpc_mdelem can additionally store a (non-NULL) user data pointer. This
-   pointer is intended to be used to cache semantic meaning of a metadata
-   element. For example, an OAuth token may cache the credentials it represents
-   and the time at which it expires in the mdelem user data.
-
-   Combining this metadata cache and the hpack compression table allows us to
-   simply lookup complete preparsed objects quickly, incurring a few atomic
-   ops per metadata element on the fast path.
-
-   grpc_mdelem instances MAY live longer than their refcount implies, and are
-   garbage collected periodically, meaning cached data can easily outlive a
-   single request.
-
-   STATIC METADATA: in static_metadata.h we declare a set of static metadata.
-   These mdelems and mdstrs are available via pre-declared code generated macros
-   and are available to code anywhere between grpc_init() and grpc_shutdown().
-   They are not refcounted, but can be passed to _ref and _unref functions
-   declared here - in which case those functions are effectively no-ops. */
-
-/* Forward declarations */
-typedef struct grpc_mdstr grpc_mdstr;
-typedef struct grpc_mdelem grpc_mdelem;
-
-/* if changing this, make identical changes in internal_string in metadata.c */
-struct grpc_mdstr {
-  const gpr_slice slice;
-  const uint32_t hash;
-  /* there is a private part to this in metadata.c */
-};
-
-/* if changing this, make identical changes in internal_metadata in
-   metadata.c */
-struct grpc_mdelem {
-  grpc_mdstr *const key;
-  grpc_mdstr *const value;
-  /* there is a private part to this in metadata.c */
-};
-
-void grpc_test_only_set_metadata_hash_seed(uint32_t seed);
-
-/* Constructors for grpc_mdstr instances; take a variety of data types that
-   clients may have handy */
-grpc_mdstr *grpc_mdstr_from_string(const char *str);
-/* Unrefs the slice. */
-grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice);
-grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *str, size_t length);
-
-/* Returns a borrowed slice from the mdstr with its contents base64 encoded
-   and huffman compressed */
-gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *str);
-
-/* Constructors for grpc_mdelem instances; take a variety of data types that
-   clients may have handy */
-grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *key,
-                                               grpc_mdstr *value);
-grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value);
-/* Unrefs the slices. */
-grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value);
-grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
-                                                const uint8_t *value,
-                                                size_t value_length);
-
-/* Mutator and accessor for grpc_mdelem user data. The destructor function
-   is used as a type tag and is checked during user_data fetch. */
-void *grpc_mdelem_get_user_data(grpc_mdelem *md,
-                                void (*if_destroy_func)(void *));
-void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
-                               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. */
-const char *grpc_mdstr_as_c_string(grpc_mdstr *s);
-
-#define GRPC_MDSTR_LENGTH(s) (GPR_SLICE_LENGTH(s->slice))
-
-int grpc_mdstr_is_legal_header(grpc_mdstr *s);
-int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s);
-int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s);
-
-#define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash))
-
-void grpc_mdctx_global_init(void);
-void grpc_mdctx_global_shutdown(void);
-
-#endif /* GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H */
diff --git a/src/core/transport/metadata_batch.c b/src/core/transport/metadata_batch.c
deleted file mode 100644
index 1266862..0000000
--- a/src/core/transport/metadata_batch.c
+++ /dev/null
@@ -1,194 +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/transport/metadata_batch.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/profiling/timers.h"
-
-static void assert_valid_list(grpc_mdelem_list *list) {
-#ifndef NDEBUG
-  grpc_linked_mdelem *l;
-
-  GPR_ASSERT((list->head == NULL) == (list->tail == NULL));
-  if (!list->head) return;
-  GPR_ASSERT(list->head->prev == NULL);
-  GPR_ASSERT(list->tail->next == NULL);
-  GPR_ASSERT((list->head == list->tail) == (list->head->next == NULL));
-
-  for (l = list->head; l; l = l->next) {
-    GPR_ASSERT(l->md);
-    GPR_ASSERT((l->prev == NULL) == (l == list->head));
-    GPR_ASSERT((l->next == NULL) == (l == list->tail));
-    if (l->next) GPR_ASSERT(l->next->prev == l);
-    if (l->prev) GPR_ASSERT(l->prev->next == l);
-  }
-#endif /* NDEBUG */
-}
-
-#ifndef NDEBUG
-void grpc_metadata_batch_assert_ok(grpc_metadata_batch *batch) {
-  assert_valid_list(&batch->list);
-}
-#endif /* NDEBUG */
-
-void grpc_metadata_batch_init(grpc_metadata_batch *batch) {
-  batch->list.head = batch->list.tail = NULL;
-  batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
-}
-
-void grpc_metadata_batch_destroy(grpc_metadata_batch *batch) {
-  grpc_linked_mdelem *l;
-  for (l = batch->list.head; l; l = l->next) {
-    GRPC_MDELEM_UNREF(l->md);
-  }
-}
-
-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(batch, storage);
-}
-
-static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
-  assert_valid_list(list);
-  GPR_ASSERT(storage->md);
-  storage->prev = NULL;
-  storage->next = list->head;
-  if (list->head != NULL) {
-    list->head->prev = storage;
-  } else {
-    list->tail = storage;
-  }
-  list->head = storage;
-  assert_valid_list(list);
-}
-
-void grpc_metadata_batch_link_head(grpc_metadata_batch *batch,
-                                   grpc_linked_mdelem *storage) {
-  link_head(&batch->list, storage);
-}
-
-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(batch, storage);
-}
-
-static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
-  assert_valid_list(list);
-  GPR_ASSERT(storage->md);
-  storage->prev = list->tail;
-  storage->next = NULL;
-  storage->reserved = NULL;
-  if (list->tail != NULL) {
-    list->tail->next = storage;
-  } else {
-    list->head = storage;
-  }
-  list->tail = storage;
-  assert_valid_list(list);
-}
-
-void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch,
-                                   grpc_linked_mdelem *storage) {
-  link_tail(&batch->list, storage);
-}
-
-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;
-
-  GPR_TIMER_BEGIN("grpc_metadata_batch_filter", 0);
-
-  assert_valid_list(&batch->list);
-  for (l = batch->list.head; l; l = next) {
-    grpc_mdelem *orig = l->md;
-    grpc_mdelem *filt = filter(user_data, orig);
-    next = l->next;
-    if (filt == NULL) {
-      if (l->prev) {
-        l->prev->next = l->next;
-      }
-      if (l->next) {
-        l->next->prev = l->prev;
-      }
-      if (batch->list.head == l) {
-        batch->list.head = l->next;
-      }
-      if (batch->list.tail == l) {
-        batch->list.tail = l->prev;
-      }
-      assert_valid_list(&batch->list);
-      GRPC_MDELEM_UNREF(l->md);
-    } else if (filt != orig) {
-      GRPC_MDELEM_UNREF(orig);
-      l->md = filt;
-    }
-  }
-  assert_valid_list(&batch->list);
-
-  GPR_TIMER_END("grpc_metadata_batch_filter", 0);
-}
-
-static grpc_mdelem *no_metadata_for_you(void *user_data, grpc_mdelem *elem) {
-  return NULL;
-}
-
-void grpc_metadata_batch_clear(grpc_metadata_batch *batch) {
-  batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
-  grpc_metadata_batch_filter(batch, no_metadata_for_you, NULL);
-}
-
-int grpc_metadata_batch_is_empty(grpc_metadata_batch *batch) {
-  return batch->list.head == NULL &&
-         gpr_time_cmp(gpr_inf_future(batch->deadline.clock_type),
-                      batch->deadline) == 0;
-}
diff --git a/src/core/transport/metadata_batch.h b/src/core/transport/metadata_batch.h
deleted file mode 100644
index 1b0d1fd..0000000
--- a/src/core/transport/metadata_batch.h
+++ /dev/null
@@ -1,125 +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_TRANSPORT_STREAM_OP_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_STREAM_OP_H
-
-#include <grpc/grpc.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/time.h>
-#include "src/core/transport/metadata.h"
-
-typedef struct grpc_linked_mdelem {
-  grpc_mdelem *md;
-  struct grpc_linked_mdelem *next;
-  struct grpc_linked_mdelem *prev;
-  void *reserved;
-} grpc_linked_mdelem;
-
-typedef struct grpc_mdelem_list {
-  grpc_linked_mdelem *head;
-  grpc_linked_mdelem *tail;
-} grpc_mdelem_list;
-
-typedef struct grpc_metadata_batch {
-  /** Metadata elements in this batch */
-  grpc_mdelem_list list;
-  /** 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 *batch);
-void grpc_metadata_batch_destroy(grpc_metadata_batch *batch);
-void grpc_metadata_batch_clear(grpc_metadata_batch *batch);
-int grpc_metadata_batch_is_empty(grpc_metadata_batch *batch);
-
-/** 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);
-/** 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);
-
-/** 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);
-/** 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);
-
-/** 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);
-
-#ifndef NDEBUG
-void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd);
-#else
-#define grpc_metadata_batch_assert_ok(comd) \
-  do {                                      \
-  } while (0)
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_TRANSPORT_STREAM_OP_H */
diff --git a/src/core/transport/static_metadata.c b/src/core/transport/static_metadata.c
deleted file mode 100644
index eeedae0..0000000
--- a/src/core/transport/static_metadata.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- * WARNING: Auto-generated code.
- *
- * To make changes to this file, change
- * tools/codegen/core/gen_static_metadata.py,
- * and then re-run it.
- *
- * See metadata.h for an explanation of the interface here, and metadata.c for
- * an
- * explanation of what's going on.
- */
-
-#include "src/core/transport/static_metadata.h"
-
-grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
-
-grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
-uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 3, 7, 5, 2, 4, 8, 6, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] =
-    {11, 35, 10, 35, 12, 35, 12, 49, 13, 35, 14, 35, 15, 35, 16, 35, 17, 35,
-     19, 35, 20, 35, 21, 35, 24, 35, 25, 35, 26, 35, 27, 35, 28, 35, 29, 35,
-     30, 18, 30, 35, 31, 35, 32, 35, 36, 35, 37, 35, 38, 35, 39, 35, 42, 33,
-     42, 34, 42, 48, 42, 53, 42, 54, 42, 55, 42, 56, 43, 33, 43, 48, 43, 53,
-     46, 0,  46, 1,  46, 2,  50, 35, 57, 35, 58, 35, 59, 35, 60, 35, 61, 35,
-     62, 35, 63, 35, 64, 35, 65, 35, 66, 40, 66, 68, 67, 78, 67, 79, 69, 35,
-     70, 35, 71, 35, 72, 35, 73, 35, 74, 35, 75, 41, 75, 51, 75, 52, 76, 35,
-     77, 35, 80, 3,  80, 4,  80, 5,  80, 6,  80, 7,  80, 8,  80, 9,  81, 35,
-     82, 83, 84, 35, 85, 35, 86, 35, 87, 35, 88, 35};
-
-const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = {
-    "0", "1", "2", "200", "204", "206", "304", "400", "404", "500", "accept",
-    "accept-charset", "accept-encoding", "accept-language", "accept-ranges",
-    "access-control-allow-origin", "age", "allow", "application/grpc",
-    ":authority", "authorization", "cache-control", "census-bin",
-    "census-binary-bin", "content-disposition", "content-encoding",
-    "content-language", "content-length", "content-location", "content-range",
-    "content-type", "cookie", "date", "deflate", "deflate,gzip", "", "etag",
-    "expect", "expires", "from", "GET", "grpc", "grpc-accept-encoding",
-    "grpc-encoding", "grpc-internal-encoding-request", "grpc-message",
-    "grpc-status", "grpc-timeout", "gzip", "gzip, deflate", "host", "http",
-    "https", "identity", "identity,deflate", "identity,deflate,gzip",
-    "identity,gzip", "if-match", "if-modified-since", "if-none-match",
-    "if-range", "if-unmodified-since", "last-modified", "link", "location",
-    "max-forwards", ":method", ":path", "POST", "proxy-authenticate",
-    "proxy-authorization", "range", "referer", "refresh", "retry-after",
-    ":scheme", "server", "set-cookie", "/", "/index.html", ":status",
-    "strict-transport-security", "te", "trailers", "transfer-encoding",
-    "user-agent", "vary", "via", "www-authenticate"};
-
-const uint8_t grpc_static_accept_encoding_metadata[8] = {0,  29, 26, 30,
-                                                         28, 32, 27, 31};
diff --git a/src/core/transport/static_metadata.h b/src/core/transport/static_metadata.h
deleted file mode 100644
index ef72b80..0000000
--- a/src/core/transport/static_metadata.h
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- * WARNING: Auto-generated code.
- *
- * To make changes to this file, change
- * tools/codegen/core/gen_static_metadata.py,
- * and then re-run it.
- *
- * See metadata.h for an explanation of the interface here, and metadata.c for
- * an
- * explanation of what's going on.
- */
-
-#ifndef GRPC_INTERNAL_CORE_TRANSPORT_STATIC_METADATA_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_STATIC_METADATA_H
-
-#include "src/core/transport/metadata.h"
-
-#define GRPC_STATIC_MDSTR_COUNT 89
-extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
-/* "0" */
-#define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0])
-/* "1" */
-#define GRPC_MDSTR_1 (&grpc_static_mdstr_table[1])
-/* "2" */
-#define GRPC_MDSTR_2 (&grpc_static_mdstr_table[2])
-/* "200" */
-#define GRPC_MDSTR_200 (&grpc_static_mdstr_table[3])
-/* "204" */
-#define GRPC_MDSTR_204 (&grpc_static_mdstr_table[4])
-/* "206" */
-#define GRPC_MDSTR_206 (&grpc_static_mdstr_table[5])
-/* "304" */
-#define GRPC_MDSTR_304 (&grpc_static_mdstr_table[6])
-/* "400" */
-#define GRPC_MDSTR_400 (&grpc_static_mdstr_table[7])
-/* "404" */
-#define GRPC_MDSTR_404 (&grpc_static_mdstr_table[8])
-/* "500" */
-#define GRPC_MDSTR_500 (&grpc_static_mdstr_table[9])
-/* "accept" */
-#define GRPC_MDSTR_ACCEPT (&grpc_static_mdstr_table[10])
-/* "accept-charset" */
-#define GRPC_MDSTR_ACCEPT_CHARSET (&grpc_static_mdstr_table[11])
-/* "accept-encoding" */
-#define GRPC_MDSTR_ACCEPT_ENCODING (&grpc_static_mdstr_table[12])
-/* "accept-language" */
-#define GRPC_MDSTR_ACCEPT_LANGUAGE (&grpc_static_mdstr_table[13])
-/* "accept-ranges" */
-#define GRPC_MDSTR_ACCEPT_RANGES (&grpc_static_mdstr_table[14])
-/* "access-control-allow-origin" */
-#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (&grpc_static_mdstr_table[15])
-/* "age" */
-#define GRPC_MDSTR_AGE (&grpc_static_mdstr_table[16])
-/* "allow" */
-#define GRPC_MDSTR_ALLOW (&grpc_static_mdstr_table[17])
-/* "application/grpc" */
-#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (&grpc_static_mdstr_table[18])
-/* ":authority" */
-#define GRPC_MDSTR_AUTHORITY (&grpc_static_mdstr_table[19])
-/* "authorization" */
-#define GRPC_MDSTR_AUTHORIZATION (&grpc_static_mdstr_table[20])
-/* "cache-control" */
-#define GRPC_MDSTR_CACHE_CONTROL (&grpc_static_mdstr_table[21])
-/* "census-bin" */
-#define GRPC_MDSTR_CENSUS_BIN (&grpc_static_mdstr_table[22])
-/* "census-binary-bin" */
-#define GRPC_MDSTR_CENSUS_BINARY_BIN (&grpc_static_mdstr_table[23])
-/* "content-disposition" */
-#define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[24])
-/* "content-encoding" */
-#define GRPC_MDSTR_CONTENT_ENCODING (&grpc_static_mdstr_table[25])
-/* "content-language" */
-#define GRPC_MDSTR_CONTENT_LANGUAGE (&grpc_static_mdstr_table[26])
-/* "content-length" */
-#define GRPC_MDSTR_CONTENT_LENGTH (&grpc_static_mdstr_table[27])
-/* "content-location" */
-#define GRPC_MDSTR_CONTENT_LOCATION (&grpc_static_mdstr_table[28])
-/* "content-range" */
-#define GRPC_MDSTR_CONTENT_RANGE (&grpc_static_mdstr_table[29])
-/* "content-type" */
-#define GRPC_MDSTR_CONTENT_TYPE (&grpc_static_mdstr_table[30])
-/* "cookie" */
-#define GRPC_MDSTR_COOKIE (&grpc_static_mdstr_table[31])
-/* "date" */
-#define GRPC_MDSTR_DATE (&grpc_static_mdstr_table[32])
-/* "deflate" */
-#define GRPC_MDSTR_DEFLATE (&grpc_static_mdstr_table[33])
-/* "deflate,gzip" */
-#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (&grpc_static_mdstr_table[34])
-/* "" */
-#define GRPC_MDSTR_EMPTY (&grpc_static_mdstr_table[35])
-/* "etag" */
-#define GRPC_MDSTR_ETAG (&grpc_static_mdstr_table[36])
-/* "expect" */
-#define GRPC_MDSTR_EXPECT (&grpc_static_mdstr_table[37])
-/* "expires" */
-#define GRPC_MDSTR_EXPIRES (&grpc_static_mdstr_table[38])
-/* "from" */
-#define GRPC_MDSTR_FROM (&grpc_static_mdstr_table[39])
-/* "GET" */
-#define GRPC_MDSTR_GET (&grpc_static_mdstr_table[40])
-/* "grpc" */
-#define GRPC_MDSTR_GRPC (&grpc_static_mdstr_table[41])
-/* "grpc-accept-encoding" */
-#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (&grpc_static_mdstr_table[42])
-/* "grpc-encoding" */
-#define GRPC_MDSTR_GRPC_ENCODING (&grpc_static_mdstr_table[43])
-/* "grpc-internal-encoding-request" */
-#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[44])
-/* "grpc-message" */
-#define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[45])
-/* "grpc-status" */
-#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[46])
-/* "grpc-timeout" */
-#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[47])
-/* "gzip" */
-#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[48])
-/* "gzip, deflate" */
-#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[49])
-/* "host" */
-#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[50])
-/* "http" */
-#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[51])
-/* "https" */
-#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[52])
-/* "identity" */
-#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[53])
-/* "identity,deflate" */
-#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[54])
-/* "identity,deflate,gzip" */
-#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
-  (&grpc_static_mdstr_table[55])
-/* "identity,gzip" */
-#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[56])
-/* "if-match" */
-#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[57])
-/* "if-modified-since" */
-#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[58])
-/* "if-none-match" */
-#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[59])
-/* "if-range" */
-#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[60])
-/* "if-unmodified-since" */
-#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[61])
-/* "last-modified" */
-#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[62])
-/* "link" */
-#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[63])
-/* "location" */
-#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[64])
-/* "max-forwards" */
-#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[65])
-/* ":method" */
-#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[66])
-/* ":path" */
-#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[67])
-/* "POST" */
-#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[68])
-/* "proxy-authenticate" */
-#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[69])
-/* "proxy-authorization" */
-#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[70])
-/* "range" */
-#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[71])
-/* "referer" */
-#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[72])
-/* "refresh" */
-#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[73])
-/* "retry-after" */
-#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[74])
-/* ":scheme" */
-#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[75])
-/* "server" */
-#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[76])
-/* "set-cookie" */
-#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[77])
-/* "/" */
-#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[78])
-/* "/index.html" */
-#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[79])
-/* ":status" */
-#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[80])
-/* "strict-transport-security" */
-#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[81])
-/* "te" */
-#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[82])
-/* "trailers" */
-#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[83])
-/* "transfer-encoding" */
-#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[84])
-/* "user-agent" */
-#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[85])
-/* "vary" */
-#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[86])
-/* "via" */
-#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[87])
-/* "www-authenticate" */
-#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[88])
-
-#define GRPC_STATIC_MDELEM_COUNT 78
-extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
-extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
-/* "accept-charset": "" */
-#define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY (&grpc_static_mdelem_table[0])
-/* "accept": "" */
-#define GRPC_MDELEM_ACCEPT_EMPTY (&grpc_static_mdelem_table[1])
-/* "accept-encoding": "" */
-#define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY (&grpc_static_mdelem_table[2])
-/* "accept-encoding": "gzip, deflate" */
-#define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \
-  (&grpc_static_mdelem_table[3])
-/* "accept-language": "" */
-#define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[4])
-/* "accept-ranges": "" */
-#define GRPC_MDELEM_ACCEPT_RANGES_EMPTY (&grpc_static_mdelem_table[5])
-/* "access-control-allow-origin": "" */
-#define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \
-  (&grpc_static_mdelem_table[6])
-/* "age": "" */
-#define GRPC_MDELEM_AGE_EMPTY (&grpc_static_mdelem_table[7])
-/* "allow": "" */
-#define GRPC_MDELEM_ALLOW_EMPTY (&grpc_static_mdelem_table[8])
-/* ":authority": "" */
-#define GRPC_MDELEM_AUTHORITY_EMPTY (&grpc_static_mdelem_table[9])
-/* "authorization": "" */
-#define GRPC_MDELEM_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[10])
-/* "cache-control": "" */
-#define GRPC_MDELEM_CACHE_CONTROL_EMPTY (&grpc_static_mdelem_table[11])
-/* "content-disposition": "" */
-#define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY (&grpc_static_mdelem_table[12])
-/* "content-encoding": "" */
-#define GRPC_MDELEM_CONTENT_ENCODING_EMPTY (&grpc_static_mdelem_table[13])
-/* "content-language": "" */
-#define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY (&grpc_static_mdelem_table[14])
-/* "content-length": "" */
-#define GRPC_MDELEM_CONTENT_LENGTH_EMPTY (&grpc_static_mdelem_table[15])
-/* "content-location": "" */
-#define GRPC_MDELEM_CONTENT_LOCATION_EMPTY (&grpc_static_mdelem_table[16])
-/* "content-range": "" */
-#define GRPC_MDELEM_CONTENT_RANGE_EMPTY (&grpc_static_mdelem_table[17])
-/* "content-type": "application/grpc" */
-#define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \
-  (&grpc_static_mdelem_table[18])
-/* "content-type": "" */
-#define GRPC_MDELEM_CONTENT_TYPE_EMPTY (&grpc_static_mdelem_table[19])
-/* "cookie": "" */
-#define GRPC_MDELEM_COOKIE_EMPTY (&grpc_static_mdelem_table[20])
-/* "date": "" */
-#define GRPC_MDELEM_DATE_EMPTY (&grpc_static_mdelem_table[21])
-/* "etag": "" */
-#define GRPC_MDELEM_ETAG_EMPTY (&grpc_static_mdelem_table[22])
-/* "expect": "" */
-#define GRPC_MDELEM_EXPECT_EMPTY (&grpc_static_mdelem_table[23])
-/* "expires": "" */
-#define GRPC_MDELEM_EXPIRES_EMPTY (&grpc_static_mdelem_table[24])
-/* "from": "" */
-#define GRPC_MDELEM_FROM_EMPTY (&grpc_static_mdelem_table[25])
-/* "grpc-accept-encoding": "deflate" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE (&grpc_static_mdelem_table[26])
-/* "grpc-accept-encoding": "deflate,gzip" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \
-  (&grpc_static_mdelem_table[27])
-/* "grpc-accept-encoding": "gzip" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP (&grpc_static_mdelem_table[28])
-/* "grpc-accept-encoding": "identity" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \
-  (&grpc_static_mdelem_table[29])
-/* "grpc-accept-encoding": "identity,deflate" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \
-  (&grpc_static_mdelem_table[30])
-/* "grpc-accept-encoding": "identity,deflate,gzip" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
-  (&grpc_static_mdelem_table[31])
-/* "grpc-accept-encoding": "identity,gzip" */
-#define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \
-  (&grpc_static_mdelem_table[32])
-/* "grpc-encoding": "deflate" */
-#define GRPC_MDELEM_GRPC_ENCODING_DEFLATE (&grpc_static_mdelem_table[33])
-/* "grpc-encoding": "gzip" */
-#define GRPC_MDELEM_GRPC_ENCODING_GZIP (&grpc_static_mdelem_table[34])
-/* "grpc-encoding": "identity" */
-#define GRPC_MDELEM_GRPC_ENCODING_IDENTITY (&grpc_static_mdelem_table[35])
-/* "grpc-status": "0" */
-#define GRPC_MDELEM_GRPC_STATUS_0 (&grpc_static_mdelem_table[36])
-/* "grpc-status": "1" */
-#define GRPC_MDELEM_GRPC_STATUS_1 (&grpc_static_mdelem_table[37])
-/* "grpc-status": "2" */
-#define GRPC_MDELEM_GRPC_STATUS_2 (&grpc_static_mdelem_table[38])
-/* "host": "" */
-#define GRPC_MDELEM_HOST_EMPTY (&grpc_static_mdelem_table[39])
-/* "if-match": "" */
-#define GRPC_MDELEM_IF_MATCH_EMPTY (&grpc_static_mdelem_table[40])
-/* "if-modified-since": "" */
-#define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[41])
-/* "if-none-match": "" */
-#define GRPC_MDELEM_IF_NONE_MATCH_EMPTY (&grpc_static_mdelem_table[42])
-/* "if-range": "" */
-#define GRPC_MDELEM_IF_RANGE_EMPTY (&grpc_static_mdelem_table[43])
-/* "if-unmodified-since": "" */
-#define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[44])
-/* "last-modified": "" */
-#define GRPC_MDELEM_LAST_MODIFIED_EMPTY (&grpc_static_mdelem_table[45])
-/* "link": "" */
-#define GRPC_MDELEM_LINK_EMPTY (&grpc_static_mdelem_table[46])
-/* "location": "" */
-#define GRPC_MDELEM_LOCATION_EMPTY (&grpc_static_mdelem_table[47])
-/* "max-forwards": "" */
-#define GRPC_MDELEM_MAX_FORWARDS_EMPTY (&grpc_static_mdelem_table[48])
-/* ":method": "GET" */
-#define GRPC_MDELEM_METHOD_GET (&grpc_static_mdelem_table[49])
-/* ":method": "POST" */
-#define GRPC_MDELEM_METHOD_POST (&grpc_static_mdelem_table[50])
-/* ":path": "/" */
-#define GRPC_MDELEM_PATH_SLASH (&grpc_static_mdelem_table[51])
-/* ":path": "/index.html" */
-#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (&grpc_static_mdelem_table[52])
-/* "proxy-authenticate": "" */
-#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[53])
-/* "proxy-authorization": "" */
-#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[54])
-/* "range": "" */
-#define GRPC_MDELEM_RANGE_EMPTY (&grpc_static_mdelem_table[55])
-/* "referer": "" */
-#define GRPC_MDELEM_REFERER_EMPTY (&grpc_static_mdelem_table[56])
-/* "refresh": "" */
-#define GRPC_MDELEM_REFRESH_EMPTY (&grpc_static_mdelem_table[57])
-/* "retry-after": "" */
-#define GRPC_MDELEM_RETRY_AFTER_EMPTY (&grpc_static_mdelem_table[58])
-/* ":scheme": "grpc" */
-#define GRPC_MDELEM_SCHEME_GRPC (&grpc_static_mdelem_table[59])
-/* ":scheme": "http" */
-#define GRPC_MDELEM_SCHEME_HTTP (&grpc_static_mdelem_table[60])
-/* ":scheme": "https" */
-#define GRPC_MDELEM_SCHEME_HTTPS (&grpc_static_mdelem_table[61])
-/* "server": "" */
-#define GRPC_MDELEM_SERVER_EMPTY (&grpc_static_mdelem_table[62])
-/* "set-cookie": "" */
-#define GRPC_MDELEM_SET_COOKIE_EMPTY (&grpc_static_mdelem_table[63])
-/* ":status": "200" */
-#define GRPC_MDELEM_STATUS_200 (&grpc_static_mdelem_table[64])
-/* ":status": "204" */
-#define GRPC_MDELEM_STATUS_204 (&grpc_static_mdelem_table[65])
-/* ":status": "206" */
-#define GRPC_MDELEM_STATUS_206 (&grpc_static_mdelem_table[66])
-/* ":status": "304" */
-#define GRPC_MDELEM_STATUS_304 (&grpc_static_mdelem_table[67])
-/* ":status": "400" */
-#define GRPC_MDELEM_STATUS_400 (&grpc_static_mdelem_table[68])
-/* ":status": "404" */
-#define GRPC_MDELEM_STATUS_404 (&grpc_static_mdelem_table[69])
-/* ":status": "500" */
-#define GRPC_MDELEM_STATUS_500 (&grpc_static_mdelem_table[70])
-/* "strict-transport-security": "" */
-#define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
-  (&grpc_static_mdelem_table[71])
-/* "te": "trailers" */
-#define GRPC_MDELEM_TE_TRAILERS (&grpc_static_mdelem_table[72])
-/* "transfer-encoding": "" */
-#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (&grpc_static_mdelem_table[73])
-/* "user-agent": "" */
-#define GRPC_MDELEM_USER_AGENT_EMPTY (&grpc_static_mdelem_table[74])
-/* "vary": "" */
-#define GRPC_MDELEM_VARY_EMPTY (&grpc_static_mdelem_table[75])
-/* "via": "" */
-#define GRPC_MDELEM_VIA_EMPTY (&grpc_static_mdelem_table[76])
-/* "www-authenticate": "" */
-#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[77])
-
-extern const uint8_t
-    grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2];
-extern const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT];
-extern const uint8_t grpc_static_accept_encoding_metadata[8];
-#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \
-  (&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]])
-#endif /* GRPC_INTERNAL_CORE_TRANSPORT_STATIC_METADATA_H */
diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c
deleted file mode 100644
index 3b555fa..0000000
--- a/src/core/transport/transport.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/transport/transport.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/atm.h>
-#include <grpc/support/log.h>
-#include "src/core/transport/transport_impl.h"
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason) {
-  gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count);
-  gpr_log(GPR_DEBUG, "%s %p:%p   REF %d->%d %s", refcount->object_type,
-          refcount, refcount->destroy.cb_arg, val, val + 1, reason);
-#else
-void grpc_stream_ref(grpc_stream_refcount *refcount) {
-#endif
-  gpr_ref_non_zero(&refcount->refs);
-}
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount,
-                       const char *reason) {
-  gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count);
-  gpr_log(GPR_DEBUG, "%s %p:%p UNREF %d->%d %s", refcount->object_type,
-          refcount, refcount->destroy.cb_arg, val, val - 1, reason);
-#else
-void grpc_stream_unref(grpc_exec_ctx *exec_ctx,
-                       grpc_stream_refcount *refcount) {
-#endif
-  if (gpr_unref(&refcount->refs)) {
-    grpc_exec_ctx_enqueue(exec_ctx, &refcount->destroy, true, NULL);
-  }
-}
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
-                          grpc_iomgr_cb_func cb, void *cb_arg,
-                          const char *object_type) {
-  refcount->object_type = object_type;
-#else
-void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
-                          grpc_iomgr_cb_func cb, void *cb_arg) {
-#endif
-  gpr_ref_init(&refcount->refs, initial_refs);
-  grpc_closure_init(&refcount->destroy, cb, cb_arg);
-}
-
-size_t grpc_transport_stream_size(grpc_transport *transport) {
-  return transport->vtable->sizeof_stream;
-}
-
-void grpc_transport_destroy(grpc_exec_ctx *exec_ctx,
-                            grpc_transport *transport) {
-  transport->vtable->destroy(exec_ctx, transport);
-}
-
-int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx,
-                               grpc_transport *transport, grpc_stream *stream,
-                               grpc_stream_refcount *refcount,
-                               const void *server_data) {
-  return transport->vtable->init_stream(exec_ctx, transport, stream, refcount,
-                                        server_data);
-}
-
-void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx,
-                                      grpc_transport *transport,
-                                      grpc_stream *stream,
-                                      grpc_transport_stream_op *op) {
-  transport->vtable->perform_stream_op(exec_ctx, transport, stream, op);
-}
-
-void grpc_transport_perform_op(grpc_exec_ctx *exec_ctx,
-                               grpc_transport *transport,
-                               grpc_transport_op *op) {
-  transport->vtable->perform_op(exec_ctx, transport, op);
-}
-
-void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx,
-                                grpc_transport *transport, grpc_stream *stream,
-                                grpc_pollset *pollset) {
-  transport->vtable->set_pollset(exec_ctx, transport, stream, pollset);
-}
-
-void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
-                                   grpc_transport *transport,
-                                   grpc_stream *stream) {
-  transport->vtable->destroy_stream(exec_ctx, transport, stream);
-}
-
-char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
-                              grpc_transport *transport) {
-  return transport->vtable->get_peer(exec_ctx, transport);
-}
-
-void grpc_transport_stream_op_finish_with_failure(
-    grpc_exec_ctx *exec_ctx, grpc_transport_stream_op *op) {
-  grpc_exec_ctx_enqueue(exec_ctx, op->recv_message_ready, false, NULL);
-  grpc_exec_ctx_enqueue(exec_ctx, op->recv_initial_metadata_ready, false, NULL);
-  grpc_exec_ctx_enqueue(exec_ctx, op->on_complete, false, NULL);
-}
-
-void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
-                                               grpc_status_code status) {
-  GPR_ASSERT(status != GRPC_STATUS_OK);
-  if (op->cancel_with_status == GRPC_STATUS_OK) {
-    op->cancel_with_status = status;
-  }
-  if (op->close_with_status != GRPC_STATUS_OK) {
-    op->close_with_status = GRPC_STATUS_OK;
-    if (op->optional_close_message != NULL) {
-      gpr_slice_unref(*op->optional_close_message);
-      op->optional_close_message = NULL;
-    }
-  }
-}
-
-typedef struct {
-  gpr_slice message;
-  grpc_closure *then_call;
-  grpc_closure closure;
-} close_message_data;
-
-static void free_message(grpc_exec_ctx *exec_ctx, void *p, bool iomgr_success) {
-  close_message_data *cmd = p;
-  gpr_slice_unref(cmd->message);
-  if (cmd->then_call != NULL) {
-    cmd->then_call->cb(exec_ctx, cmd->then_call->cb_arg, iomgr_success);
-  }
-  gpr_free(cmd);
-}
-
-void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op,
-                                        grpc_status_code status,
-                                        gpr_slice *optional_message) {
-  close_message_data *cmd;
-  GPR_ASSERT(status != GRPC_STATUS_OK);
-  if (op->cancel_with_status != GRPC_STATUS_OK ||
-      op->close_with_status != GRPC_STATUS_OK) {
-    if (optional_message) {
-      gpr_slice_unref(*optional_message);
-    }
-    return;
-  }
-  if (optional_message) {
-    cmd = gpr_malloc(sizeof(*cmd));
-    cmd->message = *optional_message;
-    cmd->then_call = op->on_complete;
-    grpc_closure_init(&cmd->closure, free_message, cmd);
-    op->on_complete = &cmd->closure;
-    op->optional_close_message = &cmd->message;
-  }
-  op->close_with_status = status;
-}
diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h
deleted file mode 100644
index ed6e121..0000000
--- a/src/core/transport/transport.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_H
-
-#include <stddef.h>
-
-#include "src/core/iomgr/pollset.h"
-#include "src/core/iomgr/pollset_set.h"
-#include "src/core/transport/metadata_batch.h"
-#include "src/core/transport/byte_stream.h"
-#include "src/core/channel/context.h"
-
-/* forward declarations */
-typedef struct grpc_transport grpc_transport;
-
-/* grpc_stream doesn't actually exist. It's used as a typesafe
-   opaque pointer for whatever data the transport wants to track
-   for a stream. */
-typedef struct grpc_stream grpc_stream;
-
-/*#define GRPC_STREAM_REFCOUNT_DEBUG*/
-
-typedef struct grpc_stream_refcount {
-  gpr_refcount refs;
-  grpc_closure destroy;
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-  const char *object_type;
-#endif
-} grpc_stream_refcount;
-
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
-                          grpc_iomgr_cb_func cb, void *cb_arg,
-                          const char *object_type);
-void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason);
-void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount,
-                       const char *reason);
-#define GRPC_STREAM_REF_INIT(rc, ir, cb, cb_arg, objtype) \
-  grpc_stream_ref_init(rc, ir, cb, cb_arg, objtype)
-#else
-void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
-                          grpc_iomgr_cb_func cb, void *cb_arg);
-void grpc_stream_ref(grpc_stream_refcount *refcount);
-void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount);
-#define GRPC_STREAM_REF_INIT(rc, ir, cb, cb_arg, objtype) \
-  grpc_stream_ref_init(rc, ir, cb, cb_arg)
-#endif
-
-/* Transport stream op: a set of operations to perform on a transport
-   against a single stream */
-typedef struct grpc_transport_stream_op {
-  /** Send initial metadata to the peer, from the provided metadata batch. */
-  grpc_metadata_batch *send_initial_metadata;
-
-  /** Send trailing metadata to the peer, from the provided metadata batch. */
-  grpc_metadata_batch *send_trailing_metadata;
-
-  /** Send message data to the peer, from the provided byte stream. */
-  grpc_byte_stream *send_message;
-
-  /** Receive initial metadata from the stream, into provided metadata batch. */
-  grpc_metadata_batch *recv_initial_metadata;
-  /** Should be enqueued when initial metadata is ready to be processed. */
-  grpc_closure *recv_initial_metadata_ready;
-
-  /** Receive message data from the stream, into provided byte stream. */
-  grpc_byte_stream **recv_message;
-  /** Should be enqueued when one message is ready to be processed. */
-  grpc_closure *recv_message_ready;
-
-  /** Receive trailing metadata from the stream, into provided metadata batch.
-   */
-  grpc_metadata_batch *recv_trailing_metadata;
-
-  /** Should be enqueued when all requested operations (excluding recv_message
-      and recv_initial_metadata which have their own closures) in a given batch
-      have been completed. */
-  grpc_closure *on_complete;
-
-  /** If != GRPC_STATUS_OK, cancel this stream */
-  grpc_status_code cancel_with_status;
-
-  /** If != GRPC_STATUS_OK, send grpc-status, grpc-message, and close this
-      stream for both reading and writing */
-  grpc_status_code close_with_status;
-  gpr_slice *optional_close_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_closure *on_consumed;
-  /** connectivity monitoring - set connectivity_state to NULL to unsubscribe */
-  grpc_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.
-      If true, the callback is set to set_accept_stream_fn, with its
-      user_data argument set to set_accept_stream_user_data */
-  bool set_accept_stream;
-  void (*set_accept_stream_fn)(grpc_exec_ctx *exec_ctx, 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;
-  /** add this transport to a pollset_set */
-  grpc_pollset_set *bind_pollset_set;
-  /** send a ping, call this back if not NULL */
-  grpc_closure *send_ping;
-} grpc_transport_op;
-
-/* Returns the amount of memory required to store a grpc_stream for this
-   transport */
-size_t grpc_transport_stream_size(grpc_transport *transport);
-
-/* Initialize transport data for a stream.
-
-   Returns 0 on success, any other (transport-defined) value for failure.
-
-   Arguments:
-     transport   - the transport on which to create this stream
-     stream      - a pointer to uninitialized memory to initialize
-     server_data - either NULL for a client initiated stream, or a pointer
-                   supplied from the accept_stream callback function */
-int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx,
-                               grpc_transport *transport, grpc_stream *stream,
-                               grpc_stream_refcount *refcount,
-                               const void *server_data);
-
-void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx,
-                                grpc_transport *transport, grpc_stream *stream,
-                                grpc_pollset *pollset);
-
-/* Destroy transport data for a stream.
-
-   Requires: a recv_batch with final_state == GRPC_STREAM_CLOSED has been
-   received by the up-layer. Must not be called in the same call stack as
-   recv_frame.
-
-   Arguments:
-     transport - the transport on which to create this stream
-     stream    - the grpc_stream to destroy (memory is still owned by the
-                 caller, but any child memory must be cleaned up) */
-void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
-                                   grpc_transport *transport,
-                                   grpc_stream *stream);
-
-void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
-                                                  grpc_transport_stream_op *op);
-
-void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
-                                               grpc_status_code status);
-
-void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op,
-                                        grpc_status_code status,
-                                        gpr_slice *optional_message);
-
-char *grpc_transport_stream_op_string(grpc_transport_stream_op *op);
-
-/* Send a batch of operations on a transport
-
-   Takes ownership of any objects contained in ops.
-
-   Arguments:
-     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_stream_op specifying the op to perform */
-void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx,
-                                      grpc_transport *transport,
-                                      grpc_stream *stream,
-                                      grpc_transport_stream_op *op);
-
-void grpc_transport_perform_op(grpc_exec_ctx *exec_ctx,
-                               grpc_transport *transport,
-                               grpc_transport_op *op);
-
-/* Send a ping on a transport
-
-   Calls cb with user data when a response is received. */
-void grpc_transport_ping(grpc_transport *transport, grpc_closure *cb);
-
-/* Advise peer of pending connection termination. */
-void grpc_transport_goaway(grpc_transport *transport, grpc_status_code status,
-                           gpr_slice debug_data);
-
-/* Close a transport. Aborts all open streams. */
-void grpc_transport_close(grpc_transport *transport);
-
-/* Destroy the transport */
-void grpc_transport_destroy(grpc_exec_ctx *exec_ctx, grpc_transport *transport);
-
-/* Get the transports peer */
-char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
-                              grpc_transport *transport);
-
-#endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_H */
diff --git a/src/core/transport/transport_impl.h b/src/core/transport/transport_impl.h
deleted file mode 100644
index 40bfb4b..0000000
--- a/src/core/transport/transport_impl.h
+++ /dev/null
@@ -1,78 +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_TRANSPORT_TRANSPORT_IMPL_H
-#define GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_IMPL_H
-
-#include "src/core/transport/transport.h"
-
-typedef struct grpc_transport_vtable {
-  /* Memory required for a single stream element - this is allocated by upper
-     layers and initialized by the transport */
-  size_t sizeof_stream; /* = sizeof(transport stream) */
-
-  /* implementation of grpc_transport_init_stream */
-  int (*init_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
-                     grpc_stream *stream, grpc_stream_refcount *refcount,
-                     const void *server_data);
-
-  /* implementation of grpc_transport_set_pollset */
-  void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
-                      grpc_stream *stream, grpc_pollset *pollset);
-
-  /* implementation of grpc_transport_perform_stream_op */
-  void (*perform_stream_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
-                            grpc_stream *stream, grpc_transport_stream_op *op);
-
-  /* implementation of grpc_transport_perform_op */
-  void (*perform_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
-                     grpc_transport_op *op);
-
-  /* implementation of grpc_transport_destroy_stream */
-  void (*destroy_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
-                         grpc_stream *stream);
-
-  /* implementation of grpc_transport_destroy */
-  void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_transport *self);
-
-  /* implementation of grpc_transport_get_peer */
-  char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_transport *self);
-} grpc_transport_vtable;
-
-/* an instance of a grpc transport */
-struct grpc_transport {
-  /* pointer to a vtable defining operations on this transport */
-  const grpc_transport_vtable *vtable;
-};
-
-#endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_IMPL_H */
diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c
deleted file mode 100644
index 98b51af..0000000
--- a/src/core/transport/transport_op_string.c
+++ /dev/null
@@ -1,140 +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/channel_stack.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "src/core/support/string.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
-
-/* These routines are here to facilitate debugging - they produce string
-   representations of various transport data structures */
-
-static void put_metadata(gpr_strvec *b, grpc_mdelem *md) {
-  gpr_strvec_add(b, gpr_strdup("key="));
-  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_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
-}
-
-static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) {
-  grpc_linked_mdelem *m;
-  for (m = md.list.head; m != NULL; m = m->next) {
-    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(md.deadline.clock_type)) != 0) {
-    char *tmp;
-    gpr_asprintf(&tmp, " deadline=%lld.%09d", (long long)md.deadline.tv_sec,
-                 (int)md.deadline.tv_nsec);
-    gpr_strvec_add(b, tmp);
-  }
-}
-
-char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) {
-  char *tmp;
-  char *out;
-  int first = 1;
-
-  gpr_strvec b;
-  gpr_strvec_init(&b);
-
-  if (op->send_initial_metadata != NULL) {
-    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
-    first = 0;
-    gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA{"));
-    put_metadata_list(&b, *op->send_initial_metadata);
-    gpr_strvec_add(&b, gpr_strdup("}"));
-  }
-
-  if (op->send_message != NULL) {
-    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
-    first = 0;
-    gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d",
-                 op->send_message->flags, op->send_message->length);
-    gpr_strvec_add(&b, tmp);
-  }
-
-  if (op->send_trailing_metadata != NULL) {
-    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
-    first = 0;
-    gpr_strvec_add(&b, gpr_strdup("SEND_TRAILING_METADATA{"));
-    put_metadata_list(&b, *op->send_trailing_metadata);
-    gpr_strvec_add(&b, gpr_strdup("}"));
-  }
-
-  if (op->recv_initial_metadata != NULL) {
-    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
-    first = 0;
-    gpr_strvec_add(&b, gpr_strdup("RECV_INITIAL_METADATA"));
-  }
-
-  if (op->recv_message != NULL) {
-    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
-    first = 0;
-    gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE"));
-  }
-
-  if (op->recv_trailing_metadata != NULL) {
-    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
-    first = 0;
-    gpr_strvec_add(&b, gpr_strdup("RECV_TRAILING_METADATA"));
-  }
-
-  if (op->cancel_with_status != GRPC_STATUS_OK) {
-    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
-    first = 0;
-    gpr_asprintf(&tmp, "CANCEL:%d", op->cancel_with_status);
-    gpr_strvec_add(&b, tmp);
-  }
-
-  out = gpr_strvec_flatten(&b, NULL);
-  gpr_strvec_destroy(&b);
-
-  return out;
-}
-
-void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
-                      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/fake_transport_security.c b/src/core/tsi/fake_transport_security.c
deleted file mode 100644
index 72ac32a..0000000
--- a/src/core/tsi/fake_transport_security.c
+++ /dev/null
@@ -1,525 +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/tsi/fake_transport_security.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/useful.h>
-#include "src/core/tsi/transport_security.h"
-
-/* --- Constants. ---*/
-#define TSI_FAKE_FRAME_HEADER_SIZE 4
-#define TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE 64
-#define TSI_FAKE_DEFAULT_FRAME_SIZE 16384
-
-/* --- Structure definitions. ---*/
-
-/* a frame is encoded like this:
-   | size |     data    |
-   where the size field value is the size of the size field plus the size of
-   the data encoded in little endian on 4 bytes.  */
-typedef struct {
-  unsigned char *data;
-  size_t size;
-  size_t allocated_size;
-  size_t offset;
-  int needs_draining;
-} tsi_fake_frame;
-
-typedef enum {
-  TSI_FAKE_CLIENT_INIT = 0,
-  TSI_FAKE_SERVER_INIT = 1,
-  TSI_FAKE_CLIENT_FINISHED = 2,
-  TSI_FAKE_SERVER_FINISHED = 3,
-  TSI_FAKE_HANDSHAKE_MESSAGE_MAX = 4
-} tsi_fake_handshake_message;
-
-typedef struct {
-  tsi_handshaker base;
-  int is_client;
-  tsi_fake_handshake_message next_message_to_send;
-  int needs_incoming_message;
-  tsi_fake_frame incoming;
-  tsi_fake_frame outgoing;
-  tsi_result result;
-} tsi_fake_handshaker;
-
-typedef struct {
-  tsi_frame_protector base;
-  tsi_fake_frame protect_frame;
-  tsi_fake_frame unprotect_frame;
-  size_t max_frame_size;
-} tsi_fake_frame_protector;
-
-/* --- Utils. ---*/
-
-static const char *tsi_fake_handshake_message_strings[] = {
-    "CLIENT_INIT", "SERVER_INIT", "CLIENT_FINISHED", "SERVER_FINISHED"};
-
-static const char *tsi_fake_handshake_message_to_string(int msg) {
-  if (msg < 0 || msg >= TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
-    gpr_log(GPR_ERROR, "Invalid message %d", msg);
-    return "UNKNOWN";
-  }
-  return tsi_fake_handshake_message_strings[msg];
-}
-
-static tsi_result tsi_fake_handshake_message_from_string(
-    const char *msg_string, tsi_fake_handshake_message *msg) {
-  tsi_fake_handshake_message i;
-  for (i = 0; i < TSI_FAKE_HANDSHAKE_MESSAGE_MAX; i++) {
-    if (strncmp(msg_string, tsi_fake_handshake_message_strings[i],
-                strlen(tsi_fake_handshake_message_strings[i])) == 0) {
-      *msg = i;
-      return TSI_OK;
-    }
-  }
-  gpr_log(GPR_ERROR, "Invalid handshake message.");
-  return TSI_DATA_CORRUPTED;
-}
-
-static uint32_t load32_little_endian(const unsigned char *buf) {
-  return ((uint32_t)(buf[0]) | (uint32_t)(buf[1] << 8) |
-          (uint32_t)(buf[2] << 16) | (uint32_t)(buf[3] << 24));
-}
-
-static void store32_little_endian(uint32_t value, unsigned char *buf) {
-  buf[3] = (unsigned char)((value >> 24) & 0xFF);
-  buf[2] = (unsigned char)((value >> 16) & 0xFF);
-  buf[1] = (unsigned char)((value >> 8) & 0xFF);
-  buf[0] = (unsigned char)((value)&0xFF);
-}
-
-static void tsi_fake_frame_reset(tsi_fake_frame *frame, int needs_draining) {
-  frame->offset = 0;
-  frame->needs_draining = needs_draining;
-  if (!needs_draining) frame->size = 0;
-}
-
-/* Returns 1 if successful, 0 otherwise. */
-static int tsi_fake_frame_ensure_size(tsi_fake_frame *frame) {
-  if (frame->data == NULL) {
-    frame->allocated_size = frame->size;
-    frame->data = malloc(frame->allocated_size);
-    if (frame->data == NULL) return 0;
-  } else if (frame->size > frame->allocated_size) {
-    unsigned char *new_data = realloc(frame->data, frame->size);
-    if (new_data == NULL) {
-      free(frame->data);
-      frame->data = NULL;
-      return 0;
-    }
-    frame->data = new_data;
-    frame->allocated_size = frame->size;
-  }
-  return 1;
-}
-
-/* This method should not be called if frame->needs_framing is not 0.  */
-static tsi_result fill_frame_from_bytes(const unsigned char *incoming_bytes,
-                                        size_t *incoming_bytes_size,
-                                        tsi_fake_frame *frame) {
-  size_t available_size = *incoming_bytes_size;
-  size_t to_read_size = 0;
-  const unsigned char *bytes_cursor = incoming_bytes;
-
-  if (frame->needs_draining) return TSI_INTERNAL_ERROR;
-  if (frame->data == NULL) {
-    frame->allocated_size = TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE;
-    frame->data = malloc(frame->allocated_size);
-    if (frame->data == NULL) return TSI_OUT_OF_RESOURCES;
-  }
-
-  if (frame->offset < TSI_FAKE_FRAME_HEADER_SIZE) {
-    to_read_size = TSI_FAKE_FRAME_HEADER_SIZE - frame->offset;
-    if (to_read_size > available_size) {
-      /* Just fill what we can and exit. */
-      memcpy(frame->data + frame->offset, bytes_cursor, available_size);
-      bytes_cursor += available_size;
-      frame->offset += available_size;
-      *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes);
-      return TSI_INCOMPLETE_DATA;
-    }
-    memcpy(frame->data + frame->offset, bytes_cursor, to_read_size);
-    bytes_cursor += to_read_size;
-    frame->offset += to_read_size;
-    available_size -= to_read_size;
-    frame->size = load32_little_endian(frame->data);
-    if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES;
-  }
-
-  to_read_size = frame->size - frame->offset;
-  if (to_read_size > available_size) {
-    memcpy(frame->data + frame->offset, bytes_cursor, available_size);
-    frame->offset += available_size;
-    bytes_cursor += available_size;
-    *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes);
-    return TSI_INCOMPLETE_DATA;
-  }
-  memcpy(frame->data + frame->offset, bytes_cursor, to_read_size);
-  bytes_cursor += to_read_size;
-  *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes);
-  tsi_fake_frame_reset(frame, 1 /* needs_draining */);
-  return TSI_OK;
-}
-
-/* This method should not be called if frame->needs_framing is 0.  */
-static tsi_result drain_frame_to_bytes(unsigned char *outgoing_bytes,
-                                       size_t *outgoing_bytes_size,
-                                       tsi_fake_frame *frame) {
-  size_t to_write_size = frame->size - frame->offset;
-  if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
-  if (*outgoing_bytes_size < to_write_size) {
-    memcpy(outgoing_bytes, frame->data + frame->offset, *outgoing_bytes_size);
-    frame->offset += *outgoing_bytes_size;
-    return TSI_INCOMPLETE_DATA;
-  }
-  memcpy(outgoing_bytes, frame->data + frame->offset, to_write_size);
-  *outgoing_bytes_size = to_write_size;
-  tsi_fake_frame_reset(frame, 0 /* needs_draining */);
-  return TSI_OK;
-}
-
-static tsi_result bytes_to_frame(unsigned char *bytes, size_t bytes_size,
-                                 tsi_fake_frame *frame) {
-  frame->offset = 0;
-  frame->size = bytes_size + TSI_FAKE_FRAME_HEADER_SIZE;
-  if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES;
-  store32_little_endian((uint32_t)frame->size, frame->data);
-  memcpy(frame->data + TSI_FAKE_FRAME_HEADER_SIZE, bytes, bytes_size);
-  tsi_fake_frame_reset(frame, 1 /* needs draining */);
-  return TSI_OK;
-}
-
-static void tsi_fake_frame_destruct(tsi_fake_frame *frame) {
-  if (frame->data != NULL) free(frame->data);
-}
-
-/* --- tsi_frame_protector methods implementation. ---*/
-
-static tsi_result fake_protector_protect(tsi_frame_protector *self,
-                                         const unsigned char *unprotected_bytes,
-                                         size_t *unprotected_bytes_size,
-                                         unsigned char *protected_output_frames,
-                                         size_t *protected_output_frames_size) {
-  tsi_result result = TSI_OK;
-  tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
-  unsigned char frame_header[TSI_FAKE_FRAME_HEADER_SIZE];
-  tsi_fake_frame *frame = &impl->protect_frame;
-  size_t saved_output_size = *protected_output_frames_size;
-  size_t drained_size = 0;
-  size_t *num_bytes_written = protected_output_frames_size;
-  *num_bytes_written = 0;
-
-  /* Try to drain first. */
-  if (frame->needs_draining) {
-    drained_size = saved_output_size - *num_bytes_written;
-    result =
-        drain_frame_to_bytes(protected_output_frames, &drained_size, frame);
-    *num_bytes_written += drained_size;
-    protected_output_frames += drained_size;
-    if (result != TSI_OK) {
-      if (result == TSI_INCOMPLETE_DATA) {
-        *unprotected_bytes_size = 0;
-        result = TSI_OK;
-      }
-      return result;
-    }
-  }
-
-  /* Now process the unprotected_bytes. */
-  if (frame->needs_draining) return TSI_INTERNAL_ERROR;
-  if (frame->size == 0) {
-    /* New frame, create a header. */
-    size_t written_in_frame_size = 0;
-    store32_little_endian((uint32_t)impl->max_frame_size, frame_header);
-    written_in_frame_size = TSI_FAKE_FRAME_HEADER_SIZE;
-    result = fill_frame_from_bytes(frame_header, &written_in_frame_size, frame);
-    if (result != TSI_INCOMPLETE_DATA) {
-      gpr_log(GPR_ERROR, "fill_frame_from_bytes returned %s",
-              tsi_result_to_string(result));
-      return result;
-    }
-  }
-  result =
-      fill_frame_from_bytes(unprotected_bytes, unprotected_bytes_size, frame);
-  if (result != TSI_OK) {
-    if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
-    return result;
-  }
-
-  /* Try to drain again. */
-  if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
-  if (frame->offset != 0) return TSI_INTERNAL_ERROR;
-  drained_size = saved_output_size - *num_bytes_written;
-  result = drain_frame_to_bytes(protected_output_frames, &drained_size, frame);
-  *num_bytes_written += drained_size;
-  if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
-  return result;
-}
-
-static tsi_result fake_protector_protect_flush(
-    tsi_frame_protector *self, unsigned char *protected_output_frames,
-    size_t *protected_output_frames_size, size_t *still_pending_size) {
-  tsi_result result = TSI_OK;
-  tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
-  tsi_fake_frame *frame = &impl->protect_frame;
-  if (!frame->needs_draining) {
-    /* Create a short frame. */
-    frame->size = frame->offset;
-    frame->offset = 0;
-    frame->needs_draining = 1;
-    store32_little_endian((uint32_t)frame->size,
-                          frame->data); /* Overwrite header. */
-  }
-  result = drain_frame_to_bytes(protected_output_frames,
-                                protected_output_frames_size, frame);
-  if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
-  *still_pending_size = frame->size - frame->offset;
-  return result;
-}
-
-static tsi_result fake_protector_unprotect(
-    tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
-    size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
-    size_t *unprotected_bytes_size) {
-  tsi_result result = TSI_OK;
-  tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
-  tsi_fake_frame *frame = &impl->unprotect_frame;
-  size_t saved_output_size = *unprotected_bytes_size;
-  size_t drained_size = 0;
-  size_t *num_bytes_written = unprotected_bytes_size;
-  *num_bytes_written = 0;
-
-  /* Try to drain first. */
-  if (frame->needs_draining) {
-    /* Go past the header if needed. */
-    if (frame->offset == 0) frame->offset = TSI_FAKE_FRAME_HEADER_SIZE;
-    drained_size = saved_output_size - *num_bytes_written;
-    result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame);
-    unprotected_bytes += drained_size;
-    *num_bytes_written += drained_size;
-    if (result != TSI_OK) {
-      if (result == TSI_INCOMPLETE_DATA) {
-        *protected_frames_bytes_size = 0;
-        result = TSI_OK;
-      }
-      return result;
-    }
-  }
-
-  /* Now process the protected_bytes. */
-  if (frame->needs_draining) return TSI_INTERNAL_ERROR;
-  result = fill_frame_from_bytes(protected_frames_bytes,
-                                 protected_frames_bytes_size, frame);
-  if (result != TSI_OK) {
-    if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
-    return result;
-  }
-
-  /* Try to drain again. */
-  if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
-  if (frame->offset != 0) return TSI_INTERNAL_ERROR;
-  frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; /* Go past the header. */
-  drained_size = saved_output_size - *num_bytes_written;
-  result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame);
-  *num_bytes_written += drained_size;
-  if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
-  return result;
-}
-
-static void fake_protector_destroy(tsi_frame_protector *self) {
-  tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
-  tsi_fake_frame_destruct(&impl->protect_frame);
-  tsi_fake_frame_destruct(&impl->unprotect_frame);
-  free(self);
-}
-
-static const tsi_frame_protector_vtable frame_protector_vtable = {
-    fake_protector_protect, fake_protector_protect_flush,
-    fake_protector_unprotect, fake_protector_destroy,
-};
-
-/* --- tsi_handshaker methods implementation. ---*/
-
-static tsi_result fake_handshaker_get_bytes_to_send_to_peer(
-    tsi_handshaker *self, unsigned char *bytes, size_t *bytes_size) {
-  tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
-  tsi_result result = TSI_OK;
-  if (impl->needs_incoming_message || impl->result == TSI_OK) {
-    *bytes_size = 0;
-    return TSI_OK;
-  }
-  if (!impl->outgoing.needs_draining) {
-    tsi_fake_handshake_message next_message_to_send =
-        impl->next_message_to_send + 2;
-    const char *msg_string =
-        tsi_fake_handshake_message_to_string(impl->next_message_to_send);
-    result = bytes_to_frame((unsigned char *)msg_string, strlen(msg_string),
-                            &impl->outgoing);
-    if (result != TSI_OK) return result;
-    if (next_message_to_send > TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
-      next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX;
-    }
-    if (tsi_tracing_enabled) {
-      gpr_log(GPR_INFO, "%s prepared %s.",
-              impl->is_client ? "Client" : "Server",
-              tsi_fake_handshake_message_to_string(impl->next_message_to_send));
-    }
-    impl->next_message_to_send = next_message_to_send;
-  }
-  result = drain_frame_to_bytes(bytes, bytes_size, &impl->outgoing);
-  if (result != TSI_OK) return result;
-  if (!impl->is_client &&
-      impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
-    /* We're done. */
-    if (tsi_tracing_enabled) {
-      gpr_log(GPR_INFO, "Server is done.");
-    }
-    impl->result = TSI_OK;
-  } else {
-    impl->needs_incoming_message = 1;
-  }
-  return TSI_OK;
-}
-
-static tsi_result fake_handshaker_process_bytes_from_peer(
-    tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) {
-  tsi_result result = TSI_OK;
-  tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
-  tsi_fake_handshake_message expected_msg = impl->next_message_to_send - 1;
-  tsi_fake_handshake_message received_msg;
-
-  if (!impl->needs_incoming_message || impl->result == TSI_OK) {
-    *bytes_size = 0;
-    return TSI_OK;
-  }
-  result = fill_frame_from_bytes(bytes, bytes_size, &impl->incoming);
-  if (result != TSI_OK) return result;
-
-  /* We now have a complete frame. */
-  result = tsi_fake_handshake_message_from_string(
-      (const char *)impl->incoming.data + TSI_FAKE_FRAME_HEADER_SIZE,
-      &received_msg);
-  if (result != TSI_OK) {
-    impl->result = result;
-    return result;
-  }
-  if (received_msg != expected_msg) {
-    gpr_log(GPR_ERROR, "Invalid received message (%s instead of %s)",
-            tsi_fake_handshake_message_to_string(received_msg),
-            tsi_fake_handshake_message_to_string(expected_msg));
-  }
-  if (tsi_tracing_enabled) {
-    gpr_log(GPR_INFO, "%s received %s.", impl->is_client ? "Client" : "Server",
-            tsi_fake_handshake_message_to_string(received_msg));
-  }
-  tsi_fake_frame_reset(&impl->incoming, 0 /* needs_draining */);
-  impl->needs_incoming_message = 0;
-  if (impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
-    /* We're done. */
-    if (tsi_tracing_enabled) {
-      gpr_log(GPR_INFO, "%s is done.", impl->is_client ? "Client" : "Server");
-    }
-    impl->result = TSI_OK;
-  }
-  return TSI_OK;
-}
-
-static tsi_result fake_handshaker_get_result(tsi_handshaker *self) {
-  tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
-  return impl->result;
-}
-
-static tsi_result fake_handshaker_extract_peer(tsi_handshaker *self,
-                                               tsi_peer *peer) {
-  tsi_result result = tsi_construct_peer(1, peer);
-  if (result != TSI_OK) return result;
-  result = tsi_construct_string_peer_property_from_cstring(
-      TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_FAKE_CERTIFICATE_TYPE,
-      &peer->properties[0]);
-  if (result != TSI_OK) tsi_peer_destruct(peer);
-  return result;
-}
-
-static tsi_result fake_handshaker_create_frame_protector(
-    tsi_handshaker *self, size_t *max_protected_frame_size,
-    tsi_frame_protector **protector) {
-  *protector = tsi_create_fake_protector(max_protected_frame_size);
-  if (*protector == NULL) return TSI_OUT_OF_RESOURCES;
-  return TSI_OK;
-}
-
-static void fake_handshaker_destroy(tsi_handshaker *self) {
-  tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
-  tsi_fake_frame_destruct(&impl->incoming);
-  tsi_fake_frame_destruct(&impl->outgoing);
-  free(self);
-}
-
-static const tsi_handshaker_vtable handshaker_vtable = {
-    fake_handshaker_get_bytes_to_send_to_peer,
-    fake_handshaker_process_bytes_from_peer, fake_handshaker_get_result,
-    fake_handshaker_extract_peer, fake_handshaker_create_frame_protector,
-    fake_handshaker_destroy,
-};
-
-tsi_handshaker *tsi_create_fake_handshaker(int is_client) {
-  tsi_fake_handshaker *impl = calloc(1, sizeof(tsi_fake_handshaker));
-  impl->base.vtable = &handshaker_vtable;
-  impl->is_client = is_client;
-  impl->result = TSI_HANDSHAKE_IN_PROGRESS;
-  if (is_client) {
-    impl->needs_incoming_message = 0;
-    impl->next_message_to_send = TSI_FAKE_CLIENT_INIT;
-  } else {
-    impl->needs_incoming_message = 1;
-    impl->next_message_to_send = TSI_FAKE_SERVER_INIT;
-  }
-  return &impl->base;
-}
-
-tsi_frame_protector *tsi_create_fake_protector(
-    size_t *max_protected_frame_size) {
-  tsi_fake_frame_protector *impl = calloc(1, sizeof(tsi_fake_frame_protector));
-  if (impl == NULL) return NULL;
-  impl->max_frame_size = (max_protected_frame_size == NULL)
-                             ? TSI_FAKE_DEFAULT_FRAME_SIZE
-                             : *max_protected_frame_size;
-  impl->base.vtable = &frame_protector_vtable;
-  return &impl->base;
-}
diff --git a/src/core/tsi/fake_transport_security.h b/src/core/tsi/fake_transport_security.h
deleted file mode 100644
index fe295aa..0000000
--- a/src/core/tsi/fake_transport_security.h
+++ /dev/null
@@ -1,61 +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_TSI_FAKE_TRANSPORT_SECURITY_H
-#define GRPC_INTERNAL_CORE_TSI_FAKE_TRANSPORT_SECURITY_H
-
-#include "src/core/tsi/transport_security_interface.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */
-#define TSI_FAKE_CERTIFICATE_TYPE "FAKE"
-
-/* Creates a fake handshaker that will create a fake frame protector.
-
-   No cryptography is performed in these objects. They just simulate handshake
-   messages going back and forth for the handshaker and do some framing on
-   cleartext data for the protector.  */
-tsi_handshaker *tsi_create_fake_handshaker(int is_client);
-
-/* Creates a protector directly without going through the handshake phase. */
-tsi_frame_protector *tsi_create_fake_protector(
-    size_t *max_protected_frame_size);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_TSI_FAKE_TRANSPORT_SECURITY_H */
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c
deleted file mode 100644
index 6adcaac..0000000
--- a/src/core/tsi/ssl_transport_security.c
+++ /dev/null
@@ -1,1469 +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/tsi/ssl_transport_security.h"
-
-#include <limits.h>
-#include <string.h>
-
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
-
-#include <openssl/bio.h>
-#include <openssl/crypto.h> /* For OPENSSL_free */
-#include <openssl/err.h>
-#include <openssl/ssl.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-
-#include "src/core/tsi/ssl_types.h"
-#include "src/core/tsi/transport_security.h"
-
-/* --- Constants. ---*/
-
-#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... */
-#define TSI_SSL_MAX_PROTECTION_OVERHEAD 100
-
-/* --- Structure definitions. ---*/
-
-struct tsi_ssl_handshaker_factory {
-  tsi_result (*create_handshaker)(tsi_ssl_handshaker_factory *self,
-                                  const char *server_name_indication,
-                                  tsi_handshaker **handshaker);
-  void (*destroy)(tsi_ssl_handshaker_factory *self);
-};
-
-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 {
-  tsi_ssl_handshaker_factory base;
-
-  /* Several contexts to support SNI.
-     The tsi_peer array contains the subject names of the server certificates
-     associated with the contexts at the same index.  */
-  SSL_CTX **ssl_contexts;
-  tsi_peer *ssl_context_x509_subject_names;
-  size_t ssl_context_count;
-  unsigned char *alpn_protocol_list;
-  size_t alpn_protocol_list_length;
-} tsi_ssl_server_handshaker_factory;
-
-typedef struct {
-  tsi_handshaker base;
-  SSL *ssl;
-  BIO *into_ssl;
-  BIO *from_ssl;
-  tsi_result result;
-} tsi_ssl_handshaker;
-
-typedef struct {
-  tsi_frame_protector base;
-  SSL *ssl;
-  BIO *into_ssl;
-  BIO *from_ssl;
-  unsigned char *buffer;
-  size_t buffer_size;
-  size_t buffer_offset;
-} tsi_ssl_frame_protector;
-
-/* --- Library Initialization. ---*/
-
-static gpr_once init_openssl_once = GPR_ONCE_INIT;
-static gpr_mu *openssl_mutexes = NULL;
-
-static void openssl_locking_cb(int mode, int type, const char *file, int line) {
-  if (mode & CRYPTO_LOCK) {
-    gpr_mu_lock(&openssl_mutexes[type]);
-  } else {
-    gpr_mu_unlock(&openssl_mutexes[type]);
-  }
-}
-
-static unsigned long openssl_thread_id_cb(void) {
-  return (unsigned long)gpr_thd_currentid();
-}
-
-static void init_openssl(void) {
-  int i;
-  int num_locks;
-  SSL_library_init();
-  SSL_load_error_strings();
-  OpenSSL_add_all_algorithms();
-  num_locks = CRYPTO_num_locks();
-  GPR_ASSERT(num_locks > 0);
-  openssl_mutexes = malloc((size_t)num_locks * sizeof(gpr_mu));
-  GPR_ASSERT(openssl_mutexes != NULL);
-  for (i = 0; i < CRYPTO_num_locks(); i++) {
-    gpr_mu_init(&openssl_mutexes[i]);
-  }
-  CRYPTO_set_locking_callback(openssl_locking_cb);
-  CRYPTO_set_id_callback(openssl_thread_id_cb);
-}
-
-/* --- Ssl utils. ---*/
-
-static const char *ssl_error_string(int error) {
-  switch (error) {
-    case SSL_ERROR_NONE:
-      return "SSL_ERROR_NONE";
-    case SSL_ERROR_ZERO_RETURN:
-      return "SSL_ERROR_ZERO_RETURN";
-    case SSL_ERROR_WANT_READ:
-      return "SSL_ERROR_WANT_READ";
-    case SSL_ERROR_WANT_WRITE:
-      return "SSL_ERROR_WANT_WRITE";
-    case SSL_ERROR_WANT_CONNECT:
-      return "SSL_ERROR_WANT_CONNECT";
-    case SSL_ERROR_WANT_ACCEPT:
-      return "SSL_ERROR_WANT_ACCEPT";
-    case SSL_ERROR_WANT_X509_LOOKUP:
-      return "SSL_ERROR_WANT_X509_LOOKUP";
-    case SSL_ERROR_SYSCALL:
-      return "SSL_ERROR_SYSCALL";
-    case SSL_ERROR_SSL:
-      return "SSL_ERROR_SSL";
-    default:
-      return "Unknown error";
-  }
-}
-
-/* TODO(jboeuf): Remove when we are past the debugging phase with this code. */
-static void ssl_log_where_info(const SSL *ssl, int where, int flag,
-                               const char *msg) {
-  if ((where & flag) && tsi_tracing_enabled) {
-    gpr_log(GPR_INFO, "%20.20s - %30.30s  - %5.10s", msg,
-            SSL_state_string_long(ssl), SSL_state_string(ssl));
-  }
-}
-
-/* Used for debugging. TODO(jboeuf): Remove when code is mature enough. */
-static void ssl_info_callback(const SSL *ssl, int where, int ret) {
-  if (ret == 0) {
-    gpr_log(GPR_ERROR, "ssl_info_callback: error occured.\n");
-    return;
-  }
-
-  ssl_log_where_info(ssl, where, SSL_CB_LOOP, "LOOP");
-  ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_START, "HANDSHAKE START");
-  ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_DONE, "HANDSHAKE DONE");
-}
-
-/* Returns 1 if name looks like an IP address, 0 otherwise.
-   This is a very rough heuristic as it does not handle IPV6 or things like:
-   0300.0250.00.01, 0xC0.0Xa8.0x0.0x1, 000030052000001, 0xc0.052000001 */
-static int looks_like_ip_address(const char *name) {
-  size_t i;
-  size_t dot_count = 0;
-  size_t num_size = 0;
-  for (i = 0; i < strlen(name); i++) {
-    if (name[i] >= '0' && name[i] <= '9') {
-      if (num_size > 3) return 0;
-      num_size++;
-    } else if (name[i] == '.') {
-      if (dot_count > 3 || num_size == 0) return 0;
-      dot_count++;
-      num_size = 0;
-    } else {
-      return 0;
-    }
-  }
-  if (dot_count < 3 || num_size == 0) return 0;
-  return 1;
-}
-
-/* Gets the subject CN from an X509 cert. */
-static tsi_result ssl_get_x509_common_name(X509 *cert, unsigned char **utf8,
-                                           size_t *utf8_size) {
-  int common_name_index = -1;
-  X509_NAME_ENTRY *common_name_entry = NULL;
-  ASN1_STRING *common_name_asn1 = NULL;
-  X509_NAME *subject_name = X509_get_subject_name(cert);
-  int utf8_returned_size = 0;
-  if (subject_name == NULL) {
-    gpr_log(GPR_ERROR, "Could not get subject name from certificate.");
-    return TSI_NOT_FOUND;
-  }
-  common_name_index =
-      X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
-  if (common_name_index == -1) {
-    gpr_log(GPR_ERROR,
-            "Could not get common name of subject from certificate.");
-    return TSI_NOT_FOUND;
-  }
-  common_name_entry = X509_NAME_get_entry(subject_name, common_name_index);
-  if (common_name_entry == NULL) {
-    gpr_log(GPR_ERROR, "Could not get common name entry from certificate.");
-    return TSI_INTERNAL_ERROR;
-  }
-  common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
-  if (common_name_asn1 == NULL) {
-    gpr_log(GPR_ERROR,
-            "Could not get common name entry asn1 from certificate.");
-    return TSI_INTERNAL_ERROR;
-  }
-  utf8_returned_size = ASN1_STRING_to_UTF8(utf8, common_name_asn1);
-  if (utf8_returned_size < 0) {
-    gpr_log(GPR_ERROR, "Could not extract utf8 from asn1 string.");
-    return TSI_OUT_OF_RESOURCES;
-  }
-  *utf8_size = (size_t)utf8_returned_size;
-  return TSI_OK;
-}
-
-/* Gets the subject CN of an X509 cert as a tsi_peer_property. */
-static tsi_result peer_property_from_x509_common_name(
-    X509 *cert, tsi_peer_property *property) {
-  unsigned char *common_name;
-  size_t common_name_size;
-  tsi_result result =
-      ssl_get_x509_common_name(cert, &common_name, &common_name_size);
-  if (result != TSI_OK) {
-    if (result == TSI_NOT_FOUND) {
-      common_name = NULL;
-      common_name_size = 0;
-    } else {
-      return result;
-    }
-  }
-  result = tsi_construct_string_peer_property(
-      TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY,
-      common_name == NULL ? "" : (const char *)common_name, common_name_size,
-      property);
-  OPENSSL_free(common_name);
-  return result;
-}
-
-/* Gets the subject SANs from an X509 cert as a tsi_peer_property. */
-static tsi_result add_subject_alt_names_properties_to_peer(
-    tsi_peer *peer, GENERAL_NAMES *subject_alt_names,
-    size_t subject_alt_name_count) {
-  size_t i;
-  tsi_result result = TSI_OK;
-
-  /* Reset for DNS entries filtering. */
-  peer->property_count -= subject_alt_name_count;
-
-  for (i = 0; i < subject_alt_name_count; i++) {
-    GENERAL_NAME *subject_alt_name =
-        sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i));
-    /* Filter out the non-dns entries names. */
-    if (subject_alt_name->type == GEN_DNS) {
-      unsigned char *dns_name = NULL;
-      int dns_name_size =
-          ASN1_STRING_to_UTF8(&dns_name, subject_alt_name->d.dNSName);
-      if (dns_name_size < 0) {
-        gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string.");
-        result = TSI_INTERNAL_ERROR;
-        break;
-      }
-      result = tsi_construct_string_peer_property(
-          TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
-          (const char *)dns_name, (size_t)dns_name_size,
-          &peer->properties[peer->property_count++]);
-      OPENSSL_free(dns_name);
-      if (result != TSI_OK) break;
-    }
-  }
-  return result;
-}
-
-/* Gets information about the peer's X509 cert as a tsi_peer object. */
-static tsi_result peer_from_x509(X509 *cert, int include_certificate_type,
-                                 tsi_peer *peer) {
-  /* TODO(jboeuf): Maybe add more properties. */
-  GENERAL_NAMES *subject_alt_names =
-      X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
-  int subject_alt_name_count = (subject_alt_names != NULL)
-                                   ? (int)sk_GENERAL_NAME_num(subject_alt_names)
-                                   : 0;
-  size_t property_count;
-  tsi_result result;
-  GPR_ASSERT(subject_alt_name_count >= 0);
-  property_count = (include_certificate_type ? (size_t)1 : 0) +
-                   1 /* common name */ + (size_t)subject_alt_name_count;
-  result = tsi_construct_peer(property_count, peer);
-  if (result != TSI_OK) return result;
-  do {
-    if (include_certificate_type) {
-      result = tsi_construct_string_peer_property_from_cstring(
-          TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
-          &peer->properties[0]);
-      if (result != TSI_OK) break;
-    }
-    result = peer_property_from_x509_common_name(
-        cert, &peer->properties[include_certificate_type ? 1 : 0]);
-    if (result != TSI_OK) break;
-
-    if (subject_alt_name_count != 0) {
-      result = add_subject_alt_names_properties_to_peer(
-          peer, subject_alt_names, (size_t)subject_alt_name_count);
-      if (result != TSI_OK) break;
-    }
-  } while (0);
-
-  if (subject_alt_names != NULL) {
-    sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free);
-  }
-  if (result != TSI_OK) tsi_peer_destruct(peer);
-  return result;
-}
-
-/* Logs the SSL error stack. */
-static void log_ssl_error_stack(void) {
-  unsigned long err;
-  while ((err = ERR_get_error()) != 0) {
-    char details[256];
-    ERR_error_string_n((uint32_t)err, details, sizeof(details));
-    gpr_log(GPR_ERROR, "%s", details);
-  }
-}
-
-/* Performs an SSL_read and handle errors. */
-static tsi_result do_ssl_read(SSL *ssl, unsigned char *unprotected_bytes,
-                              size_t *unprotected_bytes_size) {
-  int read_from_ssl;
-  GPR_ASSERT(*unprotected_bytes_size <= INT_MAX);
-  read_from_ssl =
-      SSL_read(ssl, unprotected_bytes, (int)*unprotected_bytes_size);
-  if (read_from_ssl == 0) {
-    gpr_log(GPR_ERROR, "SSL_read returned 0 unexpectedly.");
-    return TSI_INTERNAL_ERROR;
-  }
-  if (read_from_ssl < 0) {
-    read_from_ssl = SSL_get_error(ssl, read_from_ssl);
-    switch (read_from_ssl) {
-      case SSL_ERROR_WANT_READ:
-        /* We need more data to finish the frame. */
-        *unprotected_bytes_size = 0;
-        return TSI_OK;
-      case SSL_ERROR_WANT_WRITE:
-        gpr_log(
-            GPR_ERROR,
-            "Peer tried to renegotiate SSL connection. This is unsupported.");
-        return TSI_UNIMPLEMENTED;
-      case SSL_ERROR_SSL:
-        gpr_log(GPR_ERROR, "Corruption detected.");
-        log_ssl_error_stack();
-        return TSI_DATA_CORRUPTED;
-      default:
-        gpr_log(GPR_ERROR, "SSL_read failed with error %s.",
-                ssl_error_string(read_from_ssl));
-        return TSI_PROTOCOL_FAILURE;
-    }
-  }
-  *unprotected_bytes_size = (size_t)read_from_ssl;
-  return TSI_OK;
-}
-
-/* Performs an SSL_write and handle errors. */
-static tsi_result do_ssl_write(SSL *ssl, unsigned char *unprotected_bytes,
-                               size_t unprotected_bytes_size) {
-  int ssl_write_result;
-  GPR_ASSERT(unprotected_bytes_size <= INT_MAX);
-  ssl_write_result =
-      SSL_write(ssl, unprotected_bytes, (int)unprotected_bytes_size);
-  if (ssl_write_result < 0) {
-    ssl_write_result = SSL_get_error(ssl, ssl_write_result);
-    if (ssl_write_result == SSL_ERROR_WANT_READ) {
-      gpr_log(GPR_ERROR,
-              "Peer tried to renegotiate SSL connection. This is unsupported.");
-      return TSI_UNIMPLEMENTED;
-    } else {
-      gpr_log(GPR_ERROR, "SSL_write failed with error %s.",
-              ssl_error_string(ssl_write_result));
-      return TSI_INTERNAL_ERROR;
-    }
-  }
-  return TSI_OK;
-}
-
-/* Loads an in-memory PEM certificate chain into the SSL context. */
-static tsi_result ssl_ctx_use_certificate_chain(
-    SSL_CTX *context, const unsigned char *pem_cert_chain,
-    size_t pem_cert_chain_size) {
-  tsi_result result = TSI_OK;
-  X509 *certificate = NULL;
-  BIO *pem;
-  GPR_ASSERT(pem_cert_chain_size <= INT_MAX);
-  pem = BIO_new_mem_buf((void *)pem_cert_chain, (int)pem_cert_chain_size);
-  if (pem == NULL) return TSI_OUT_OF_RESOURCES;
-
-  do {
-    certificate = PEM_read_bio_X509_AUX(pem, NULL, NULL, "");
-    if (certificate == NULL) {
-      result = TSI_INVALID_ARGUMENT;
-      break;
-    }
-    if (!SSL_CTX_use_certificate(context, certificate)) {
-      result = TSI_INVALID_ARGUMENT;
-      break;
-    }
-    while (1) {
-      X509 *certificate_authority = PEM_read_bio_X509(pem, NULL, NULL, "");
-      if (certificate_authority == NULL) {
-        ERR_clear_error();
-        break; /* Done reading. */
-      }
-      if (!SSL_CTX_add_extra_chain_cert(context, certificate_authority)) {
-        X509_free(certificate_authority);
-        result = TSI_INVALID_ARGUMENT;
-        break;
-      }
-      /* We don't need to free certificate_authority as its ownership has been
-         transfered to the context. That is not the case for certificate though.
-       */
-    }
-  } while (0);
-
-  if (certificate != NULL) X509_free(certificate);
-  BIO_free(pem);
-  return result;
-}
-
-/* Loads an in-memory PEM private key into the SSL context. */
-static tsi_result ssl_ctx_use_private_key(SSL_CTX *context,
-                                          const unsigned char *pem_key,
-                                          size_t pem_key_size) {
-  tsi_result result = TSI_OK;
-  EVP_PKEY *private_key = NULL;
-  BIO *pem;
-  GPR_ASSERT(pem_key_size <= INT_MAX);
-  pem = BIO_new_mem_buf((void *)pem_key, (int)pem_key_size);
-  if (pem == NULL) return TSI_OUT_OF_RESOURCES;
-  do {
-    private_key = PEM_read_bio_PrivateKey(pem, NULL, NULL, "");
-    if (private_key == NULL) {
-      result = TSI_INVALID_ARGUMENT;
-      break;
-    }
-    if (!SSL_CTX_use_PrivateKey(context, private_key)) {
-      result = TSI_INVALID_ARGUMENT;
-      break;
-    }
-  } while (0);
-  if (private_key != NULL) EVP_PKEY_free(private_key);
-  BIO_free(pem);
-  return result;
-}
-
-/* Loads in-memory PEM verification certs into the SSL context and optionally
-   returns the verification cert names (root_names can be NULL). */
-static tsi_result ssl_ctx_load_verification_certs(
-    SSL_CTX *context, const unsigned char *pem_roots, size_t pem_roots_size,
-    STACK_OF(X509_NAME) * *root_names) {
-  tsi_result result = TSI_OK;
-  size_t num_roots = 0;
-  X509 *root = NULL;
-  X509_NAME *root_name = NULL;
-  BIO *pem;
-  X509_STORE *root_store;
-  GPR_ASSERT(pem_roots_size <= INT_MAX);
-  pem = BIO_new_mem_buf((void *)pem_roots, (int)pem_roots_size);
-  root_store = SSL_CTX_get_cert_store(context);
-  if (root_store == NULL) return TSI_INVALID_ARGUMENT;
-  if (pem == NULL) return TSI_OUT_OF_RESOURCES;
-  if (root_names != NULL) {
-    *root_names = sk_X509_NAME_new_null();
-    if (*root_names == NULL) return TSI_OUT_OF_RESOURCES;
-  }
-
-  while (1) {
-    root = PEM_read_bio_X509_AUX(pem, NULL, NULL, "");
-    if (root == NULL) {
-      ERR_clear_error();
-      break; /* We're at the end of stream. */
-    }
-    if (root_names != NULL) {
-      root_name = X509_get_subject_name(root);
-      if (root_name == NULL) {
-        gpr_log(GPR_ERROR, "Could not get name from root certificate.");
-        result = TSI_INVALID_ARGUMENT;
-        break;
-      }
-      root_name = X509_NAME_dup(root_name);
-      if (root_name == NULL) {
-        result = TSI_OUT_OF_RESOURCES;
-        break;
-      }
-      sk_X509_NAME_push(*root_names, root_name);
-      root_name = NULL;
-    }
-    if (!X509_STORE_add_cert(root_store, root)) {
-      gpr_log(GPR_ERROR, "Could not add root certificate to ssl context.");
-      result = TSI_INTERNAL_ERROR;
-      break;
-    }
-    X509_free(root);
-    num_roots++;
-  }
-
-  if (num_roots == 0) {
-    gpr_log(GPR_ERROR, "Could not load any root certificate.");
-    result = TSI_INVALID_ARGUMENT;
-  }
-
-  if (result != TSI_OK) {
-    if (root != NULL) X509_free(root);
-    if (root_names != NULL) {
-      sk_X509_NAME_pop_free(*root_names, X509_NAME_free);
-      *root_names = NULL;
-      if (root_name != NULL) X509_NAME_free(root_name);
-    }
-  }
-  BIO_free(pem);
-  return result;
-}
-
-/* Populates the SSL context with a private key and a cert chain, and sets the
-   cipher list and the ephemeral ECDH key. */
-static tsi_result populate_ssl_context(
-    SSL_CTX *context, const unsigned char *pem_private_key,
-    size_t pem_private_key_size, const unsigned char *pem_certificate_chain,
-    size_t pem_certificate_chain_size, const char *cipher_list) {
-  tsi_result result = TSI_OK;
-  if (pem_certificate_chain != NULL) {
-    result = ssl_ctx_use_certificate_chain(context, pem_certificate_chain,
-                                           pem_certificate_chain_size);
-    if (result != TSI_OK) {
-      gpr_log(GPR_ERROR, "Invalid cert chain file.");
-      return result;
-    }
-  }
-  if (pem_private_key != NULL) {
-    result =
-        ssl_ctx_use_private_key(context, pem_private_key, pem_private_key_size);
-    if (result != TSI_OK || !SSL_CTX_check_private_key(context)) {
-      gpr_log(GPR_ERROR, "Invalid private key.");
-      return result != TSI_OK ? result : TSI_INVALID_ARGUMENT;
-    }
-  }
-  if ((cipher_list != NULL) && !SSL_CTX_set_cipher_list(context, cipher_list)) {
-    gpr_log(GPR_ERROR, "Invalid cipher list: %s.", cipher_list);
-    return TSI_INVALID_ARGUMENT;
-  }
-  {
-    EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
-    if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) {
-      gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key.");
-      EC_KEY_free(ecdh);
-      return TSI_INTERNAL_ERROR;
-    }
-    SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
-    EC_KEY_free(ecdh);
-  }
-  return TSI_OK;
-}
-
-/* Extracts the CN and the SANs from an X509 cert as a peer object. */
-static tsi_result extract_x509_subject_names_from_pem_cert(
-    const unsigned char *pem_cert, size_t pem_cert_size, tsi_peer *peer) {
-  tsi_result result = TSI_OK;
-  X509 *cert = NULL;
-  BIO *pem;
-  GPR_ASSERT(pem_cert_size <= INT_MAX);
-  pem = BIO_new_mem_buf((void *)pem_cert, (int)pem_cert_size);
-  if (pem == NULL) return TSI_OUT_OF_RESOURCES;
-
-  cert = PEM_read_bio_X509(pem, NULL, NULL, "");
-  if (cert == NULL) {
-    gpr_log(GPR_ERROR, "Invalid certificate");
-    result = TSI_INVALID_ARGUMENT;
-  } else {
-    result = peer_from_x509(cert, 0, peer);
-  }
-  if (cert != NULL) X509_free(cert);
-  BIO_free(pem);
-  return result;
-}
-
-/* Builds the alpn protocol name list according to rfc 7301. */
-static tsi_result build_alpn_protocol_name_list(
-    const unsigned char **alpn_protocols,
-    const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
-    unsigned char **protocol_name_list, size_t *protocol_name_list_length) {
-  uint16_t i;
-  unsigned char *current;
-  *protocol_name_list = NULL;
-  *protocol_name_list_length = 0;
-  if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT;
-  for (i = 0; i < num_alpn_protocols; i++) {
-    if (alpn_protocols_lengths[i] == 0) {
-      gpr_log(GPR_ERROR, "Invalid 0-length protocol name.");
-      return TSI_INVALID_ARGUMENT;
-    }
-    *protocol_name_list_length += (size_t)alpn_protocols_lengths[i] + 1;
-  }
-  *protocol_name_list = malloc(*protocol_name_list_length);
-  if (*protocol_name_list == NULL) return TSI_OUT_OF_RESOURCES;
-  current = *protocol_name_list;
-  for (i = 0; i < num_alpn_protocols; i++) {
-    *(current++) = alpn_protocols_lengths[i];
-    memcpy(current, alpn_protocols[i], alpn_protocols_lengths[i]);
-    current += alpn_protocols_lengths[i];
-  }
-  /* Safety check. */
-  if ((current < *protocol_name_list) ||
-      ((uintptr_t)(current - *protocol_name_list) !=
-       *protocol_name_list_length)) {
-    return TSI_INTERNAL_ERROR;
-  }
-  return TSI_OK;
-}
-
-/* --- tsi_frame_protector methods implementation. ---*/
-
-static tsi_result ssl_protector_protect(tsi_frame_protector *self,
-                                        const unsigned char *unprotected_bytes,
-                                        size_t *unprotected_bytes_size,
-                                        unsigned char *protected_output_frames,
-                                        size_t *protected_output_frames_size) {
-  tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
-  int read_from_ssl;
-  size_t available;
-  tsi_result result = TSI_OK;
-
-  /* First see if we have some pending data in the SSL BIO. */
-  int pending_in_ssl = (int)BIO_pending(impl->from_ssl);
-  if (pending_in_ssl > 0) {
-    *unprotected_bytes_size = 0;
-    GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
-    read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
-                             (int)*protected_output_frames_size);
-    if (read_from_ssl < 0) {
-      gpr_log(GPR_ERROR,
-              "Could not read from BIO even though some data is pending");
-      return TSI_INTERNAL_ERROR;
-    }
-    *protected_output_frames_size = (size_t)read_from_ssl;
-    return TSI_OK;
-  }
-
-  /* Now see if we can send a complete frame. */
-  available = impl->buffer_size - impl->buffer_offset;
-  if (available > *unprotected_bytes_size) {
-    /* If we cannot, just copy the data in our internal buffer. */
-    memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes,
-           *unprotected_bytes_size);
-    impl->buffer_offset += *unprotected_bytes_size;
-    *protected_output_frames_size = 0;
-    return TSI_OK;
-  }
-
-  /* If we can, prepare the buffer, send it to SSL_write and read. */
-  memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, available);
-  result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_size);
-  if (result != TSI_OK) return result;
-
-  GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
-  read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
-                           (int)*protected_output_frames_size);
-  if (read_from_ssl < 0) {
-    gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
-    return TSI_INTERNAL_ERROR;
-  }
-  *protected_output_frames_size = (size_t)read_from_ssl;
-  *unprotected_bytes_size = available;
-  impl->buffer_offset = 0;
-  return TSI_OK;
-}
-
-static tsi_result ssl_protector_protect_flush(
-    tsi_frame_protector *self, unsigned char *protected_output_frames,
-    size_t *protected_output_frames_size, size_t *still_pending_size) {
-  tsi_result result = TSI_OK;
-  tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
-  int read_from_ssl = 0;
-  int pending;
-
-  if (impl->buffer_offset != 0) {
-    result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_offset);
-    if (result != TSI_OK) return result;
-    impl->buffer_offset = 0;
-  }
-
-  pending = (int)BIO_pending(impl->from_ssl);
-  GPR_ASSERT(pending >= 0);
-  *still_pending_size = (size_t)pending;
-  if (*still_pending_size == 0) return TSI_OK;
-
-  GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
-  read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
-                           (int)*protected_output_frames_size);
-  if (read_from_ssl <= 0) {
-    gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
-    return TSI_INTERNAL_ERROR;
-  }
-  *protected_output_frames_size = (size_t)read_from_ssl;
-  pending = (int)BIO_pending(impl->from_ssl);
-  GPR_ASSERT(pending >= 0);
-  *still_pending_size = (size_t)pending;
-  return TSI_OK;
-}
-
-static tsi_result ssl_protector_unprotect(
-    tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
-    size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
-    size_t *unprotected_bytes_size) {
-  tsi_result result = TSI_OK;
-  int written_into_ssl = 0;
-  size_t output_bytes_size = *unprotected_bytes_size;
-  size_t output_bytes_offset = 0;
-  tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
-
-  /* First, try to read remaining data from ssl. */
-  result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
-  if (result != TSI_OK) return result;
-  if (*unprotected_bytes_size == output_bytes_size) {
-    /* We have read everything we could and cannot process any more input. */
-    *protected_frames_bytes_size = 0;
-    return TSI_OK;
-  }
-  output_bytes_offset = *unprotected_bytes_size;
-  unprotected_bytes += output_bytes_offset;
-  *unprotected_bytes_size = output_bytes_size - output_bytes_offset;
-
-  /* Then, try to write some data to ssl. */
-  GPR_ASSERT(*protected_frames_bytes_size <= INT_MAX);
-  written_into_ssl = BIO_write(impl->into_ssl, protected_frames_bytes,
-                               (int)*protected_frames_bytes_size);
-  if (written_into_ssl < 0) {
-    gpr_log(GPR_ERROR, "Sending protected frame to ssl failed with %d",
-            written_into_ssl);
-    return TSI_INTERNAL_ERROR;
-  }
-  *protected_frames_bytes_size = (size_t)written_into_ssl;
-
-  /* Now try to read some data again. */
-  result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
-  if (result == TSI_OK) {
-    /* Don't forget to output the total number of bytes read. */
-    *unprotected_bytes_size += output_bytes_offset;
-  }
-  return result;
-}
-
-static void ssl_protector_destroy(tsi_frame_protector *self) {
-  tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
-  if (impl->buffer != NULL) free(impl->buffer);
-  if (impl->ssl != NULL) SSL_free(impl->ssl);
-  free(self);
-}
-
-static const tsi_frame_protector_vtable frame_protector_vtable = {
-    ssl_protector_protect, ssl_protector_protect_flush, ssl_protector_unprotect,
-    ssl_protector_destroy,
-};
-
-/* --- tsi_handshaker methods implementation. ---*/
-
-static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
-                                                           unsigned char *bytes,
-                                                           size_t *bytes_size) {
-  tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
-  int bytes_read_from_ssl = 0;
-  if (bytes == NULL || bytes_size == NULL || *bytes_size == 0 ||
-      *bytes_size > INT_MAX) {
-    return TSI_INVALID_ARGUMENT;
-  }
-  GPR_ASSERT(*bytes_size <= INT_MAX);
-  bytes_read_from_ssl = BIO_read(impl->from_ssl, bytes, (int)*bytes_size);
-  if (bytes_read_from_ssl < 0) {
-    *bytes_size = 0;
-    if (!BIO_should_retry(impl->from_ssl)) {
-      impl->result = TSI_INTERNAL_ERROR;
-      return impl->result;
-    } else {
-      return TSI_OK;
-    }
-  }
-  *bytes_size = (size_t)bytes_read_from_ssl;
-  return BIO_pending(impl->from_ssl) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA;
-}
-
-static tsi_result ssl_handshaker_get_result(tsi_handshaker *self) {
-  tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
-  if ((impl->result == TSI_HANDSHAKE_IN_PROGRESS) &&
-      SSL_is_init_finished(impl->ssl)) {
-    impl->result = TSI_OK;
-  }
-  return impl->result;
-}
-
-static tsi_result ssl_handshaker_process_bytes_from_peer(
-    tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) {
-  tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
-  int bytes_written_into_ssl_size = 0;
-  if (bytes == NULL || bytes_size == 0 || *bytes_size > INT_MAX) {
-    return TSI_INVALID_ARGUMENT;
-  }
-  GPR_ASSERT(*bytes_size <= INT_MAX);
-  bytes_written_into_ssl_size =
-      BIO_write(impl->into_ssl, bytes, (int)*bytes_size);
-  if (bytes_written_into_ssl_size < 0) {
-    gpr_log(GPR_ERROR, "Could not write to memory BIO.");
-    impl->result = TSI_INTERNAL_ERROR;
-    return impl->result;
-  }
-  *bytes_size = (size_t)bytes_written_into_ssl_size;
-
-  if (!tsi_handshaker_is_in_progress(self)) {
-    impl->result = TSI_OK;
-    return impl->result;
-  } else {
-    /* Get ready to get some bytes from SSL. */
-    int ssl_result = SSL_do_handshake(impl->ssl);
-    ssl_result = SSL_get_error(impl->ssl, ssl_result);
-    switch (ssl_result) {
-      case SSL_ERROR_WANT_READ:
-        if (BIO_pending(impl->from_ssl) == 0) {
-          /* We need more data. */
-          return TSI_INCOMPLETE_DATA;
-        } else {
-          return TSI_OK;
-        }
-      case SSL_ERROR_NONE:
-        return TSI_OK;
-      default: {
-        char err_str[256];
-        ERR_error_string_n(ERR_get_error(), err_str, sizeof(err_str));
-        gpr_log(GPR_ERROR, "Handshake failed with fatal error %s: %s.",
-                ssl_error_string(ssl_result), err_str);
-        impl->result = TSI_PROTOCOL_FAILURE;
-        return impl->result;
-      }
-    }
-  }
-}
-
-static tsi_result ssl_handshaker_extract_peer(tsi_handshaker *self,
-                                              tsi_peer *peer) {
-  tsi_result result = TSI_OK;
-  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);
-  if (peer_cert != NULL) {
-    result = peer_from_x509(peer_cert, 1, peer);
-    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 =
-        calloc(1, sizeof(tsi_peer_property) * (peer->property_count + 1));
-    if (new_properties == NULL) return TSI_OUT_OF_RESOURCES;
-    for (i = 0; i < peer->property_count; i++) {
-      new_properties[i] = peer->properties[i];
-    }
-    result = tsi_construct_string_peer_property(
-        TSI_SSL_ALPN_SELECTED_PROTOCOL, (const char *)alpn_selected,
-        alpn_selected_len, &new_properties[peer->property_count]);
-    if (result != TSI_OK) {
-      free(new_properties);
-      return result;
-    }
-    if (peer->properties != NULL) free(peer->properties);
-    peer->property_count++;
-    peer->properties = new_properties;
-  }
-  return result;
-}
-
-static tsi_result ssl_handshaker_create_frame_protector(
-    tsi_handshaker *self, size_t *max_output_protected_frame_size,
-    tsi_frame_protector **protector) {
-  size_t actual_max_output_protected_frame_size =
-      TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
-  tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
-  tsi_ssl_frame_protector *protector_impl =
-      calloc(1, sizeof(tsi_ssl_frame_protector));
-  if (protector_impl == NULL) {
-    return TSI_OUT_OF_RESOURCES;
-  }
-
-  if (max_output_protected_frame_size != NULL) {
-    if (*max_output_protected_frame_size >
-        TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND) {
-      *max_output_protected_frame_size =
-          TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
-    } else if (*max_output_protected_frame_size <
-               TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND) {
-      *max_output_protected_frame_size =
-          TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND;
-    }
-    actual_max_output_protected_frame_size = *max_output_protected_frame_size;
-  }
-  protector_impl->buffer_size =
-      actual_max_output_protected_frame_size - TSI_SSL_MAX_PROTECTION_OVERHEAD;
-  protector_impl->buffer = malloc(protector_impl->buffer_size);
-  if (protector_impl->buffer == NULL) {
-    gpr_log(GPR_ERROR,
-            "Could not allocated buffer for tsi_ssl_frame_protector.");
-    free(protector_impl);
-    return TSI_INTERNAL_ERROR;
-  }
-
-  /* Transfer ownership of ssl to the frame protector. It is OK as the caller
-   * cannot call anything else but destroy on the handshaker after this call. */
-  protector_impl->ssl = impl->ssl;
-  impl->ssl = NULL;
-  protector_impl->into_ssl = impl->into_ssl;
-  protector_impl->from_ssl = impl->from_ssl;
-
-  protector_impl->base.vtable = &frame_protector_vtable;
-  *protector = &protector_impl->base;
-  return TSI_OK;
-}
-
-static void ssl_handshaker_destroy(tsi_handshaker *self) {
-  tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
-  SSL_free(impl->ssl); /* The BIO objects are owned by ssl */
-  free(impl);
-}
-
-static const tsi_handshaker_vtable handshaker_vtable = {
-    ssl_handshaker_get_bytes_to_send_to_peer,
-    ssl_handshaker_process_bytes_from_peer, ssl_handshaker_get_result,
-    ssl_handshaker_extract_peer, ssl_handshaker_create_frame_protector,
-    ssl_handshaker_destroy,
-};
-
-/* --- tsi_ssl_handshaker_factory common methods. --- */
-
-tsi_result tsi_ssl_handshaker_factory_create_handshaker(
-    tsi_ssl_handshaker_factory *self, const char *server_name_indication,
-    tsi_handshaker **handshaker) {
-  if (self == NULL || handshaker == NULL) return TSI_INVALID_ARGUMENT;
-  return self->create_handshaker(self, server_name_indication, handshaker);
-}
-
-void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self) {
-  if (self == NULL) return;
-  self->destroy(self);
-}
-
-static tsi_result create_tsi_ssl_handshaker(SSL_CTX *ctx, int is_client,
-                                            const char *server_name_indication,
-                                            tsi_handshaker **handshaker) {
-  SSL *ssl = SSL_new(ctx);
-  BIO *into_ssl = NULL;
-  BIO *from_ssl = NULL;
-  tsi_ssl_handshaker *impl = NULL;
-  *handshaker = NULL;
-  if (ctx == NULL) {
-    gpr_log(GPR_ERROR, "SSL Context is null. Should never happen.");
-    return TSI_INTERNAL_ERROR;
-  }
-  if (ssl == NULL) {
-    return TSI_OUT_OF_RESOURCES;
-  }
-  SSL_set_info_callback(ssl, ssl_info_callback);
-
-  into_ssl = BIO_new(BIO_s_mem());
-  from_ssl = BIO_new(BIO_s_mem());
-  if (into_ssl == NULL || from_ssl == NULL) {
-    gpr_log(GPR_ERROR, "BIO_new failed.");
-    SSL_free(ssl);
-    if (into_ssl != NULL) BIO_free(into_ssl);
-    if (from_ssl != NULL) BIO_free(into_ssl);
-    return TSI_OUT_OF_RESOURCES;
-  }
-  SSL_set_bio(ssl, into_ssl, from_ssl);
-  if (is_client) {
-    int ssl_result;
-    SSL_set_connect_state(ssl);
-    if (server_name_indication != NULL) {
-      if (!SSL_set_tlsext_host_name(ssl, server_name_indication)) {
-        gpr_log(GPR_ERROR, "Invalid server name indication %s.",
-                server_name_indication);
-        SSL_free(ssl);
-        return TSI_INTERNAL_ERROR;
-      }
-    }
-    ssl_result = SSL_do_handshake(ssl);
-    ssl_result = SSL_get_error(ssl, ssl_result);
-    if (ssl_result != SSL_ERROR_WANT_READ) {
-      gpr_log(GPR_ERROR,
-              "Unexpected error received from first SSL_do_handshake call: %s",
-              ssl_error_string(ssl_result));
-      SSL_free(ssl);
-      return TSI_INTERNAL_ERROR;
-    }
-  } else {
-    SSL_set_accept_state(ssl);
-  }
-
-  impl = calloc(1, sizeof(tsi_ssl_handshaker));
-  if (impl == NULL) {
-    SSL_free(ssl);
-    return TSI_OUT_OF_RESOURCES;
-  }
-  impl->ssl = ssl;
-  impl->into_ssl = into_ssl;
-  impl->from_ssl = from_ssl;
-  impl->result = TSI_HANDSHAKE_IN_PROGRESS;
-  impl->base.vtable = &handshaker_vtable;
-  *handshaker = &impl->base;
-  return TSI_OK;
-}
-
-static int select_protocol_list(const unsigned char **out,
-                                unsigned char *outlen,
-                                const unsigned char *client_list,
-                                size_t client_list_len,
-                                const unsigned char *server_list,
-                                size_t 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) &&
-           (uintptr_t)(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(
-    tsi_ssl_handshaker_factory *self, const char *server_name_indication,
-    tsi_handshaker **handshaker) {
-  tsi_ssl_client_handshaker_factory *impl =
-      (tsi_ssl_client_handshaker_factory *)self;
-  return create_tsi_ssl_handshaker(impl->ssl_context, 1, server_name_indication,
-                                   handshaker);
-}
-
-static void ssl_client_handshaker_factory_destroy(
-    tsi_ssl_handshaker_factory *self) {
-  tsi_ssl_client_handshaker_factory *impl =
-      (tsi_ssl_client_handshaker_factory *)self;
-  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(
-    tsi_ssl_handshaker_factory *self, const char *server_name_indication,
-    tsi_handshaker **handshaker) {
-  tsi_ssl_server_handshaker_factory *impl =
-      (tsi_ssl_server_handshaker_factory *)self;
-  if (impl->ssl_context_count == 0 || server_name_indication != NULL) {
-    return TSI_INVALID_ARGUMENT;
-  }
-  /* Create the handshaker with the first context. We will switch if needed
-     because of SNI in ssl_server_handshaker_factory_servername_callback.  */
-  return create_tsi_ssl_handshaker(impl->ssl_contexts[0], 0, NULL, handshaker);
-}
-
-static void ssl_server_handshaker_factory_destroy(
-    tsi_ssl_handshaker_factory *self) {
-  tsi_ssl_server_handshaker_factory *impl =
-      (tsi_ssl_server_handshaker_factory *)self;
-  size_t i;
-  for (i = 0; i < impl->ssl_context_count; i++) {
-    if (impl->ssl_contexts[i] != NULL) {
-      SSL_CTX_free(impl->ssl_contexts[i]);
-      tsi_peer_destruct(&impl->ssl_context_x509_subject_names[i]);
-    }
-  }
-  if (impl->ssl_contexts != NULL) free(impl->ssl_contexts);
-  if (impl->ssl_context_x509_subject_names != NULL) {
-    free(impl->ssl_context_x509_subject_names);
-  }
-  if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list);
-  free(impl);
-}
-
-static int does_entry_match_name(const char *entry, size_t entry_length,
-                                 const char *name) {
-  const char *dot;
-  const char *name_subdomain = NULL;
-  size_t name_length = strlen(name);
-  size_t name_subdomain_length;
-  if (entry_length == 0) return 0;
-
-  /* Take care of '.' terminations. */
-  if (name[name_length - 1] == '.') {
-    name_length--;
-  }
-  if (entry[entry_length - 1] == '.') {
-    entry_length--;
-    if (entry_length == 0) return 0;
-  }
-
-  if ((name_length == entry_length) &&
-      strncmp(name, entry, entry_length) == 0) {
-    return 1; /* Perfect match. */
-  }
-  if (entry[0] != '*') return 0;
-
-  /* Wildchar subdomain matching. */
-  if (entry_length < 3 || entry[1] != '.') { /* At least *.x */
-    gpr_log(GPR_ERROR, "Invalid wildchar entry.");
-    return 0;
-  }
-  name_subdomain = strchr(name, '.');
-  if (name_subdomain == NULL) return 0;
-  name_subdomain_length = strlen(name_subdomain);
-  if (name_subdomain_length < 2) return 0;
-  name_subdomain++; /* Starts after the dot. */
-  name_subdomain_length--;
-  entry += 2; /* Remove *. */
-  entry_length -= 2;
-  dot = strchr(name_subdomain, '.');
-  if ((dot == NULL) || (dot == &name_subdomain[name_subdomain_length - 1])) {
-    gpr_log(GPR_ERROR, "Invalid toplevel subdomain: %s", name_subdomain);
-    return 0;
-  }
-  if (name_subdomain[name_subdomain_length - 1] == '.') {
-    name_subdomain_length--;
-  }
-  return ((entry_length > 0) && (name_subdomain_length == entry_length) &&
-          strncmp(entry, name_subdomain, entry_length) == 0);
-}
-
-static int ssl_server_handshaker_factory_servername_callback(SSL *ssl, int *ap,
-                                                             void *arg) {
-  tsi_ssl_server_handshaker_factory *impl =
-      (tsi_ssl_server_handshaker_factory *)arg;
-  size_t i = 0;
-  const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
-  if (servername == NULL || strlen(servername) == 0) {
-    return SSL_TLSEXT_ERR_NOACK;
-  }
-
-  for (i = 0; i < impl->ssl_context_count; i++) {
-    if (tsi_ssl_peer_matches_name(&impl->ssl_context_x509_subject_names[i],
-                                  servername)) {
-      SSL_set_SSL_CTX(ssl, impl->ssl_contexts[i]);
-      return SSL_TLSEXT_ERR_OK;
-    }
-  }
-  gpr_log(GPR_ERROR, "No match found for server name: %s.", servername);
-  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;
-  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;
-  GPR_ASSERT(factory->alpn_protocol_list_length <= UINT_MAX);
-  *outlen = (unsigned int)factory->alpn_protocol_list_length;
-  return SSL_TLSEXT_ERR_OK;
-}
-
-/* --- tsi_ssl_handshaker_factory constructors. --- */
-
-tsi_result tsi_create_ssl_client_handshaker_factory(
-    const unsigned char *pem_private_key, size_t pem_private_key_size,
-    const unsigned char *pem_cert_chain, size_t pem_cert_chain_size,
-    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
-    const char *cipher_list, const unsigned char **alpn_protocols,
-    const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
-    tsi_ssl_handshaker_factory **factory) {
-  SSL_CTX *ssl_context = NULL;
-  tsi_ssl_client_handshaker_factory *impl = NULL;
-  tsi_result result = TSI_OK;
-
-  gpr_once_init(&init_openssl_once, init_openssl);
-
-  if (factory == NULL) return TSI_INVALID_ARGUMENT;
-  *factory = NULL;
-  if (pem_root_certs == NULL) return TSI_INVALID_ARGUMENT;
-
-  ssl_context = SSL_CTX_new(TLSv1_2_method());
-  if (ssl_context == NULL) {
-    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,
-                             pem_cert_chain, pem_cert_chain_size, cipher_list);
-    if (result != TSI_OK) break;
-    result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs,
-                                             pem_root_certs_size, NULL);
-    if (result != TSI_OK) {
-      gpr_log(GPR_ERROR, "Cannot load server root certificates.");
-      break;
-    }
-
-    if (num_alpn_protocols != 0) {
-      result = build_alpn_protocol_name_list(
-          alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
-          &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));
-        break;
-      }
-#if TSI_OPENSSL_ALPN_SUPPORT
-      GPR_ASSERT(impl->alpn_protocol_list_length < UINT_MAX);
-      if (SSL_CTX_set_alpn_protos(
-              ssl_context, impl->alpn_protocol_list,
-              (unsigned int)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_client_handshaker_factory_destroy(&impl->base);
-    return result;
-  }
-  SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL);
-  /* TODO(jboeuf): Add revocation verification. */
-
-  impl->base.create_handshaker =
-      ssl_client_handshaker_factory_create_handshaker;
-  impl->base.destroy = ssl_client_handshaker_factory_destroy;
-  *factory = &impl->base;
-  return TSI_OK;
-}
-
-tsi_result tsi_create_ssl_server_handshaker_factory(
-    const unsigned char **pem_private_keys,
-    const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains,
-    const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count,
-    const unsigned char *pem_client_root_certs,
-    size_t pem_client_root_certs_size, int force_client_auth,
-    const char *cipher_list, const unsigned char **alpn_protocols,
-    const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
-    tsi_ssl_handshaker_factory **factory) {
-  tsi_ssl_server_handshaker_factory *impl = NULL;
-  tsi_result result = TSI_OK;
-  size_t i = 0;
-
-  gpr_once_init(&init_openssl_once, init_openssl);
-
-  if (factory == NULL) return TSI_INVALID_ARGUMENT;
-  *factory = NULL;
-  if (key_cert_pair_count == 0 || pem_private_keys == NULL ||
-      pem_cert_chains == NULL) {
-    return TSI_INVALID_ARGUMENT;
-  }
-
-  impl = calloc(1, sizeof(tsi_ssl_server_handshaker_factory));
-  if (impl == NULL) return TSI_OUT_OF_RESOURCES;
-  impl->base.create_handshaker =
-      ssl_server_handshaker_factory_create_handshaker;
-  impl->base.destroy = ssl_server_handshaker_factory_destroy;
-  impl->ssl_contexts = calloc(key_cert_pair_count, sizeof(SSL_CTX *));
-  impl->ssl_context_x509_subject_names =
-      calloc(key_cert_pair_count, sizeof(tsi_peer));
-  if (impl->ssl_contexts == NULL ||
-      impl->ssl_context_x509_subject_names == NULL) {
-    tsi_ssl_handshaker_factory_destroy(&impl->base);
-    return TSI_OUT_OF_RESOURCES;
-  }
-  impl->ssl_context_count = key_cert_pair_count;
-
-  if (num_alpn_protocols > 0) {
-    result = build_alpn_protocol_name_list(
-        alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
-        &impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
-    if (result != TSI_OK) {
-      tsi_ssl_handshaker_factory_destroy(&impl->base);
-      return result;
-    }
-  }
-
-  for (i = 0; i < key_cert_pair_count; i++) {
-    do {
-      impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
-      if (impl->ssl_contexts[i] == NULL) {
-        gpr_log(GPR_ERROR, "Could not create ssl context.");
-        result = TSI_OUT_OF_RESOURCES;
-        break;
-      }
-      result = populate_ssl_context(
-          impl->ssl_contexts[i], pem_private_keys[i], pem_private_keys_sizes[i],
-          pem_cert_chains[i], pem_cert_chains_sizes[i], cipher_list);
-      if (result != TSI_OK) break;
-
-      if (pem_client_root_certs != NULL) {
-        int flags = SSL_VERIFY_PEER;
-        STACK_OF(X509_NAME) *root_names = NULL;
-        result = ssl_ctx_load_verification_certs(
-            impl->ssl_contexts[i], pem_client_root_certs,
-            pem_client_root_certs_size, &root_names);
-        if (result != TSI_OK) {
-          gpr_log(GPR_ERROR, "Invalid verification certs.");
-          break;
-        }
-        SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names);
-        if (force_client_auth) flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-        SSL_CTX_set_verify(impl->ssl_contexts[i], flags, NULL);
-        /* TODO(jboeuf): Add revocation verification. */
-      }
-
-      result = extract_x509_subject_names_from_pem_cert(
-          pem_cert_chains[i], pem_cert_chains_sizes[i],
-          &impl->ssl_context_x509_subject_names[i]);
-      if (result != TSI_OK) break;
-
-      SSL_CTX_set_tlsext_servername_callback(
-          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) {
-      tsi_ssl_handshaker_factory_destroy(&impl->base);
-      return result;
-    }
-  }
-  *factory = &impl->base;
-  return TSI_OK;
-}
-
-/* --- tsi_ssl utils. --- */
-
-int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name) {
-  size_t i = 0;
-  size_t san_count = 0;
-  const tsi_peer_property *cn_property = NULL;
-
-  /* For now reject what looks like an IP address. */
-  if (looks_like_ip_address(name)) return 0;
-
-  /* Check the SAN first. */
-  for (i = 0; i < peer->property_count; i++) {
-    const tsi_peer_property *property = &peer->properties[i];
-    if (property->name == NULL) continue;
-    if (strcmp(property->name,
-               TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
-      san_count++;
-      if (does_entry_match_name(property->value.data, property->value.length,
-                                name)) {
-        return 1;
-      }
-    } else if (strcmp(property->name,
-                      TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
-      cn_property = property;
-    }
-  }
-
-  /* If there's no SAN, try the CN. */
-  if (san_count == 0 && cn_property != NULL) {
-    if (does_entry_match_name(cn_property->value.data,
-                              cn_property->value.length, name)) {
-      return 1;
-    }
-  }
-
-  return 0; /* Not found. */
-}
diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h
deleted file mode 100644
index 51c0003..0000000
--- a/src/core/tsi/ssl_transport_security.h
+++ /dev/null
@@ -1,173 +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_TSI_SSL_TRANSPORT_SECURITY_H
-#define GRPC_INTERNAL_CORE_TSI_SSL_TRANSPORT_SECURITY_H
-
-#include "src/core/tsi/transport_security_interface.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */
-#define TSI_X509_CERTIFICATE_TYPE "X509"
-
-/* This property is of type TSI_PEER_PROPERTY_STRING.  */
-#define TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY "x509_subject_common_name"
-#define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \
-  "x509_subject_alternative_name"
-
-#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
-
-/* --- tsi_ssl_handshaker_factory object ---
-
-   This object creates tsi_handshaker objects implemented in terms of the
-   TLS 1.2 specificiation.  */
-
-typedef struct tsi_ssl_handshaker_factory tsi_ssl_handshaker_factory;
-
-/* Creates a client handshaker factory.
-   - pem_private_key is the buffer containing the PEM encoding of the client's
-     private key. This parameter can be NULL if the client does not have a
-     private key.
-   - pem_private_key_size is the size of the associated buffer.
-   - pem_cert_chain is the buffer containing the PEM encoding of the client's
-     certificate chain. This parameter can be NULL if the client does not have
-     a certificate chain.
-   - pem_cert_chain_size is the size of the associated buffer.
-   - pem_roots_cert is the buffer containing the PEM encoding of the server
-     root certificates. This parameter cannot be NULL.
-   - pem_roots_cert_size is the size of the associated buffer.
-   - cipher_suites contains an optional list of the ciphers that the client
-     supports. The format of this string is described in:
-     https://www.openssl.org/docs/apps/ciphers.html.
-     This parameter can be set to NULL to use the default set of ciphers.
-     TODO(jboeuf): Revisit the format of this parameter.
-   - alpn_protocols is an array containing the protocol names that the
-     handshakers created with this factory support. This parameter can be NULL.
-   - alpn_protocols_lengths is an array containing the lengths of the alpn
-     protocols specified in alpn_protocols. This parameter can be NULL.
-   - num_alpn_protocols is the number of alpn protocols and associated lengths
-     specified. If this parameter is 0, the other alpn parameters must be NULL.
-   - factory is the address of the factory pointer to be created.
-
-   - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
-     where a parameter is invalid.  */
-tsi_result tsi_create_ssl_client_handshaker_factory(
-    const unsigned char *pem_private_key, size_t pem_private_key_size,
-    const unsigned char *pem_cert_chain, size_t pem_cert_chain_size,
-    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
-    const char *cipher_suites, const unsigned char **alpn_protocols,
-    const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
-    tsi_ssl_handshaker_factory **factory);
-
-/* Creates a server handshaker factory.
-   - version indicates which version of the specification to use.
-   - pem_private_keys is an array containing the PEM encoding of the server's
-     private keys.  This parameter cannot be NULL. The size of the array is
-     given by the key_cert_pair_count parameter.
-   - pem_private_keys_sizes is the array containing the sizes of the associated
-     buffers.
-   - pem_cert_chains is an array containing the PEM encoding of the server's
-     cert chains.  This parameter cannot be NULL. The size of the array is
-     given by the key_cert_pair_count parameter.
-   - pem_cert_chains_sizes is the array containing the sizes of the associated
-     buffers.
-   - key_cert_pair_count indicates the number of items in the private_key_files
-     and cert_chain_files parameters.
-   - pem_client_roots is the buffer containing the PEM encoding of the client
-     root certificates. This parameter may be NULL in which case the server will
-     not authenticate the client. If not NULL, the force_client_auth parameter
-     specifies if the server will accept only authenticated clients or both
-     authenticated and non-authenticated clients.
-   - pem_client_root_certs_size is the size of the associated buffer.
-   - force_client_auth, if set to non-zero will force the client to authenticate
-     with an SSL cert. Note that this option is ignored if pem_client_root_certs
-     is NULL or pem_client_roots_certs_size is 0
-   - cipher_suites contains an optional list of the ciphers that the server
-     supports. The format of this string is described in:
-     https://www.openssl.org/docs/apps/ciphers.html.
-     This parameter can be set to NULL to use the default set of ciphers.
-     TODO(jboeuf): Revisit the format of this parameter.
-   - alpn_protocols is an array containing the protocol names that the
-     handshakers created with this factory support. This parameter can be NULL.
-   - alpn_protocols_lengths is an array containing the lengths of the alpn
-     protocols specified in alpn_protocols. This parameter can be NULL.
-   - num_alpn_protocols is the number of alpn protocols and associated lengths
-     specified. If this parameter is 0, the other alpn parameters must be NULL.
-   - factory is the address of the factory pointer to be created.
-
-   - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
-     where a parameter is invalid.  */
-tsi_result tsi_create_ssl_server_handshaker_factory(
-    const unsigned char **pem_private_keys,
-    const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains,
-    const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count,
-    const unsigned char *pem_client_root_certs,
-    size_t pem_client_root_certs_size, int force_client_auth,
-    const char *cipher_suites, const unsigned char **alpn_protocols,
-    const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
-    tsi_ssl_handshaker_factory **factory);
-
-/* Creates a handshaker.
-  - self is the factory from which the handshaker will be created.
-  - server_name_indication indicates the name of the server the client is
-    trying to connect to which will be relayed to the server using the SNI
-    extension.
-    This parameter must be NULL for a server handshaker factory.
-  - handhshaker is the address of the handshaker pointer to be created.
-
-  - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
-    where a parameter is invalid.  */
-tsi_result tsi_ssl_handshaker_factory_create_handshaker(
-    tsi_ssl_handshaker_factory *self, const char *server_name_indication,
-    tsi_handshaker **handshaker);
-
-/* Destroys the handshaker factory. WARNING: it is unsafe to destroy a factory
-   while handshakers created with this factory are still in use.  */
-void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self);
-
-/* Util that checks that an ssl peer matches a specific name.
-   Still TODO(jboeuf):
-   - handle mixed case.
-   - handle %encoded chars.
-   - handle public suffix wildchar more strictly (e.g. *.co.uk)
-   - handle IP addresses in SAN. */
-int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_TSI_SSL_TRANSPORT_SECURITY_H */
diff --git a/src/core/tsi/ssl_types.h b/src/core/tsi/ssl_types.h
deleted file mode 100644
index 0d0225e..0000000
--- a/src/core/tsi/ssl_types.h
+++ /dev/null
@@ -1,55 +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_TSI_SSL_TYPES_H
-#define GRPC_INTERNAL_CORE_TSI_SSL_TYPES_H
-
-/* A collection of macros to cast between various integer types that are
- * used differently between BoringSSL and OpenSSL:
- * TSI_INT_AS_SIZE(x):  convert 'int x' to a length parameter for an OpenSSL
- *                      function
- * TSI_SIZE_AS_SIZE(x): convert 'size_t x' to a length parameter for an OpenSSL
- *                      function
- */
-
-#include <openssl/ssl.h>
-
-#ifdef OPENSSL_IS_BORINGSSL
-#define TSI_INT_AS_SIZE(x) ((size_t)(x))
-#define TSI_SIZE_AS_SIZE(x) (x)
-#else
-#define TSI_INT_AS_SIZE(x) (x)
-#define TSI_SIZE_AS_SIZE(x) ((int)(x))
-#endif
-
-#endif
diff --git a/src/core/tsi/transport_security.c b/src/core/tsi/transport_security.c
deleted file mode 100644
index db219a5..0000000
--- a/src/core/tsi/transport_security.c
+++ /dev/null
@@ -1,284 +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/tsi/transport_security.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-/* --- Tracing. --- */
-
-int tsi_tracing_enabled = 0;
-
-/* --- Utils. --- */
-
-char *tsi_strdup(const char *src) {
-  char *dst;
-  size_t len;
-  if (!src) return NULL;
-  len = strlen(src) + 1;
-  dst = malloc(len);
-  if (!dst) return NULL;
-  memcpy(dst, src, len);
-  return dst;
-}
-
-/* --- tsi_result common implementation. --- */
-
-const char *tsi_result_to_string(tsi_result result) {
-  switch (result) {
-    case TSI_OK:
-      return "TSI_OK";
-    case TSI_UNKNOWN_ERROR:
-      return "TSI_UNKNOWN_ERROR";
-    case TSI_INVALID_ARGUMENT:
-      return "TSI_INVALID_ARGUMENT";
-    case TSI_PERMISSION_DENIED:
-      return "TSI_PERMISSION_DENIED";
-    case TSI_INCOMPLETE_DATA:
-      return "TSI_INCOMPLETE_DATA";
-    case TSI_FAILED_PRECONDITION:
-      return "TSI_FAILED_PRECONDITION";
-    case TSI_UNIMPLEMENTED:
-      return "TSI_UNIMPLEMENTED";
-    case TSI_INTERNAL_ERROR:
-      return "TSI_INTERNAL_ERROR";
-    case TSI_DATA_CORRUPTED:
-      return "TSI_DATA_CORRUPTED";
-    case TSI_NOT_FOUND:
-      return "TSI_NOT_FOUND";
-    case TSI_PROTOCOL_FAILURE:
-      return "TSI_PROTOCOL_FAILURE";
-    case TSI_HANDSHAKE_IN_PROGRESS:
-      return "TSI_HANDSHAKE_IN_PROGRESS";
-    case TSI_OUT_OF_RESOURCES:
-      return "TSI_OUT_OF_RESOURCES";
-    default:
-      return "UNKNOWN";
-  }
-}
-
-/* --- tsi_frame_protector common implementation. ---
-
-   Calls specific implementation after state/input validation. */
-
-tsi_result tsi_frame_protector_protect(tsi_frame_protector *self,
-                                       const unsigned char *unprotected_bytes,
-                                       size_t *unprotected_bytes_size,
-                                       unsigned char *protected_output_frames,
-                                       size_t *protected_output_frames_size) {
-  if (self == NULL || unprotected_bytes == NULL ||
-      unprotected_bytes_size == NULL || protected_output_frames == NULL ||
-      protected_output_frames_size == NULL) {
-    return TSI_INVALID_ARGUMENT;
-  }
-  return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size,
-                               protected_output_frames,
-                               protected_output_frames_size);
-}
-
-tsi_result tsi_frame_protector_protect_flush(
-    tsi_frame_protector *self, unsigned char *protected_output_frames,
-    size_t *protected_output_frames_size, size_t *still_pending_size) {
-  if (self == NULL || protected_output_frames == NULL ||
-      protected_output_frames == NULL || still_pending_size == NULL) {
-    return TSI_INVALID_ARGUMENT;
-  }
-  return self->vtable->protect_flush(self, protected_output_frames,
-                                     protected_output_frames_size,
-                                     still_pending_size);
-}
-
-tsi_result tsi_frame_protector_unprotect(
-    tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
-    size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
-    size_t *unprotected_bytes_size) {
-  if (self == NULL || protected_frames_bytes == NULL ||
-      protected_frames_bytes_size == NULL || unprotected_bytes == NULL ||
-      unprotected_bytes_size == NULL) {
-    return TSI_INVALID_ARGUMENT;
-  }
-  return self->vtable->unprotect(self, protected_frames_bytes,
-                                 protected_frames_bytes_size, unprotected_bytes,
-                                 unprotected_bytes_size);
-}
-
-void tsi_frame_protector_destroy(tsi_frame_protector *self) {
-  if (self == NULL) return;
-  self->vtable->destroy(self);
-}
-
-/* --- tsi_handshaker common implementation. ---
-
-   Calls specific implementation after state/input validation. */
-
-tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
-                                                    unsigned char *bytes,
-                                                    size_t *bytes_size) {
-  if (self == NULL || bytes == NULL || bytes_size == NULL) {
-    return TSI_INVALID_ARGUMENT;
-  }
-  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
-  return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
-}
-
-tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self,
-                                                  const unsigned char *bytes,
-                                                  size_t *bytes_size) {
-  if (self == NULL || bytes == NULL || bytes_size == NULL) {
-    return TSI_INVALID_ARGUMENT;
-  }
-  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
-  return self->vtable->process_bytes_from_peer(self, bytes, bytes_size);
-}
-
-tsi_result tsi_handshaker_get_result(tsi_handshaker *self) {
-  if (self == NULL) return TSI_INVALID_ARGUMENT;
-  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
-  return self->vtable->get_result(self);
-}
-
-tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer) {
-  if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT;
-  memset(peer, 0, sizeof(tsi_peer));
-  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
-  if (tsi_handshaker_get_result(self) != TSI_OK) {
-    return TSI_FAILED_PRECONDITION;
-  }
-  return self->vtable->extract_peer(self, peer);
-}
-
-tsi_result tsi_handshaker_create_frame_protector(
-    tsi_handshaker *self, size_t *max_protected_frame_size,
-    tsi_frame_protector **protector) {
-  tsi_result result;
-  if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT;
-  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
-  if (tsi_handshaker_get_result(self) != TSI_OK) {
-    return TSI_FAILED_PRECONDITION;
-  }
-  result = self->vtable->create_frame_protector(self, max_protected_frame_size,
-                                                protector);
-  if (result == TSI_OK) {
-    self->frame_protector_created = 1;
-  }
-  return result;
-}
-
-void tsi_handshaker_destroy(tsi_handshaker *self) {
-  if (self == NULL) return;
-  self->vtable->destroy(self);
-}
-
-/* --- tsi_peer implementation. --- */
-
-tsi_peer_property tsi_init_peer_property(void) {
-  tsi_peer_property property;
-  memset(&property, 0, sizeof(tsi_peer_property));
-  return property;
-}
-
-static void tsi_peer_destroy_list_property(tsi_peer_property *children,
-                                           size_t child_count) {
-  size_t i;
-  for (i = 0; i < child_count; i++) {
-    tsi_peer_property_destruct(&children[i]);
-  }
-  free(children);
-}
-
-void tsi_peer_property_destruct(tsi_peer_property *property) {
-  if (property->name != NULL) {
-    free(property->name);
-  }
-  if (property->value.data != NULL) {
-    free(property->value.data);
-  }
-  *property = tsi_init_peer_property(); /* Reset everything to 0. */
-}
-
-void tsi_peer_destruct(tsi_peer *self) {
-  if (self == NULL) return;
-  if (self->properties != NULL) {
-    tsi_peer_destroy_list_property(self->properties, self->property_count);
-    self->properties = NULL;
-  }
-  self->property_count = 0;
-}
-
-tsi_result tsi_construct_allocated_string_peer_property(
-    const char *name, size_t value_length, tsi_peer_property *property) {
-  *property = tsi_init_peer_property();
-  if (name != NULL) {
-    property->name = tsi_strdup(name);
-    if (property->name == NULL) return TSI_OUT_OF_RESOURCES;
-  }
-  if (value_length > 0) {
-    property->value.data = calloc(1, value_length);
-    if (property->value.data == NULL) {
-      tsi_peer_property_destruct(property);
-      return TSI_OUT_OF_RESOURCES;
-    }
-    property->value.length = value_length;
-  }
-  return TSI_OK;
-}
-
-tsi_result tsi_construct_string_peer_property_from_cstring(
-    const char *name, const char *value, tsi_peer_property *property) {
-  return tsi_construct_string_peer_property(name, value, strlen(value),
-                                            property);
-}
-
-tsi_result tsi_construct_string_peer_property(const char *name,
-                                              const char *value,
-                                              size_t value_length,
-                                              tsi_peer_property *property) {
-  tsi_result result = tsi_construct_allocated_string_peer_property(
-      name, value_length, property);
-  if (result != TSI_OK) return result;
-  if (value_length > 0) {
-    memcpy(property->value.data, value, value_length);
-  }
-  return TSI_OK;
-}
-
-tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer) {
-  memset(peer, 0, sizeof(tsi_peer));
-  if (property_count > 0) {
-    peer->properties = calloc(property_count, sizeof(tsi_peer_property));
-    if (peer->properties == NULL) return TSI_OUT_OF_RESOURCES;
-    peer->property_count = property_count;
-  }
-  return TSI_OK;
-}
diff --git a/src/core/tsi/transport_security.h b/src/core/tsi/transport_security.h
deleted file mode 100644
index 4077737..0000000
--- a/src/core/tsi/transport_security.h
+++ /dev/null
@@ -1,111 +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_TSI_TRANSPORT_SECURITY_H
-#define GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_H
-
-#include "src/core/tsi/transport_security_interface.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern int tsi_tracing_enabled;
-
-/* Base for tsi_frame_protector implementations.
-   See transport_security_interface.h for documentation. */
-typedef struct {
-  tsi_result (*protect)(tsi_frame_protector *self,
-                        const unsigned char *unprotected_bytes,
-                        size_t *unprotected_bytes_size,
-                        unsigned char *protected_output_frames,
-                        size_t *protected_output_frames_size);
-  tsi_result (*protect_flush)(tsi_frame_protector *self,
-                              unsigned char *protected_output_frames,
-                              size_t *protected_output_frames_size,
-                              size_t *still_pending_size);
-  tsi_result (*unprotect)(tsi_frame_protector *self,
-                          const unsigned char *protected_frames_bytes,
-                          size_t *protected_frames_bytes_size,
-                          unsigned char *unprotected_bytes,
-                          size_t *unprotected_bytes_size);
-  void (*destroy)(tsi_frame_protector *self);
-} tsi_frame_protector_vtable;
-
-struct tsi_frame_protector {
-  const tsi_frame_protector_vtable *vtable;
-};
-
-/* Base for tsi_handshaker implementations.
-   See transport_security_interface.h for documentation. */
-typedef struct {
-  tsi_result (*get_bytes_to_send_to_peer)(tsi_handshaker *self,
-                                          unsigned char *bytes,
-                                          size_t *bytes_size);
-  tsi_result (*process_bytes_from_peer)(tsi_handshaker *self,
-                                        const unsigned char *bytes,
-                                        size_t *bytes_size);
-  tsi_result (*get_result)(tsi_handshaker *self);
-  tsi_result (*extract_peer)(tsi_handshaker *self, tsi_peer *peer);
-  tsi_result (*create_frame_protector)(tsi_handshaker *self,
-                                       size_t *max_protected_frame_size,
-                                       tsi_frame_protector **protector);
-  void (*destroy)(tsi_handshaker *self);
-} tsi_handshaker_vtable;
-
-struct tsi_handshaker {
-  const tsi_handshaker_vtable *vtable;
-  int frame_protector_created;
-};
-
-/* Peer and property construction/destruction functions. */
-tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer);
-tsi_peer_property tsi_init_peer_property(void);
-void tsi_peer_property_destruct(tsi_peer_property *property);
-tsi_result tsi_construct_string_peer_property(const char *name,
-                                              const char *value,
-                                              size_t value_length,
-                                              tsi_peer_property *property);
-tsi_result tsi_construct_allocated_string_peer_property(
-    const char *name, size_t value_length, tsi_peer_property *property);
-tsi_result tsi_construct_string_peer_property_from_cstring(
-    const char *name, const char *value, tsi_peer_property *property);
-
-/* Utils. */
-char *tsi_strdup(const char *src); /* Sadly, no strdup in C89. */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_H */
diff --git a/src/core/tsi/transport_security_interface.h b/src/core/tsi/transport_security_interface.h
deleted file mode 100644
index 69ee17a..0000000
--- a/src/core/tsi/transport_security_interface.h
+++ /dev/null
@@ -1,344 +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_TSI_TRANSPORT_SECURITY_INTERFACE_H
-#define GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H
-
-#include <stdint.h>
-#include <stdlib.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* --- tsi result ---  */
-
-typedef enum {
-  TSI_OK = 0,
-  TSI_UNKNOWN_ERROR = 1,
-  TSI_INVALID_ARGUMENT = 2,
-  TSI_PERMISSION_DENIED = 3,
-  TSI_INCOMPLETE_DATA = 4,
-  TSI_FAILED_PRECONDITION = 5,
-  TSI_UNIMPLEMENTED = 6,
-  TSI_INTERNAL_ERROR = 7,
-  TSI_DATA_CORRUPTED = 8,
-  TSI_NOT_FOUND = 9,
-  TSI_PROTOCOL_FAILURE = 10,
-  TSI_HANDSHAKE_IN_PROGRESS = 11,
-  TSI_OUT_OF_RESOURCES = 12
-} tsi_result;
-
-const char *tsi_result_to_string(tsi_result result);
-
-/* --- tsi tracing --- */
-
-/* Set this early to avoid races */
-extern int tsi_tracing_enabled;
-
-/* --- tsi_frame_protector object ---
-
-  This object protects and unprotects buffers once the handshake is done.
-  Implementations of this object must be thread compatible.  */
-
-typedef struct tsi_frame_protector tsi_frame_protector;
-
-/* Outputs protected frames.
-   - unprotected_bytes is an input only parameter and points to the data
-     to be protected.
-   - unprotected_bytes_size is an input/output parameter used by the caller to
-     specify how many bytes are available in unprotected_bytes. The output
-     value is the number of bytes consumed during the call.
-   - protected_output_frames points to a buffer allocated by the caller that
-     will be written.
-   - protected_output_frames_size is an input/output parameter used by the
-     caller to specify how many bytes are available in protected_output_frames.
-     As an output, this value indicates the number of bytes written.
-   - This method returns TSI_OK in case of success or a specific error code in
-     case of failure. Note that even if all the input unprotected bytes are
-     consumed, they may not have been processed into the returned protected
-     output frames. The caller should call the protect_flush method
-     to make sure that there are no more protected bytes buffered in the
-     protector.
-
-   A typical way to call this method would be:
-
-   ------------------------------------------------------------------------
-   unsigned char protected_buffer[4096];
-   size_t protected_buffer_size = sizeof(protected_buffer);
-   tsi_result result = TSI_OK;
-   while (message_size > 0) {
-     size_t protected_buffer_size_to_send = protected_buffer_size;
-     size_t processed_message_size = message_size;
-     result = tsi_frame_protector_protect(protector,
-                                          message_bytes,
-                                          &processed_message_size,
-                                          protected_buffer,
-                                          &protected_buffer_size_to_send);
-     if (result != TSI_OK) break;
-     send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send);
-     message_bytes += processed_message_size;
-     message_size -= processed_message_size;
-
-     // Don't forget to flush.
-     if (message_size == 0) {
-       size_t still_pending_size;
-       do {
-         protected_buffer_size_to_send = protected_buffer_size;
-         result = tsi_frame_protector_protect_flush(
-             protector, protected_buffer,
-             &protected_buffer_size_to_send, &still_pending_size);
-         if (result != TSI_OK) break;
-         send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send);
-       } while (still_pending_size > 0);
-     }
-   }
-
-   if (result != TSI_OK) HandleError(result);
-   ------------------------------------------------------------------------  */
-tsi_result tsi_frame_protector_protect(tsi_frame_protector *self,
-                                       const unsigned char *unprotected_bytes,
-                                       size_t *unprotected_bytes_size,
-                                       unsigned char *protected_output_frames,
-                                       size_t *protected_output_frames_size);
-
-/* Indicates that we need to flush the bytes buffered in the protector and get
-   the resulting frame.
-   - protected_output_frames points to a buffer allocated by the caller that
-     will be written.
-   - protected_output_frames_size is an input/output parameter used by the
-     caller to specify how many bytes are available in protected_output_frames.
-   - still_pending_bytes is an output parameter indicating the number of bytes
-     that still need to be flushed from the protector.*/
-tsi_result tsi_frame_protector_protect_flush(
-    tsi_frame_protector *self, unsigned char *protected_output_frames,
-    size_t *protected_output_frames_size, size_t *still_pending_size);
-
-/* Outputs unprotected bytes.
-   - protected_frames_bytes is an input only parameter and points to the
-     protected frames to be unprotected.
-   - protected_frames_bytes_size is an input/output only parameter used by the
-     caller to specify how many bytes are available in protected_bytes. The
-     output value is the number of bytes consumed during the call.
-     Implementations will buffer up to a frame of protected data.
-   - unprotected_bytes points to a buffer allocated by the caller that will be
-     written.
-   - unprotected_bytes_size is an input/output parameter used by the caller to
-     specify how many bytes are available in unprotected_bytes. This
-     value is expected to be at most max_protected_frame_size minus overhead
-     which means that max_protected_frame_size is a safe bet. The output value
-     is the number of bytes actually written.
-     If *unprotected_bytes_size is unchanged, there may be more data remaining
-     to unprotect, and the caller should call this function again.
-
-   - This method returns TSI_OK in case of success. Success includes cases where
-     there is not enough data to output a frame in which case
-     unprotected_bytes_size will be set to 0 and cases where the internal buffer
-     needs to be read before new protected data can be processed in which case
-     protected_frames_size will be set to 0.  */
-tsi_result tsi_frame_protector_unprotect(
-    tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
-    size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
-    size_t *unprotected_bytes_size);
-
-/* Destroys the tsi_frame_protector object.  */
-void tsi_frame_protector_destroy(tsi_frame_protector *self);
-
-/* --- tsi_peer objects ---
-
-   tsi_peer objects are a set of properties. The peer owns the properties.  */
-
-/* This property is of type TSI_PEER_PROPERTY_STRING.  */
-#define TSI_CERTIFICATE_TYPE_PEER_PROPERTY "certificate_type"
-
-/* Property values may contain NULL characters just like C++ strings.
-   The length field gives the length of the string. */
-typedef struct tsi_peer_property {
-  char *name;
-  struct {
-    char *data;
-    size_t length;
-  } value;
-} tsi_peer_property;
-
-typedef struct {
-  tsi_peer_property *properties;
-  size_t property_count;
-} tsi_peer;
-
-/* Destructs the tsi_peer object. */
-void tsi_peer_destruct(tsi_peer *self);
-
-/* --- tsi_handshaker objects ----
-
-   Implementations of this object must be thread compatible.
-
-   A typical usage of this object would be:
-
-   ------------------------------------------------------------------------
-   tsi_result result = TSI_OK;
-   unsigned char buf[4096];
-   size_t buf_offset;
-   size_t buf_size;
-   while (1) {
-     // See if we need to send some bytes to the peer.
-     do {
-       size_t buf_size_to_send = sizeof(buf);
-       result = tsi_handshaker_get_bytes_to_send_to_peer(handshaker, buf,
-                                                         &buf_size_to_send);
-       if (buf_size_to_send > 0) send_bytes_to_peer(buf, buf_size_to_send);
-     } while (result == TSI_INCOMPLETE_DATA);
-     if (result != TSI_OK) return result;
-     if (!tsi_handshaker_is_in_progress(handshaker)) break;
-
-     do {
-       // Read bytes from the peer.
-       buf_size = sizeof(buf);
-       buf_offset = 0;
-       read_bytes_from_peer(buf, &buf_size);
-       if (buf_size == 0) break;
-
-       // Process the bytes from the peer. We have to be careful as these bytes
-       // may contain non-handshake data (protected data). If this is the case,
-       // we will exit from the loop with buf_size > 0.
-       size_t consumed_by_handshaker = buf_size;
-       result = tsi_handshaker_process_bytes_from_peer(
-           handshaker, buf, &consumed_by_handshaker);
-       buf_size -= consumed_by_handshaker;
-       buf_offset += consumed_by_handshaker;
-     } while (result == TSI_INCOMPLETE_DATA);
-
-     if (result != TSI_OK) return result;
-     if (!tsi_handshaker_is_in_progress(handshaker)) break;
-   }
-
-   // Check the Peer.
-   tsi_peer peer;
-   do {
-     result = tsi_handshaker_extract_peer(handshaker, &peer);
-     if (result != TSI_OK) break;
-     result = check_peer(&peer);
-   } while (0);
-   tsi_peer_destruct(&peer);
-   if (result != TSI_OK) return result;
-
-   // Create the protector.
-   tsi_frame_protector* protector = NULL;
-   result = tsi_handshaker_create_frame_protector(handshaker, NULL,
-                                                  &protector);
-   if (result != TSI_OK) return result;
-
-   // Do not forget to unprotect outstanding data if any.
-   if (buf_size > 0) {
-     result = tsi_frame_protector_unprotect(protector, buf + buf_offset,
-                                            buf_size, ..., ...);
-     ....
-   }
-   ...
-   ------------------------------------------------------------------------   */
-typedef struct tsi_handshaker tsi_handshaker;
-
-/* Gets bytes that need to be sent to the peer.
-   - bytes is the buffer that will be written with the data to be sent to the
-     peer.
-   - bytes_size is an input/output parameter specifying the capacity of the
-     bytes parameter as input and the number of bytes written as output.
-   Returns TSI_OK if all the data to send to the peer has been written or if
-   nothing has to be sent to the peer (in which base bytes_size outputs to 0),
-   otherwise returns TSI_INCOMPLETE_DATA which indicates that this method
-   needs to be called again to get all the bytes to send to the peer (there
-   was more data to write than the specified bytes_size). In case of a fatal
-   error in the handshake, another specific error code is returned.  */
-tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
-                                                    unsigned char *bytes,
-                                                    size_t *bytes_size);
-
-/* Processes bytes received from the peer.
-   - bytes is the buffer containing the data.
-   - bytes_size is an input/output parameter specifying the size of the data as
-     input and the number of bytes consumed as output.
-   Return TSI_OK if the handshake has all the data it needs to process,
-   otherwise return TSI_INCOMPLETE_DATA which indicates that this method
-   needs to be called again to complete the data needed for processing. In
-   case of a fatal error in the handshake, another specific error code is
-   returned.  */
-tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self,
-                                                  const unsigned char *bytes,
-                                                  size_t *bytes_size);
-
-/* Gets the result of the handshaker.
-   Returns TSI_OK if the hanshake completed successfully and there has been no
-   errors. Returns TSI_HANDSHAKE_IN_PROGRESS if the handshaker is not done yet
-   but no error has been encountered so far. Otherwise the handshaker failed
-   with the returned error.  */
-tsi_result tsi_handshaker_get_result(tsi_handshaker *self);
-
-/* Returns 1 if the handshake is in progress, 0 otherwise.  */
-#define tsi_handshaker_is_in_progress(h) \
-  (tsi_handshaker_get_result((h)) == TSI_HANDSHAKE_IN_PROGRESS)
-
-/* This method may return TSI_FAILED_PRECONDITION if
-   tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise
-   assuming the handshaker is not in a fatal error state.
-   The caller is responsible for destructing the peer.  */
-tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer);
-
-/* This method creates a tsi_frame_protector object after the handshake phase
-   is done. After this method has been called successfully, the only method
-   that can be called on this object is Destroy.
-   - max_output_protected_frame_size is an input/output parameter specifying the
-     desired max output protected frame size as input and outputing the actual
-     max output frame size as the output. Passing NULL is OK and will result in
-     the implementation choosing the default maximum protected frame size. Note
-     that this size only applies to outgoing frames (generated with
-     tsi_frame_protector_protect) and not incoming frames (input of
-     tsi_frame_protector_unprotect).
-   - protector is an output parameter pointing to the newly created
-     tsi_frame_protector object.
-   This method may return TSI_FAILED_PRECONDITION if
-   tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise assuming
-   the handshaker is not in a fatal error state.
-   The caller is responsible for destroying the protector.  */
-tsi_result tsi_handshaker_create_frame_protector(
-    tsi_handshaker *self, size_t *max_output_protected_frame_size,
-    tsi_frame_protector **protector);
-
-/* This method releases the tsi_handshaker object. After this method is called,
-   no other method can be called on the object.  */
-void tsi_handshaker_destroy(tsi_handshaker *self);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_INTERNAL_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H */
diff --git a/src/cpp/README.md b/src/cpp/README.md
index 83d37aa..f2935e5 100644
--- a/src/cpp/README.md
+++ b/src/cpp/README.md
@@ -61,7 +61,7 @@
 #Documentation
 
 You can find out how to build and run our simplest gRPC C++ example in our
-[C++ quick start](https://github.com/grpc/grpc/tree/{{ site.data.config.grpc_release_branch }}/examples/cpp).
+[C++ quick start](../../examples/cpp).
 
 For more detailed documentation on using gRPC in C++ , see our main
 documentation site at [grpc.io](http://grpc.io), specifically:
@@ -79,4 +79,4 @@
 # Examples
 
 Code examples for gRPC C++ live in this repository's
-[examples/cpp](https://github.com/grpc/grpc/tree/{{ site.data.config.grpc_release_branch }}/examples/cpp) directory.
+[examples/cpp](../../examples/cpp) directory.
diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc
index ae20392..f174676 100644
--- a/src/cpp/client/channel.cc
+++ b/src/cpp/client/channel.cc
@@ -49,7 +49,7 @@
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/slice.h>
-#include "src/core/profiling/timers.h"
+#include "src/core/lib/profiling/timers.h"
 
 namespace grpc {
 
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 73147fd..de8b2db 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -33,15 +33,15 @@
 
 #include <grpc++/client_context.h>
 
+#include <grpc++/security/credentials.h>
+#include <grpc++/server_context.h>
+#include <grpc++/support/time.h>
 #include <grpc/compression.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/server_context.h>
-#include <grpc++/support/time.h>
 
-#include "src/core/channel/compress_filter.h"
+#include "src/core/lib/channel/compress_filter.h"
 #include "src/cpp/common/create_auth_context.h"
 
 namespace grpc {
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index 1293203..efea029 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,11 +33,11 @@
 
 #include <grpc++/security/credentials.h>
 
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
 #include <grpc++/channel.h>
 #include <grpc++/support/channel_arguments.h>
 #include <grpc++/support/config.h>
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
 #include "src/cpp/client/create_channel_internal.h"
 
 namespace grpc {
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index 074dae7..cdc8406 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -31,12 +31,12 @@
  *
  */
 
+#include "src/cpp/client/secure_credentials.h"
 #include <grpc++/channel.h>
 #include <grpc++/impl/grpc_library.h>
 #include <grpc++/support/channel_arguments.h>
 #include <grpc/support/log.h>
 #include "src/cpp/client/create_channel_internal.h"
-#include "src/cpp/client/secure_credentials.h"
 #include "src/cpp/common/secure_auth_context.h"
 
 namespace grpc {
@@ -60,8 +60,7 @@
 
 SecureCallCredentials::SecureCallCredentials(grpc_call_credentials* c_creds)
     : c_creds_(c_creds) {
-  internal::GrpcLibraryInitializer gli_initializer;
-  gli_initializer.summon();
+  g_gli_initializer.summon();
 }
 
 bool SecureCallCredentials::ApplyToCall(grpc_call* call) {
@@ -83,14 +82,14 @@
 }  // namespace
 
 std::shared_ptr<ChannelCredentials> GoogleDefaultCredentials() {
-  GrpcLibrary init;  // To call grpc_init().
+  GrpcLibraryCodegen init;  // To call grpc_init().
   return WrapChannelCredentials(grpc_google_default_credentials_create());
 }
 
 // Builds SSL Credentials given SSL specific options
 std::shared_ptr<ChannelCredentials> SslCredentials(
     const SslCredentialsOptions& options) {
-  GrpcLibrary init;  // To call grpc_init().
+  GrpcLibraryCodegen init;  // To call grpc_init().
   grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {
       options.pem_private_key.c_str(), options.pem_cert_chain.c_str()};
 
@@ -102,7 +101,7 @@
 
 // Builds credentials for use when running in GCE
 std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials() {
-  GrpcLibrary init;  // To call grpc_init().
+  GrpcLibraryCodegen init;  // To call grpc_init().
   return WrapCallCredentials(
       grpc_google_compute_engine_credentials_create(nullptr));
 }
@@ -110,7 +109,7 @@
 // Builds JWT credentials.
 std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
     const grpc::string& json_key, long token_lifetime_seconds) {
-  GrpcLibrary init;  // To call grpc_init().
+  GrpcLibraryCodegen init;  // To call grpc_init().
   if (token_lifetime_seconds <= 0) {
     gpr_log(GPR_ERROR,
             "Trying to create JWTCredentials with non-positive lifetime");
@@ -125,7 +124,7 @@
 // Builds refresh token credentials.
 std::shared_ptr<CallCredentials> GoogleRefreshTokenCredentials(
     const grpc::string& json_refresh_token) {
-  GrpcLibrary init;  // To call grpc_init().
+  GrpcLibraryCodegen init;  // To call grpc_init().
   return WrapCallCredentials(grpc_google_refresh_token_credentials_create(
       json_refresh_token.c_str(), nullptr));
 }
@@ -133,7 +132,7 @@
 // Builds access token credentials.
 std::shared_ptr<CallCredentials> AccessTokenCredentials(
     const grpc::string& access_token) {
-  GrpcLibrary init;  // To call grpc_init().
+  GrpcLibraryCodegen init;  // To call grpc_init().
   return WrapCallCredentials(
       grpc_access_token_credentials_create(access_token.c_str(), nullptr));
 }
@@ -142,7 +141,7 @@
 std::shared_ptr<CallCredentials> GoogleIAMCredentials(
     const grpc::string& authorization_token,
     const grpc::string& authority_selector) {
-  GrpcLibrary init;  // To call grpc_init().
+  GrpcLibraryCodegen init;  // To call grpc_init().
   return WrapCallCredentials(grpc_google_iam_credentials_create(
       authorization_token.c_str(), authority_selector.c_str(), nullptr));
 }
@@ -224,7 +223,7 @@
 
 std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
     std::unique_ptr<MetadataCredentialsPlugin> plugin) {
-  GrpcLibrary init;  // To call grpc_init().
+  GrpcLibraryCodegen init;  // To call grpc_init().
   const char* type = plugin->GetType();
   MetadataCredentialsPluginWrapper* wrapper =
       new MetadataCredentialsPluginWrapper(std::move(plugin));
diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h
index 9e84102..fd82331 100644
--- a/src/cpp/client/secure_credentials.h
+++ b/src/cpp/client/secure_credentials.h
@@ -36,8 +36,8 @@
 
 #include <grpc/grpc_security.h>
 
-#include <grpc++/support/config.h>
 #include <grpc++/security/credentials.h>
+#include <grpc++/support/config.h>
 
 #include "src/cpp/server/thread_pool_interface.h"
 
diff --git a/src/cpp/codegen/codegen_init.cc b/src/cpp/codegen/codegen_init.cc
new file mode 100644
index 0000000..c5d2212
--- /dev/null
+++ b/src/cpp/codegen/codegen_init.cc
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc++/impl/codegen/core_codegen_interface.h>
+#include <grpc++/impl/codegen/grpc_library.h>
+
+/// Initializes the global gRPC variables for the codegen library. These will
+/// stay null in the absence of of grpc++ library. In this case, no gRPC
+/// features such as the ability to perform calls will be available. Trying to
+/// perform them would result in a segmentation fault when trying to deference
+/// the following nulled globals. These should be associated with actual
+/// as part of the instantiation of a \a grpc::GrpcLibraryInitializer variable.
+
+grpc::CoreCodegenInterface* grpc::g_core_codegen_interface = nullptr;
+grpc::GrpcLibraryInterface* grpc::g_glip = nullptr;
diff --git a/src/cpp/codegen/grpc_library.cc b/src/cpp/codegen/grpc_library.cc
deleted file mode 100644
index 48acec3..0000000
--- a/src/cpp/codegen/grpc_library.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *
- * Copyright 2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc++/impl/codegen/grpc_library.h>
-
-namespace grpc {
-
-GrpcLibraryInterface *g_glip = nullptr;
-
-}  // namespace grpc
diff --git a/src/cpp/common/call.cc b/src/cpp/common/call.cc
deleted file mode 100644
index 5b87c2a..0000000
--- a/src/cpp/common/call.cc
+++ /dev/null
@@ -1,92 +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/call.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/support/byte_buffer.h>
-#include "src/core/profiling/timers.h"
-
-namespace grpc {
-
-void FillMetadataMap(
-    grpc_metadata_array* arr,
-    std::multimap<grpc::string_ref, grpc::string_ref>* metadata) {
-  for (size_t i = 0; i < arr->count; i++) {
-    // TODO(yangg) handle duplicates?
-    metadata->insert(std::pair<grpc::string_ref, grpc::string_ref>(
-        arr->metadata[i].key, grpc::string_ref(arr->metadata[i].value,
-                                               arr->metadata[i].value_length)));
-  }
-  grpc_metadata_array_destroy(arr);
-  grpc_metadata_array_init(arr);
-}
-
-// 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;
-  }
-  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;
-}
-
-Call::Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq)
-    : call_hook_(call_hook), cq_(cq), call_(call), max_message_size_(-1) {}
-
-Call::Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq,
-           int max_message_size)
-    : call_hook_(call_hook),
-      cq_(cq),
-      call_(call),
-      max_message_size_(max_message_size) {}
-
-void Call::PerformOps(CallOpSetInterface* ops) {
-  if (max_message_size_ > 0) {
-    ops->set_max_message_size(max_message_size_);
-  }
-  call_hook_->PerformOpsOnCall(ops, this);
-}
-
-}  // namespace grpc
diff --git a/src/cpp/common/channel_arguments.cc b/src/cpp/common/channel_arguments.cc
index d7faa5e..3bdb439 100644
--- a/src/cpp/common/channel_arguments.cc
+++ b/src/cpp/common/channel_arguments.cc
@@ -36,7 +36,7 @@
 
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/log.h>
-#include "src/core/channel/channel_args.h"
+#include "src/core/lib/channel/channel_args.h"
 
 namespace grpc {
 
diff --git a/src/cpp/common/completion_queue.cc b/src/cpp/common/completion_queue.cc
index 4f76dff..729dc33 100644
--- a/src/cpp/common/completion_queue.cc
+++ b/src/cpp/common/completion_queue.cc
@@ -34,7 +34,6 @@
 
 #include <memory>
 
-#include <grpc++/impl/codegen/completion_queue_tag.h>
 #include <grpc++/impl/grpc_library.h>
 #include <grpc++/support/time.h>
 #include <grpc/grpc.h>
@@ -43,16 +42,13 @@
 namespace grpc {
 
 static internal::GrpcLibraryInitializer g_gli_initializer;
-CompletionQueue::CompletionQueue() {
-  g_gli_initializer.summon();
-  cq_ = grpc_completion_queue_create(nullptr);
-}
 
 CompletionQueue::CompletionQueue(grpc_completion_queue* take) : cq_(take) {}
 
-CompletionQueue::~CompletionQueue() { grpc_completion_queue_destroy(cq_); }
-
-void CompletionQueue::Shutdown() { grpc_completion_queue_shutdown(cq_); }
+void CompletionQueue::Shutdown() {
+  g_gli_initializer.summon();
+  grpc_completion_queue_shutdown(cq_);
+}
 
 CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(
     void** tag, bool* ok, gpr_timespec deadline) {
@@ -75,25 +71,4 @@
   }
 }
 
-bool CompletionQueue::Pluck(CompletionQueueTag* tag) {
-  auto deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
-  auto ev = grpc_completion_queue_pluck(cq_, tag, deadline, nullptr);
-  bool ok = ev.success != 0;
-  void* ignored = tag;
-  GPR_ASSERT(tag->FinalizeResult(&ignored, &ok));
-  GPR_ASSERT(ignored == tag);
-  // Ignore mutations by FinalizeResult: Pluck returns the C API status
-  return ev.success != 0;
-}
-
-void CompletionQueue::TryPluck(CompletionQueueTag* tag) {
-  auto deadline = gpr_time_0(GPR_CLOCK_REALTIME);
-  auto ev = grpc_completion_queue_pluck(cq_, tag, deadline, nullptr);
-  if (ev.type == GRPC_QUEUE_TIMEOUT) return;
-  bool ok = ev.success != 0;
-  void* ignored = tag;
-  // the tag must be swallowed if using TryPluck
-  GPR_ASSERT(!tag->FinalizeResult(&ignored, &ok));
-}
-
 }  // namespace grpc
diff --git a/src/cpp/common/core_codegen.cc b/src/cpp/common/core_codegen.cc
new file mode 100644
index 0000000..33a8f75
--- /dev/null
+++ b/src/cpp/common/core_codegen.cc
@@ -0,0 +1,256 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/cpp/common/core_codegen.h"
+
+#include <stdlib.h>
+
+#include <grpc++/support/config.h>
+#include <grpc/byte_buffer.h>
+#include <grpc/byte_buffer_reader.h>
+#include <grpc/grpc.h>
+#include <grpc/impl/codegen/alloc.h>
+#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc/impl/codegen/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
+
+#include "src/core/lib/profiling/timers.h"
+
+namespace {
+
+const int kGrpcBufferWriterMaxBufferLength = 8192;
+
+class GrpcBufferWriter GRPC_FINAL
+    : public ::grpc::protobuf::io::ZeroCopyOutputStream {
+ public:
+  explicit GrpcBufferWriter(grpc_byte_buffer** bp, int block_size)
+      : block_size_(block_size), byte_count_(0), have_backup_(false) {
+    *bp = grpc_raw_byte_buffer_create(NULL, 0);
+    slice_buffer_ = &(*bp)->data.raw.slice_buffer;
+  }
+
+  ~GrpcBufferWriter() GRPC_OVERRIDE {
+    if (have_backup_) {
+      gpr_slice_unref(backup_slice_);
+    }
+  }
+
+  bool Next(void** data, int* size) GRPC_OVERRIDE {
+    if (have_backup_) {
+      slice_ = backup_slice_;
+      have_backup_ = false;
+    } else {
+      slice_ = gpr_slice_malloc(block_size_);
+    }
+    *data = GPR_SLICE_START_PTR(slice_);
+    // On win x64, int is only 32bit
+    GPR_ASSERT(GPR_SLICE_LENGTH(slice_) <= INT_MAX);
+    byte_count_ += * size = (int)GPR_SLICE_LENGTH(slice_);
+    gpr_slice_buffer_add(slice_buffer_, slice_);
+    return true;
+  }
+
+  void BackUp(int count) GRPC_OVERRIDE {
+    gpr_slice_buffer_pop(slice_buffer_);
+    if (count == block_size_) {
+      backup_slice_ = slice_;
+    } else {
+      backup_slice_ =
+          gpr_slice_split_tail(&slice_, GPR_SLICE_LENGTH(slice_) - count);
+      gpr_slice_buffer_add(slice_buffer_, slice_);
+    }
+    have_backup_ = true;
+    byte_count_ -= count;
+  }
+
+  grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE { return byte_count_; }
+
+ private:
+  const int block_size_;
+  int64_t byte_count_;
+  gpr_slice_buffer* slice_buffer_;
+  bool have_backup_;
+  gpr_slice backup_slice_;
+  gpr_slice slice_;
+};
+
+class GrpcBufferReader GRPC_FINAL
+    : public ::grpc::protobuf::io::ZeroCopyInputStream {
+ public:
+  explicit GrpcBufferReader(grpc_byte_buffer* buffer)
+      : byte_count_(0), backup_count_(0) {
+    grpc_byte_buffer_reader_init(&reader_, buffer);
+  }
+  ~GrpcBufferReader() GRPC_OVERRIDE {
+    grpc_byte_buffer_reader_destroy(&reader_);
+  }
+
+  bool Next(const void** data, int* size) GRPC_OVERRIDE {
+    if (backup_count_ > 0) {
+      *data = GPR_SLICE_START_PTR(slice_) + GPR_SLICE_LENGTH(slice_) -
+              backup_count_;
+      GPR_ASSERT(backup_count_ <= INT_MAX);
+      *size = (int)backup_count_;
+      backup_count_ = 0;
+      return true;
+    }
+    if (!grpc_byte_buffer_reader_next(&reader_, &slice_)) {
+      return false;
+    }
+    gpr_slice_unref(slice_);
+    *data = GPR_SLICE_START_PTR(slice_);
+    // On win x64, int is only 32bit
+    GPR_ASSERT(GPR_SLICE_LENGTH(slice_) <= INT_MAX);
+    byte_count_ += * size = (int)GPR_SLICE_LENGTH(slice_);
+    return true;
+  }
+
+  void BackUp(int count) GRPC_OVERRIDE { backup_count_ = count; }
+
+  bool Skip(int count) GRPC_OVERRIDE {
+    const void* data;
+    int size;
+    while (Next(&data, &size)) {
+      if (size >= count) {
+        BackUp(size - count);
+        return true;
+      }
+      // size < count;
+      count -= size;
+    }
+    // error or we have too large count;
+    return false;
+  }
+
+  grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE {
+    return byte_count_ - backup_count_;
+  }
+
+ private:
+  int64_t byte_count_;
+  int64_t backup_count_;
+  grpc_byte_buffer_reader reader_;
+  gpr_slice slice_;
+};
+}  // namespace
+
+namespace grpc {
+
+grpc_completion_queue* CoreCodegen::grpc_completion_queue_create(
+    void* reserved) {
+  return ::grpc_completion_queue_create(reserved);
+}
+
+void CoreCodegen::grpc_completion_queue_destroy(grpc_completion_queue* cq) {
+  ::grpc_completion_queue_destroy(cq);
+}
+
+grpc_event CoreCodegen::grpc_completion_queue_pluck(grpc_completion_queue* cq,
+                                                    void* tag,
+                                                    gpr_timespec deadline,
+                                                    void* reserved) {
+  return ::grpc_completion_queue_pluck(cq, tag, deadline, reserved);
+}
+
+void* CoreCodegen::gpr_malloc(size_t size) { return ::gpr_malloc(size); }
+
+void CoreCodegen::gpr_free(void* p) { return ::gpr_free(p); }
+
+void CoreCodegen::grpc_byte_buffer_destroy(grpc_byte_buffer* bb) {
+  ::grpc_byte_buffer_destroy(bb);
+}
+
+void CoreCodegen::grpc_metadata_array_init(grpc_metadata_array* array) {
+  ::grpc_metadata_array_init(array);
+}
+
+void CoreCodegen::grpc_metadata_array_destroy(grpc_metadata_array* array) {
+  ::grpc_metadata_array_destroy(array);
+}
+
+gpr_timespec CoreCodegen::gpr_inf_future(gpr_clock_type type) {
+  return ::gpr_inf_future(type);
+}
+
+void CoreCodegen::assert_fail(const char* failed_assertion) {
+  gpr_log(GPR_ERROR, "assertion failed: %s", failed_assertion);
+  abort();
+}
+
+Status CoreCodegen::SerializeProto(const grpc::protobuf::Message& msg,
+                                   grpc_byte_buffer** bp) {
+  GPR_TIMER_SCOPE("SerializeProto", 0);
+  int byte_size = msg.ByteSize();
+  if (byte_size <= kGrpcBufferWriterMaxBufferLength) {
+    gpr_slice slice = gpr_slice_malloc(byte_size);
+    GPR_ASSERT(GPR_SLICE_END_PTR(slice) ==
+               msg.SerializeWithCachedSizesToArray(GPR_SLICE_START_PTR(slice)));
+    *bp = grpc_raw_byte_buffer_create(&slice, 1);
+    gpr_slice_unref(slice);
+    return Status::OK;
+  } else {
+    GrpcBufferWriter writer(bp, kGrpcBufferWriterMaxBufferLength);
+    return msg.SerializeToZeroCopyStream(&writer)
+               ? Status::OK
+               : Status(StatusCode::INTERNAL, "Failed to serialize message");
+  }
+}
+
+Status CoreCodegen::DeserializeProto(grpc_byte_buffer* buffer,
+                                     grpc::protobuf::Message* msg,
+                                     int max_message_size) {
+  GPR_TIMER_SCOPE("DeserializeProto", 0);
+  if (buffer == nullptr) {
+    return Status(StatusCode::INTERNAL, "No payload");
+  }
+  Status result = Status::OK;
+  {
+    GrpcBufferReader reader(buffer);
+    ::grpc::protobuf::io::CodedInputStream decoder(&reader);
+    if (max_message_size > 0) {
+      decoder.SetTotalBytesLimit(max_message_size, max_message_size);
+    }
+    if (!msg->ParseFromCodedStream(&decoder)) {
+      result = Status(StatusCode::INTERNAL, msg->InitializationErrorString());
+    }
+    if (!decoder.ConsumedEntireMessage()) {
+      result = Status(StatusCode::INTERNAL, "Did not read entire message");
+    }
+  }
+  grpc_byte_buffer_destroy(buffer);
+  return result;
+}
+
+}  // namespace grpc
diff --git a/src/cpp/common/core_codegen.h b/src/cpp/common/core_codegen.h
new file mode 100644
index 0000000..e15cb4c
--- /dev/null
+++ b/src/cpp/common/core_codegen.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+// This file should be compiled as part of grpc++.
+
+#include <grpc++/impl/codegen/core_codegen_interface.h>
+#include <grpc/byte_buffer.h>
+#include <grpc/impl/codegen/grpc_types.h>
+
+namespace grpc {
+
+/// Implementation of the core codegen interface.
+class CoreCodegen : public CoreCodegenInterface {
+ private:
+  Status SerializeProto(const grpc::protobuf::Message& msg,
+                        grpc_byte_buffer** bp) override;
+
+  Status DeserializeProto(grpc_byte_buffer* buffer,
+                          grpc::protobuf::Message* msg,
+                          int max_message_size) override;
+
+  grpc_completion_queue* grpc_completion_queue_create(void* reserved) override;
+  void grpc_completion_queue_destroy(grpc_completion_queue* cq) override;
+  grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq, void* tag,
+                                         gpr_timespec deadline,
+                                         void* reserved) override;
+
+  void* gpr_malloc(size_t size) override;
+  void gpr_free(void* p) override;
+
+  void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) override;
+
+  void grpc_metadata_array_init(grpc_metadata_array* array) override;
+  void grpc_metadata_array_destroy(grpc_metadata_array* array) override;
+
+  gpr_timespec gpr_inf_future(gpr_clock_type type) override;
+
+  void assert_fail(const char* failed_assertion) override;
+};
+
+}  // namespace grpc
diff --git a/src/cpp/common/create_auth_context.h b/src/cpp/common/create_auth_context.h
index 4f3da39..c530555 100644
--- a/src/cpp/common/create_auth_context.h
+++ b/src/cpp/common/create_auth_context.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,8 +32,8 @@
  */
 #include <memory>
 
-#include <grpc/grpc.h>
 #include <grpc++/security/auth_context.h>
+#include <grpc/grpc.h>
 
 namespace grpc {
 
diff --git a/src/cpp/common/insecure_create_auth_context.cc b/src/cpp/common/insecure_create_auth_context.cc
index b2e1532..7ec5d9b 100644
--- a/src/cpp/common/insecure_create_auth_context.cc
+++ b/src/cpp/common/insecure_create_auth_context.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,8 +32,8 @@
  */
 #include <memory>
 
-#include <grpc/grpc.h>
 #include <grpc++/security/auth_context.h>
+#include <grpc/grpc.h>
 
 namespace grpc {
 
diff --git a/src/cpp/common/secure_channel_arguments.cc b/src/cpp/common/secure_channel_arguments.cc
index e17d3b5..82e02f0 100644
--- a/src/cpp/common/secure_channel_arguments.cc
+++ b/src/cpp/common/secure_channel_arguments.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,7 @@
 #include <grpc++/support/channel_arguments.h>
 
 #include <grpc/grpc_security.h>
-#include "src/core/channel/channel_args.h"
+#include "src/core/lib/channel/channel_args.h"
 
 namespace grpc {
 
diff --git a/src/cpp/common/secure_create_auth_context.cc b/src/cpp/common/secure_create_auth_context.cc
index 40bc298..d7cf803 100644
--- a/src/cpp/common/secure_create_auth_context.cc
+++ b/src/cpp/common/secure_create_auth_context.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,9 +32,9 @@
  */
 #include <memory>
 
+#include <grpc++/security/auth_context.h>
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
-#include <grpc++/security/auth_context.h>
 #include "src/cpp/common/secure_auth_context.h"
 
 namespace grpc {
diff --git a/src/cpp/proto/proto_utils.cc b/src/cpp/proto/proto_utils.cc
deleted file mode 100644
index 79e7bf1..0000000
--- a/src/cpp/proto/proto_utils.cc
+++ /dev/null
@@ -1,206 +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/proto_utils.h>
-
-#include <climits>
-
-#include <grpc/grpc.h>
-#include <grpc/byte_buffer.h>
-#include <grpc/byte_buffer_reader.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
-#include <grpc/support/port_platform.h>
-#include <grpc++/support/config.h>
-
-#include "src/core/profiling/timers.h"
-
-const int kMaxBufferLength = 8192;
-
-class GrpcBufferWriter GRPC_FINAL
-    : public ::grpc::protobuf::io::ZeroCopyOutputStream {
- public:
-  explicit GrpcBufferWriter(grpc_byte_buffer** bp,
-                            int block_size = kMaxBufferLength)
-      : block_size_(block_size), byte_count_(0), have_backup_(false) {
-    *bp = grpc_raw_byte_buffer_create(NULL, 0);
-    slice_buffer_ = &(*bp)->data.raw.slice_buffer;
-  }
-
-  ~GrpcBufferWriter() GRPC_OVERRIDE {
-    if (have_backup_) {
-      gpr_slice_unref(backup_slice_);
-    }
-  }
-
-  bool Next(void** data, int* size) GRPC_OVERRIDE {
-    if (have_backup_) {
-      slice_ = backup_slice_;
-      have_backup_ = false;
-    } else {
-      slice_ = gpr_slice_malloc(block_size_);
-    }
-    *data = GPR_SLICE_START_PTR(slice_);
-    // On win x64, int is only 32bit
-    GPR_ASSERT(GPR_SLICE_LENGTH(slice_) <= INT_MAX);
-    byte_count_ += * size = (int)GPR_SLICE_LENGTH(slice_);
-    gpr_slice_buffer_add(slice_buffer_, slice_);
-    return true;
-  }
-
-  void BackUp(int count) GRPC_OVERRIDE {
-    gpr_slice_buffer_pop(slice_buffer_);
-    if (count == block_size_) {
-      backup_slice_ = slice_;
-    } else {
-      backup_slice_ =
-          gpr_slice_split_tail(&slice_, GPR_SLICE_LENGTH(slice_) - count);
-      gpr_slice_buffer_add(slice_buffer_, slice_);
-    }
-    have_backup_ = true;
-    byte_count_ -= count;
-  }
-
-  grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE { return byte_count_; }
-
- private:
-  const int block_size_;
-  int64_t byte_count_;
-  gpr_slice_buffer* slice_buffer_;
-  bool have_backup_;
-  gpr_slice backup_slice_;
-  gpr_slice slice_;
-};
-
-class GrpcBufferReader GRPC_FINAL
-    : public ::grpc::protobuf::io::ZeroCopyInputStream {
- public:
-  explicit GrpcBufferReader(grpc_byte_buffer* buffer)
-      : byte_count_(0), backup_count_(0) {
-    grpc_byte_buffer_reader_init(&reader_, buffer);
-  }
-  ~GrpcBufferReader() GRPC_OVERRIDE {
-    grpc_byte_buffer_reader_destroy(&reader_);
-  }
-
-  bool Next(const void** data, int* size) GRPC_OVERRIDE {
-    if (backup_count_ > 0) {
-      *data = GPR_SLICE_START_PTR(slice_) + GPR_SLICE_LENGTH(slice_) -
-              backup_count_;
-      GPR_ASSERT(backup_count_ <= INT_MAX);
-      *size = (int)backup_count_;
-      backup_count_ = 0;
-      return true;
-    }
-    if (!grpc_byte_buffer_reader_next(&reader_, &slice_)) {
-      return false;
-    }
-    gpr_slice_unref(slice_);
-    *data = GPR_SLICE_START_PTR(slice_);
-    // On win x64, int is only 32bit
-    GPR_ASSERT(GPR_SLICE_LENGTH(slice_) <= INT_MAX);
-    byte_count_ += * size = (int)GPR_SLICE_LENGTH(slice_);
-    return true;
-  }
-
-  void BackUp(int count) GRPC_OVERRIDE { backup_count_ = count; }
-
-  bool Skip(int count) GRPC_OVERRIDE {
-    const void* data;
-    int size;
-    while (Next(&data, &size)) {
-      if (size >= count) {
-        BackUp(size - count);
-        return true;
-      }
-      // size < count;
-      count -= size;
-    }
-    // error or we have too large count;
-    return false;
-  }
-
-  grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE {
-    return byte_count_ - backup_count_;
-  }
-
- private:
-  int64_t byte_count_;
-  int64_t backup_count_;
-  grpc_byte_buffer_reader reader_;
-  gpr_slice slice_;
-};
-
-namespace grpc {
-
-Status SerializeProto(const grpc::protobuf::Message& msg,
-                      grpc_byte_buffer** bp) {
-  GPR_TIMER_SCOPE("SerializeProto", 0);
-  int byte_size = msg.ByteSize();
-  if (byte_size <= kMaxBufferLength) {
-    gpr_slice slice = gpr_slice_malloc(byte_size);
-    GPR_ASSERT(GPR_SLICE_END_PTR(slice) ==
-               msg.SerializeWithCachedSizesToArray(GPR_SLICE_START_PTR(slice)));
-    *bp = grpc_raw_byte_buffer_create(&slice, 1);
-    gpr_slice_unref(slice);
-    return Status::OK;
-  } else {
-    GrpcBufferWriter writer(bp);
-    return msg.SerializeToZeroCopyStream(&writer)
-               ? Status::OK
-               : Status(StatusCode::INTERNAL, "Failed to serialize message");
-  }
-}
-
-Status DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg,
-                        int max_message_size) {
-  GPR_TIMER_SCOPE("DeserializeProto", 0);
-  if (!buffer) {
-    return Status(StatusCode::INTERNAL, "No payload");
-  }
-  GrpcBufferReader reader(buffer);
-  ::grpc::protobuf::io::CodedInputStream decoder(&reader);
-  if (max_message_size > 0) {
-    decoder.SetTotalBytesLimit(max_message_size, max_message_size);
-  }
-  if (!msg->ParseFromCodedStream(&decoder)) {
-    return Status(StatusCode::INTERNAL, msg->InitializationErrorString());
-  }
-  if (!decoder.ConsumedEntireMessage()) {
-    return Status(StatusCode::INTERNAL, "Did not read entire message");
-  }
-  return Status::OK;
-}
-
-}  // namespace grpc
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index 6d31a60..7e5f557 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -49,7 +49,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
-#include "src/core/profiling/timers.h"
+#include "src/core/lib/profiling/timers.h"
 #include "src/cpp/server/thread_pool_interface.h"
 
 namespace grpc {
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 134e5f1..1947d68 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -33,10 +33,10 @@
 
 #include <grpc++/server_builder.h>
 
-#include <grpc/support/cpu.h>
-#include <grpc/support/log.h>
 #include <grpc++/impl/service_type.h>
 #include <grpc++/server.h>
+#include <grpc/support/cpu.h>
+#include <grpc/support/log.h>
 #include "src/cpp/server/thread_pool_interface.h"
 
 namespace grpc {
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index e205a19..0422650 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -42,7 +42,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
-#include "src/core/channel/compress_filter.h"
+#include "src/core/lib/channel/compress_filter.h"
+#include "src/core/lib/surface/call.h"
 #include "src/cpp/common/create_auth_context.h"
 
 namespace grpc {
@@ -62,7 +63,11 @@
   void FillOps(grpc_op* ops, size_t* nops) GRPC_OVERRIDE;
   bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE;
 
-  bool CheckCancelled(CompletionQueue* cq);
+  bool CheckCancelled(CompletionQueue* cq) {
+    cq->TryPluck(this);
+    return CheckCancelledNoPluck();
+  }
+  bool CheckCancelledAsync() { return CheckCancelledNoPluck(); }
 
   void set_tag(void* tag) {
     has_tag_ = true;
@@ -72,6 +77,11 @@
   void Unref();
 
  private:
+  bool CheckCancelledNoPluck() {
+    grpc::lock_guard<grpc::mutex> g(mu_);
+    return finalized_ ? (cancelled_ != 0) : false;
+  }
+
   bool has_tag_;
   void* tag_;
   grpc::mutex mu_;
@@ -88,12 +98,6 @@
   }
 }
 
-bool ServerContext::CompletionOp::CheckCancelled(CompletionQueue* cq) {
-  cq->TryPluck(this);
-  grpc::lock_guard<grpc::mutex> g(mu_);
-  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_;
@@ -182,12 +186,19 @@
 }
 
 bool ServerContext::IsCancelled() const {
-  return completion_op_ && completion_op_->CheckCancelled(cq_);
+  if (has_notify_when_done_tag_) {
+    // when using async API, but the result is only valid
+    // if the tag has already been delivered at the completion queue
+    return completion_op_ && completion_op_->CheckCancelledAsync();
+  } else {
+    // when using sync API
+    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);
+      grpc_call_compression_for_level(call_, level);
   set_compression_algorithm(algorithm_for_level);
 }
 
diff --git a/src/cpp/util/string_ref.cc b/src/cpp/util/string_ref.cc
index 66c79a1..b55019b 100644
--- a/src/cpp/util/string_ref.cc
+++ b/src/cpp/util/string_ref.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,72 +33,8 @@
 
 #include <grpc++/support/string_ref.h>
 
-#include <string.h>
-
-#include <algorithm>
-#include <iostream>
-
 namespace grpc {
 
 const size_t string_ref::npos = size_t(-1);
 
-string_ref& string_ref::operator=(const string_ref& rhs) {
-  data_ = rhs.data_;
-  length_ = rhs.length_;
-  return *this;
-}
-
-string_ref::string_ref(const char* s) : data_(s), length_(strlen(s)) {}
-
-string_ref string_ref::substr(size_t pos, size_t n) const {
-  if (pos > length_) pos = length_;
-  if (n > (length_ - pos)) n = length_ - pos;
-  return string_ref(data_ + pos, n);
-}
-
-int string_ref::compare(string_ref x) const {
-  size_t min_size = length_ < x.length_ ? length_ : x.length_;
-  int r = memcmp(data_, x.data_, min_size);
-  if (r < 0) return -1;
-  if (r > 0) return 1;
-  if (length_ < x.length_) return -1;
-  if (length_ > x.length_) return 1;
-  return 0;
-}
-
-bool string_ref::starts_with(string_ref x) const {
-  return length_ >= x.length_ && (memcmp(data_, x.data_, x.length_) == 0);
-}
-
-bool string_ref::ends_with(string_ref x) const {
-  return length_ >= x.length_ &&
-         (memcmp(data_ + (length_ - x.length_), x.data_, x.length_) == 0);
-}
-
-size_t string_ref::find(string_ref s) const {
-  auto it = std::search(cbegin(), cend(), s.cbegin(), s.cend());
-  return it == cend() ? npos : std::distance(cbegin(), it);
-}
-
-size_t string_ref::find(char c) const {
-  auto it = std::find(cbegin(), cend(), c);
-  return it == cend() ? npos : std::distance(cbegin(), it);
-}
-
-bool operator==(string_ref x, string_ref y) { return x.compare(y) == 0; }
-
-bool operator!=(string_ref x, string_ref y) { return x.compare(y) != 0; }
-
-bool operator<(string_ref x, string_ref y) { return x.compare(y) < 0; }
-
-bool operator<=(string_ref x, string_ref y) { return x.compare(y) <= 0; }
-
-bool operator>(string_ref x, string_ref y) { return x.compare(y) > 0; }
-
-bool operator>=(string_ref x, string_ref y) { return x.compare(y) >= 0; }
-
-std::ostream& operator<<(std::ostream& out, const string_ref& string) {
-  return out << grpc::string(string.begin(), string.end());
-}
-
 }  // namespace grpc
diff --git a/src/cpp/util/time.cc b/src/cpp/util/time.cc
index 2685e31..bb5fce3 100644
--- a/src/cpp/util/time.cc
+++ b/src/cpp/util/time.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,8 @@
 
 #ifndef GRPC_CXX0X_NO_CHRONO
 
-#include <grpc/support/time.h>
 #include <grpc++/support/time.h>
+#include <grpc/support/time.h>
 
 using std::chrono::duration_cast;
 using std::chrono::nanoseconds;
diff --git a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
index 5c5b802..d41b1b9 100644
--- a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
+++ b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs
@@ -1,6 +1,6 @@
 #region Copyright notice and license
 
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,12 +33,16 @@
 
 using System;
 using System.Collections.Generic;
+using System.Globalization;
 
 namespace Grpc.Core.Logging
 {
     /// <summary>Logger that logs to System.Console.</summary>
     public class ConsoleLogger : ILogger
     {
+        // Format similar enough to C core log format except nanosecond precision is not supported.
+        const string DateTimeFormatString = "MMdd HH:mm:ss.ffffff";
+
         readonly Type forType;
         readonly string forTypeString;
 
@@ -142,7 +146,7 @@
         {
             Console.Error.WriteLine("{0}{1} {2}{3}",
                 severityString,
-                DateTime.Now,
+                DateTime.Now.ToString(DateTimeFormatString, CultureInfo.InvariantCulture),
                 forTypeString,
                 message);
         }
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
index aa22f84..52cef96 100644
--- a/src/csharp/Grpc.Core/Metadata.cs
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -323,7 +323,7 @@
 
             private static string NormalizeKey(string key)
             {
-                var normalized = GrpcPreconditions.CheckNotNull(key, "key").ToLower(CultureInfo.InvariantCulture);
+                var normalized = GrpcPreconditions.CheckNotNull(key, "key").ToLowerInvariant();
                 GrpcPreconditions.CheckArgument(ValidKeyRegex.IsMatch(normalized), 
                     "Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores and hyphens.");
                 return normalized;
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index 04741ae..4bd4f20 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -41,11 +41,11 @@
         /// <summary>
         /// Current version of gRPC C# assemblies
         /// </summary>
-        public const string CurrentAssemblyVersion = "0.13.1.0";
+        public const string CurrentAssemblyVersion = "0.14.0.0";
 
         /// <summary>
         /// Current version of gRPC C#
         /// </summary>
-        public const string CurrentVersion = "0.13.1-pre1";
+        public const string CurrentVersion = "0.14.0-dev";
     }
 }
diff --git a/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs
index 47a1522..1edeeda 100644
--- a/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs
+++ b/src/csharp/Grpc.IntegrationTesting/BenchmarkServiceImpl.cs
@@ -1,6 +1,6 @@
 #region Copyright notice and license
 
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -46,16 +46,13 @@
     /// </summary>
     public class BenchmarkServiceImpl : BenchmarkService.IBenchmarkService
     {
-        private readonly int responseSize;
-
-        public BenchmarkServiceImpl(int responseSize)
+        public BenchmarkServiceImpl()
         {
-            this.responseSize = responseSize;
         }
 
         public Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
         {
-            var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) };
+            var response = new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) };
             return Task.FromResult(response);
         }
 
@@ -63,7 +60,7 @@
         {
             await requestStream.ForEachAsync(async request =>
             {
-                var response = new SimpleResponse { Payload = CreateZerosPayload(responseSize) };
+                var response = new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) };
                 await responseStream.WriteAsync(response);
             });
         }
diff --git a/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
index c401601..e6dc232 100644
--- a/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
@@ -41,6 +41,7 @@
 using System.Threading.Tasks;
 using Google.Protobuf;
 using Grpc.Core;
+using Grpc.Core.Logging;
 using Grpc.Core.Utils;
 using NUnit.Framework;
 using Grpc.Testing;
@@ -50,42 +51,65 @@
     /// <summary>
     /// Helper methods to start client runners for performance testing.
     /// </summary>
-    public static class ClientRunners
+    public class ClientRunners
     {
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<ClientRunners>();
+
         /// <summary>
         /// Creates a started client runner.
         /// </summary>
         public static IClientRunner CreateStarted(ClientConfig config)
         {
+            Logger.Debug("ClientConfig: {0}", config);
             string target = config.ServerTargets.Single();
-            GrpcPreconditions.CheckArgument(config.LoadParams.LoadCase == LoadParams.LoadOneofCase.ClosedLoop);
+            GrpcPreconditions.CheckArgument(config.LoadParams.LoadCase == LoadParams.LoadOneofCase.ClosedLoop,
+                "Only closed loop scenario supported for C#");
+            GrpcPreconditions.CheckArgument(config.ClientChannels == 1, "ClientConfig.ClientChannels needs to be 1");
+
+            if (config.OutstandingRpcsPerChannel != 0)
+            {
+                Logger.Warning("ClientConfig.OutstandingRpcsPerChannel is not supported for C#. Ignoring the value");
+            }
+            if (config.AsyncClientThreads != 0)
+            {
+                Logger.Warning("ClientConfig.AsyncClientThreads is not supported for C#. Ignoring the value");
+            }
+            if (config.CoreLimit != 0)
+            {
+                Logger.Warning("ClientConfig.CoreLimit is not supported for C#. Ignoring the value");
+            }
+            if (config.CoreList.Count > 0)
+            {
+                Logger.Warning("ClientConfig.CoreList is not supported for C#. Ignoring the value");
+            }
 
             var credentials = config.SecurityParams != null ? TestCredentials.CreateSslCredentials() : ChannelCredentials.Insecure;
-            var channel = new Channel(target, credentials);
-
-            switch (config.RpcType)
+            List<ChannelOption> channelOptions = null;
+            if (config.SecurityParams != null && config.SecurityParams.ServerHostOverride != "")
             {
-                case RpcType.UNARY:
-                    return new SyncUnaryClientRunner(channel,
-                        config.PayloadConfig.SimpleParams.ReqSize,
-                        config.HistogramParams);
-
-                case RpcType.STREAMING:
-                default:
-                    throw new ArgumentException("Unsupported RpcType.");
+                channelOptions = new List<ChannelOption>
+                {
+                    new ChannelOption(ChannelOptions.SslTargetNameOverride, config.SecurityParams.ServerHostOverride)
+                };
             }
+            var channel = new Channel(target, credentials, channelOptions);
+
+            return new ClientRunnerImpl(channel,
+                config.ClientType,
+                config.RpcType,
+                config.PayloadConfig,
+                config.HistogramParams);
         }
     }
 
-    /// <summary>
-    /// Client that starts synchronous unary calls in a closed loop.
-    /// </summary>
-    public class SyncUnaryClientRunner : IClientRunner
+    public class ClientRunnerImpl : IClientRunner
     {
         const double SecondsToNanos = 1e9;
 
         readonly Channel channel;
-        readonly int payloadSize;
+        readonly ClientType clientType;
+        readonly RpcType rpcType;
+        readonly PayloadConfig payloadConfig;
         readonly Histogram histogram;
 
         readonly BenchmarkService.IBenchmarkServiceClient client;
@@ -93,15 +117,19 @@
         readonly CancellationTokenSource stoppedCts;
         readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
         
-        public SyncUnaryClientRunner(Channel channel, int payloadSize, HistogramParams histogramParams)
+        public ClientRunnerImpl(Channel channel, ClientType clientType, RpcType rpcType, PayloadConfig payloadConfig, HistogramParams histogramParams)
         {
             this.channel = GrpcPreconditions.CheckNotNull(channel);
-            this.payloadSize = payloadSize;
+            this.clientType = clientType;
+            this.rpcType = rpcType;
+            this.payloadConfig = payloadConfig;
             this.histogram = new Histogram(histogramParams.Resolution, histogramParams.MaxPossible);
 
             this.stoppedCts = new CancellationTokenSource();
             this.client = BenchmarkService.NewClient(channel);
-            this.runnerTask = Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning);
+
+            var threadBody = GetThreadBody();
+            this.runnerTask = Task.Factory.StartNew(threadBody, TaskCreationOptions.LongRunning);
         }
 
         public ClientStats GetStats(bool reset)
@@ -126,12 +154,9 @@
             await channel.ShutdownAsync();
         }
 
-        private void Run()
+        private void RunClosedLoopUnary()
         {
-            var request = new SimpleRequest
-            {
-                Payload = CreateZerosPayload(payloadSize)
-            };
+            var request = CreateSimpleRequest();
             var stopwatch = new Stopwatch();
 
             while (!stoppedCts.Token.IsCancellationRequested)
@@ -145,6 +170,124 @@
             }
         }
 
+        private async Task RunClosedLoopUnaryAsync()
+        {
+            var request = CreateSimpleRequest();
+            var stopwatch = new Stopwatch();
+
+            while (!stoppedCts.Token.IsCancellationRequested)
+            {
+                stopwatch.Restart();
+                await client.UnaryCallAsync(request);
+                stopwatch.Stop();
+
+                // spec requires data point in nanoseconds.
+                histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos);
+            }
+        }
+
+        private async Task RunClosedLoopStreamingAsync()
+        {
+            var request = CreateSimpleRequest();
+            var stopwatch = new Stopwatch();
+
+            using (var call = client.StreamingCall())
+            {
+                while (!stoppedCts.Token.IsCancellationRequested)
+                {
+                    stopwatch.Restart();
+                    await call.RequestStream.WriteAsync(request);
+                    await call.ResponseStream.MoveNext();
+                    stopwatch.Stop();
+
+                    // spec requires data point in nanoseconds.
+                    histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos);
+                }
+
+                // finish the streaming call
+                await call.RequestStream.CompleteAsync();
+                Assert.IsFalse(await call.ResponseStream.MoveNext());
+            }
+        }
+
+        private async Task RunGenericClosedLoopStreamingAsync()
+        {
+            var request = CreateByteBufferRequest();
+            var stopwatch = new Stopwatch();
+
+            var callDetails = new CallInvocationDetails<byte[], byte[]>(channel, GenericService.StreamingCallMethod, new CallOptions());
+
+            using (var call = Calls.AsyncDuplexStreamingCall(callDetails))
+            {
+                while (!stoppedCts.Token.IsCancellationRequested)
+                {
+                    stopwatch.Restart();
+                    await call.RequestStream.WriteAsync(request);
+                    await call.ResponseStream.MoveNext();
+                    stopwatch.Stop();
+
+                    // spec requires data point in nanoseconds.
+                    histogram.AddObservation(stopwatch.Elapsed.TotalSeconds * SecondsToNanos);
+                }
+
+                // finish the streaming call
+                await call.RequestStream.CompleteAsync();
+                Assert.IsFalse(await call.ResponseStream.MoveNext());
+            }
+        }
+
+        private Action GetThreadBody()
+        {
+            if (payloadConfig.PayloadCase == PayloadConfig.PayloadOneofCase.BytebufParams)
+            {
+                GrpcPreconditions.CheckArgument(clientType == ClientType.ASYNC_CLIENT, "Generic client only supports async API");
+                GrpcPreconditions.CheckArgument(rpcType == RpcType.STREAMING, "Generic client only supports streaming calls");
+                return () =>
+                {
+                    RunGenericClosedLoopStreamingAsync().Wait();
+                };
+            }
+
+            GrpcPreconditions.CheckNotNull(payloadConfig.SimpleParams);
+            if (clientType == ClientType.SYNC_CLIENT)
+            {
+                GrpcPreconditions.CheckArgument(rpcType == RpcType.UNARY, "Sync client can only be used for Unary calls in C#");
+                return RunClosedLoopUnary;
+            }
+            else if (clientType == ClientType.ASYNC_CLIENT)
+            {
+                switch (rpcType)
+                {
+                    case RpcType.UNARY:
+                        return () =>
+                        {
+                            RunClosedLoopUnaryAsync().Wait();
+                        };
+                    case RpcType.STREAMING:
+                        return () =>
+                        {
+                            RunClosedLoopStreamingAsync().Wait();
+                        };
+                }
+            }
+            throw new ArgumentException("Unsupported configuration.");
+        }
+
+        private SimpleRequest CreateSimpleRequest()
+        {
+            GrpcPreconditions.CheckNotNull(payloadConfig.SimpleParams);
+            return new SimpleRequest
+            {
+                Payload = CreateZerosPayload(payloadConfig.SimpleParams.ReqSize),
+                ResponseSize = payloadConfig.SimpleParams.RespSize
+            };
+        }
+
+        private byte[] CreateByteBufferRequest()
+        {
+            return new byte[payloadConfig.BytebufParams.ReqSize];
+        }
+
         private static Payload CreateZerosPayload(int size)
         {
             return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
diff --git a/src/csharp/Grpc.IntegrationTesting/GenericService.cs b/src/csharp/Grpc.IntegrationTesting/GenericService.cs
new file mode 100644
index 0000000..c612826
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/GenericService.cs
@@ -0,0 +1,71 @@
+#region Copyright notice and license
+
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+using Grpc.Testing;
+
+namespace Grpc.IntegrationTesting
+{
+    /// <summary>
+    /// Utility methods for defining and calling a service that doesn't use protobufs
+    /// for serialization/deserialization.
+    /// </summary>
+    public static class GenericService
+    {
+        readonly static Marshaller<byte[]> ByteArrayMarshaller = new Marshaller<byte[]>((b) => b, (b) => b);
+
+        public readonly static Method<byte[], byte[]> StreamingCallMethod = new Method<byte[], byte[]>(
+            MethodType.DuplexStreaming,
+            "grpc.testing.BenchmarkService",
+            "StreamingCall",
+            ByteArrayMarshaller,
+            ByteArrayMarshaller
+        );
+
+        public static ServerServiceDefinition BindHandler(DuplexStreamingServerMethod<byte[], byte[]> handler)
+        {
+            return ServerServiceDefinition.CreateBuilder(StreamingCallMethod.ServiceName)
+                .AddMethod(StreamingCallMethod, handler).Build();
+        }
+    }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 3729913..4c04994 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -120,6 +120,7 @@
     <Compile Include="WorkerServiceImpl.cs" />
     <Compile Include="QpsWorker.cs" />
     <Compile Include="WallClockStopwatch.cs" />
+    <Compile Include="GenericService.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs
index 06d5ee9..a8cf75b 100644
--- a/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs
@@ -55,14 +55,7 @@
         {
             var serverConfig = new ServerConfig
             {
-                ServerType = ServerType.ASYNC_SERVER,
-                PayloadConfig = new PayloadConfig
-                {
-                    SimpleParams = new SimpleProtoParams
-                    {
-                        RespSize = 100
-                    }
-                }
+                ServerType = ServerType.ASYNC_SERVER
             };
             serverRunner = ServerRunners.CreateStarted(serverConfig);
         }
@@ -88,7 +81,8 @@
                 {
                     SimpleParams = new SimpleProtoParams
                     {
-                        ReqSize = 100
+                        ReqSize = 100,
+                        RespSize = 100
                     }
                 },
                 HistogramParams = new HistogramParams
diff --git a/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs b/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs
index 4a73645..c326378 100644
--- a/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs
@@ -41,6 +41,7 @@
 using System.Threading.Tasks;
 using Google.Protobuf;
 using Grpc.Core;
+using Grpc.Core.Logging;
 using Grpc.Core.Utils;
 using NUnit.Framework;
 using Grpc.Testing;
@@ -50,27 +51,78 @@
     /// <summary>
     /// Helper methods to start server runners for performance testing.
     /// </summary>
-    public static class ServerRunners
+    public class ServerRunners
     {
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<ServerRunners>();
+
         /// <summary>
         /// Creates a started server runner.
         /// </summary>
         public static IServerRunner CreateStarted(ServerConfig config)
         {
-            GrpcPreconditions.CheckArgument(config.ServerType == ServerType.ASYNC_SERVER);
+            Logger.Debug("ServerConfig: {0}", config);
             var credentials = config.SecurityParams != null ? TestCredentials.CreateSslServerCredentials() : ServerCredentials.Insecure;
 
-            // TODO: qps_driver needs to setup payload properly...
-            int responseSize = config.PayloadConfig != null ? config.PayloadConfig.SimpleParams.RespSize : 0;
+            if (config.AsyncServerThreads != 0)
+            {
+                Logger.Warning("ServerConfig.AsyncServerThreads is not supported for C#. Ignoring the value");
+            }
+            if (config.CoreLimit != 0)
+            {
+                Logger.Warning("ServerConfig.CoreLimit is not supported for C#. Ignoring the value");
+            }
+            if (config.CoreList.Count > 0)
+            {
+                Logger.Warning("ServerConfig.CoreList is not supported for C#. Ignoring the value");
+            }
+
+            ServerServiceDefinition service = null;
+            if (config.ServerType == ServerType.ASYNC_SERVER)
+            {
+                GrpcPreconditions.CheckArgument(config.PayloadConfig == null,
+                    "ServerConfig.PayloadConfig shouldn't be set for BenchmarkService based server.");    
+                service = BenchmarkService.BindService(new BenchmarkServiceImpl());
+            }
+            else if (config.ServerType == ServerType.ASYNC_GENERIC_SERVER)
+            {
+                var genericService = new GenericServiceImpl(config.PayloadConfig.BytebufParams.RespSize);
+                service = GenericService.BindHandler(genericService.StreamingCall);
+            }
+            else
+            {
+                throw new ArgumentException("Unsupported ServerType");
+            }
+
             var server = new Server
             {
-                Services = { BenchmarkService.BindService(new BenchmarkServiceImpl(responseSize)) },
+                Services = { service },
                 Ports = { new ServerPort("[::]", config.Port, credentials) }
             };
 
             server.Start();
             return new ServerRunnerImpl(server);
         }
+
+        private class GenericServiceImpl
+        {
+            readonly byte[] response;
+
+            public GenericServiceImpl(int responseSize)
+            {
+                this.response = new byte[responseSize];
+            }
+
+            /// <summary>
+            /// Generic streaming call handler.
+            /// </summary>
+            public async Task StreamingCall(IAsyncStreamReader<byte[]> requestStream, IServerStreamWriter<byte[]> responseStream, ServerCallContext context)
+            {
+                await requestStream.ForEachAsync(async request =>
+                {
+                    await responseStream.WriteAsync(response);
+                });
+            }
+        }
     }
 
     /// <summary>
@@ -119,6 +171,5 @@
         {
             return server.ShutdownAsync();
         }
-    }
-        
+    }        
 }
diff --git a/src/csharp/README.md b/src/csharp/README.md
index b4fa945..201c5ab 100644
--- a/src/csharp/README.md
+++ b/src/csharp/README.md
@@ -55,16 +55,11 @@
 
 **Windows**
 
-- The grpc_csharp_ext native library needs to be built so you can build the gRPC C# solution. You can 
-  either build the native solution in `vsprojects/grpc_csharp_ext.sln` from Visual Studio manually, or you can use
-  a convenience batch script that builds everything for you.
+- The grpc_csharp_ext native library needs to be built so you can build the gRPC C# solution. Open the
+  solution `vsprojects/grpc_csharp_ext.sln` in Visual Studio and build it.
 
-  ```
-  > REM From src/csharp directory
-  > buildall.bat
-  ```
-
-- Open Grpc.sln using Visual Studio.
+- Open `src\csharp\Grpc.sln` (path is relative to gRPC repository root)
+  using Visual Studio
 
 **Linux**
 
@@ -79,7 +74,7 @@
 **Mac OS X**
 
 - The grpc_csharp_ext native library needs to be built so you can build the gRPC C# solution.
-  
+
   ```sh
   # from the gRPC repository root
   $ tools/run_tests/run_tests.py -c dbg -l csharp --build_only
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index ea9f0a3..7c42a6d 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -1,7 +1,7 @@
 @rem Builds gRPC NuGet packages
 
 @rem Current package versions
-set VERSION=0.13.1-pre1
+set VERSION=0.14.0-dev
 set PROTOBUF_VERSION=3.0.0-beta2
 
 @rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 1df74a0..642dc9e 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/support/string.h"
+#include "src/core/lib/support/string.h"
 
 #include <grpc/byte_buffer_reader.h>
 #include <grpc/support/port_platform.h>
diff --git a/src/node/README.md b/src/node/README.md
index 3501b54..15d4c6d 100644
--- a/src/node/README.md
+++ b/src/node/README.md
@@ -7,6 +7,8 @@
 ## PREREQUISITES
 - `node`: This requires `node` to be installed, version `0.12` or above. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package.
 
+- **Note:** If you installed `node` via a package manager and the version is still less than `0.12`, try directly installing it from [nodejs.org](https://nodejs.org).
+
 ## INSTALLATION
 
 Install the gRPC NPM package
@@ -17,7 +19,21 @@
 
 ## BUILD FROM SOURCE
  1. Clone [the grpc Git Repository](https://github.com/grpc/grpc).
- 3. Run `npm install`.
+ 2. Run `npm install` from the repository root.
+
+ - **Note:** On Windows, this might fail due to [nodejs issue #4932](https://github.com/nodejs/node/issues/4932) in which case, you will see something like the following in `npm install`'s output (towards the very beginning):
+
+    ```
+     ..
+     Building the projects in this solution one at a time. To enable parallel build, please add the "/m" switch.
+     WINDOWS_BUILD_WARNING
+      "..\IMPORTANT: Due to https:\github.com\nodejs\node\issues\4932, to build this library on Windows, you must first remove C:\Users\jenkins\.node-gyp\4.4.0\include\node\openssl"
+      ...
+      ..
+    ```
+
+    To fix this, you will have to delete the folder `C:\Users\<username>\.node-gyp\<node_version>\include\node\openssl` and retry `npm install`
+
 
 ## TESTING
 To run the test suite, simply run `npm test` in the install location.
diff --git a/src/node/ext/call_credentials.cc b/src/node/ext/call_credentials.cc
index 98696db..bd2d146 100644
--- a/src/node/ext/call_credentials.cc
+++ b/src/node/ext/call_credentials.cc
@@ -35,6 +35,8 @@
 #include <nan.h>
 #include <uv.h>
 
+#include <list>
+
 #include "grpc/grpc.h"
 #include "grpc/grpc_security.h"
 #include "grpc/support/log.h"
@@ -161,6 +163,15 @@
   grpc_metadata_credentials_plugin plugin;
   plugin_state *state = new plugin_state;
   state->callback = new Nan::Callback(info[0].As<Function>());
+  state->pending_callbacks = new std::list<plugin_callback_data*>();
+  uv_mutex_init(&state->plugin_mutex);
+  uv_async_init(uv_default_loop(),
+                &state->plugin_async,
+                SendPluginCallback);
+  uv_unref((uv_handle_t*)&state->plugin_async);
+
+  state->plugin_async.data = state;
+
   plugin.get_metadata = plugin_get_metadata;
   plugin.destroy = plugin_destroy_state;
   plugin.state = reinterpret_cast<void*>(state);
@@ -208,48 +219,60 @@
 
 NAUV_WORK_CB(SendPluginCallback) {
   Nan::HandleScope scope;
-  plugin_callback_data *data = reinterpret_cast<plugin_callback_data*>(
-      async->data);
-  // Attach cb and user_data to plugin_callback so that it can access them later
-  v8::Local<v8::Function> plugin_callback = Nan::GetFunction(
-      Nan::New<v8::FunctionTemplate>(PluginCallback)).ToLocalChecked();
-  Nan::Set(plugin_callback, Nan::New("cb").ToLocalChecked(),
-           Nan::New<v8::External>(reinterpret_cast<void*>(data->cb)));
-  Nan::Set(plugin_callback, Nan::New("user_data").ToLocalChecked(),
-           Nan::New<v8::External>(data->user_data));
-  const int argc = 2;
-  v8::Local<v8::Value> argv[argc] = {
-    Nan::New(data->service_url).ToLocalChecked(),
-    plugin_callback
-  };
-  Nan::Callback *callback = data->state->callback;
-  callback->Call(argc, argv);
-  delete data;
-  uv_unref((uv_handle_t *)async);
-  uv_close((uv_handle_t *)async, (uv_close_cb)free);
+  plugin_state *state = reinterpret_cast<plugin_state*>(async->data);
+  std::list<plugin_callback_data*> callbacks;
+  uv_mutex_lock(&state->plugin_mutex);
+  callbacks.splice(callbacks.begin(), *state->pending_callbacks);
+  uv_mutex_unlock(&state->plugin_mutex);
+  while (!callbacks.empty()) {
+    plugin_callback_data *data = callbacks.front();
+    callbacks.pop_front();
+    // Attach cb and user_data to plugin_callback so that it can access them later
+    v8::Local<v8::Function> plugin_callback = Nan::GetFunction(
+        Nan::New<v8::FunctionTemplate>(PluginCallback)).ToLocalChecked();
+    Nan::Set(plugin_callback, Nan::New("cb").ToLocalChecked(),
+             Nan::New<v8::External>(reinterpret_cast<void*>(data->cb)));
+    Nan::Set(plugin_callback, Nan::New("user_data").ToLocalChecked(),
+             Nan::New<v8::External>(data->user_data));
+    const int argc = 2;
+    v8::Local<v8::Value> argv[argc] = {
+      Nan::New(data->service_url).ToLocalChecked(),
+      plugin_callback
+    };
+    Nan::Callback *callback = state->callback;
+    callback->Call(argc, argv);
+    delete data;
+  }
 }
 
 void plugin_get_metadata(void *state, grpc_auth_metadata_context context,
                          grpc_credentials_plugin_metadata_cb cb,
                          void *user_data) {
-  uv_async_t *async = static_cast<uv_async_t*>(malloc(sizeof(uv_async_t)));
-  uv_async_init(uv_default_loop(),
-                async,
-                SendPluginCallback);
+  plugin_state *p_state = reinterpret_cast<plugin_state*>(state);
   plugin_callback_data *data = new plugin_callback_data;
-  data->state = reinterpret_cast<plugin_state*>(state);
   data->service_url = context.service_url;
   data->cb = cb;
   data->user_data = user_data;
-  async->data = data;
-  /* libuv says that it will coalesce calls to uv_async_send. If there is ever a
-   * problem with a callback not getting called, that is probably the reason */
-  uv_async_send(async);
+
+  uv_mutex_lock(&p_state->plugin_mutex);
+  p_state->pending_callbacks->push_back(data);
+  uv_mutex_unlock(&p_state->plugin_mutex);
+
+  uv_async_send(&p_state->plugin_async);
+}
+
+void plugin_uv_close_cb(uv_handle_t *handle) {
+  uv_async_t *async = reinterpret_cast<uv_async_t*>(handle);
+  plugin_state *state = reinterpret_cast<plugin_state *>(async->data);
+  uv_mutex_destroy(&state->plugin_mutex);
+  delete state->pending_callbacks;
+  delete state->callback;
+  delete state;
 }
 
 void plugin_destroy_state(void *ptr) {
   plugin_state *state = reinterpret_cast<plugin_state *>(ptr);
-  delete state->callback;
+  uv_close((uv_handle_t*)&state->plugin_async, plugin_uv_close_cb);
 }
 
 }  // namespace node
diff --git a/src/node/ext/call_credentials.h b/src/node/ext/call_credentials.h
index a9bfe30..1f35595 100644
--- a/src/node/ext/call_credentials.h
+++ b/src/node/ext/call_credentials.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,8 +34,11 @@
 #ifndef GRPC_NODE_CALL_CREDENTIALS_H_
 #define GRPC_NODE_CALL_CREDENTIALS_H_
 
+#include <list>
+
 #include <node.h>
 #include <nan.h>
+#include <uv.h>
 #include "grpc/grpc_security.h"
 
 namespace grpc {
@@ -73,17 +76,20 @@
 
 /* Auth metadata plugin functionality */
 
-typedef struct plugin_state {
-  Nan::Callback *callback;
-} plugin_state;
-
 typedef struct plugin_callback_data {
-  plugin_state *state;
   const char *service_url;
   grpc_credentials_plugin_metadata_cb cb;
   void *user_data;
 } plugin_callback_data;
 
+typedef struct plugin_state {
+  Nan::Callback *callback;
+  std::list<plugin_callback_data*> *pending_callbacks;
+  uv_mutex_t plugin_mutex;
+  // async.data == this
+  uv_async_t plugin_async;
+} plugin_state;
+
 void plugin_get_metadata(void *state, grpc_auth_metadata_context context,
                          grpc_credentials_plugin_metadata_cb cb,
                          void *user_data);
diff --git a/src/node/index.js b/src/node/index.js
index 1c19772..6567d56 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -87,6 +87,10 @@
  *   Buffers. Defaults to false
  * - longsAsStrings: deserialize long values as strings instead of objects.
  *   Defaults to true
+ * - deprecatedArgumentOrder: Use the beta method argument order for client
+ *   methods, with optional arguments after the callback. Defaults to false.
+ *   This option is only a temporary stopgap measure to smooth an API breakage.
+ *   It is deprecated, and new code should not use it.
  * @param {string|{root: string, file: string}} filename The file to load
  * @param {string=} format The file format to expect. Must be either 'proto' or
  *     'json'. Defaults to 'proto'
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index 5602011..ac0eddc 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -286,7 +286,7 @@
 function timeoutOnSleepingServer(client, done) {
   var deadline = new Date();
   deadline.setMilliseconds(deadline.getMilliseconds() + 1);
-  var call = client.fullDuplexCall(null, {deadline: deadline});
+  var call = client.fullDuplexCall({deadline: deadline});
   call.write({
     payload: {body: zeroBuffer(27182)}
   });
@@ -316,10 +316,10 @@
       body: zeroBuffer(271828)
     }
   };
-  var unary = client.unaryCall(arg, function(err, resp) {
+  var unary = client.unaryCall(arg, metadata, function(err, resp) {
     assert.ifError(err);
     done();
-  }, metadata);
+  });
   unary.on('metadata', function(metadata) {
     assert.deepEqual(metadata.get(ECHO_INITIAL_KEY),
                      ['test_initial_metadata_value']);
@@ -455,14 +455,14 @@
       credential = credential.createScoped(scope);
     }
     var creds = grpc.credentials.createFromGoogleCredential(credential);
-    client.unaryCall(arg, function(err, resp) {
+    client.unaryCall(arg, {credentials: creds}, function(err, resp) {
       assert.ifError(err);
       assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL);
       assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1);
       if (done) {
         done();
       }
-    }, null, {credentials: creds});
+    });
   });
 }
 
diff --git a/src/node/performance/benchmark_client.js b/src/node/performance/benchmark_client.js
index 620aecd..80bec0b 100644
--- a/src/node/performance/benchmark_client.js
+++ b/src/node/performance/benchmark_client.js
@@ -45,6 +45,9 @@
 var _ = require('lodash');
 var PoissonProcess = require('poisson-process');
 var Histogram = require('./histogram');
+
+var genericService = require('./generic_service');
+
 var grpc = require('../../../');
 var serviceProto = grpc.load({
   root: __dirname + '/../../..',
@@ -104,10 +107,14 @@
   }
 
   this.clients = [];
+  var GenericClient = grpc.makeGenericClientConstructor(genericService);
+  this.genericClients = [];
 
   for (var i = 0; i < channels; i++) {
     this.clients[i] = new serviceProto.BenchmarkService(
         server_targets[i % server_targets.length], creds, options);
+    this.genericClients[i] = new GenericClient(
+        server_targets[i % server_targets.length], creds, options);
   }
 
   this.histogram = new Histogram(histogram_params.resolution,
@@ -130,9 +137,11 @@
  *     'STREAMING'
  * @param {number} req_size The size of the payload to send with each request
  * @param {number} resp_size The size of payload to request be sent in responses
+ * @param {boolean} generic Indicates that the generic (non-proto) clients
+ *     should be used
  */
 BenchmarkClient.prototype.startClosedLoop = function(
-    outstanding_rpcs_per_channel, rpc_type, req_size, resp_size) {
+    outstanding_rpcs_per_channel, rpc_type, req_size, resp_size, generic) {
   var self = this;
 
   self.running = true;
@@ -141,12 +150,20 @@
 
   var makeCall;
 
-  var argument = {
-    response_size: resp_size,
-    payload: {
-      body: zeroBuffer(req_size)
-    }
-  };
+  var argument;
+  var client_list;
+  if (generic) {
+    argument = zeroBuffer(req_size);
+    client_list = self.genericClients;
+  } else {
+    argument = {
+      response_size: resp_size,
+      payload: {
+        body: zeroBuffer(req_size)
+      }
+    };
+    client_list = self.clients;
+  }
 
   if (rpc_type == 'UNARY') {
     makeCall = function(client) {
@@ -195,7 +212,7 @@
     };
   }
 
-  _.each(self.clients, function(client) {
+  _.each(client_list, function(client) {
     _.times(outstanding_rpcs_per_channel, function() {
       makeCall(client);
     });
@@ -213,9 +230,12 @@
  * @param {number} req_size The size of the payload to send with each request
  * @param {number} resp_size The size of payload to request be sent in responses
  * @param {number} offered_load The load parameter for the Poisson process
+ * @param {boolean} generic Indicates that the generic (non-proto) clients
+ *     should be used
  */
 BenchmarkClient.prototype.startPoisson = function(
-    outstanding_rpcs_per_channel, rpc_type, req_size, resp_size, offered_load) {
+    outstanding_rpcs_per_channel, rpc_type, req_size, resp_size, offered_load,
+    generic) {
   var self = this;
 
   self.running = true;
@@ -224,12 +244,20 @@
 
   var makeCall;
 
-  var argument = {
-    response_size: resp_size,
-    payload: {
-      body: zeroBuffer(req_size)
-    }
-  };
+  var argument;
+  var client_list;
+  if (generic) {
+    argument = zeroBuffer(req_size);
+    client_list = self.genericClients;
+  } else {
+    argument = {
+      response_size: resp_size,
+      payload: {
+        body: zeroBuffer(req_size)
+      }
+    };
+    client_list = self.clients;
+  }
 
   if (rpc_type == 'UNARY') {
     makeCall = function(client, poisson) {
@@ -282,7 +310,7 @@
 
   var averageIntervalMs = (1 / offered_load) * 1000;
 
-  _.each(self.clients, function(client) {
+  _.each(client_list, function(client) {
     _.times(outstanding_rpcs_per_channel, function() {
       var p = PoissonProcess.create(averageIntervalMs, function() {
         makeCall(client, p);
diff --git a/src/node/performance/benchmark_server.js b/src/node/performance/benchmark_server.js
index e48acd4..b1b0bd1 100644
--- a/src/node/performance/benchmark_server.js
+++ b/src/node/performance/benchmark_server.js
@@ -41,6 +41,8 @@
 var fs = require('fs');
 var path = require('path');
 
+var genericService = require('./generic_service');
+
 var grpc = require('../../../');
 var serviceProto = grpc.load({
   root: __dirname + '/../../..',
@@ -84,14 +86,28 @@
   });
 }
 
+function makeStreamingGenericCall(response_size) {
+  var response = zeroBuffer(response_size);
+  return function streamingGenericCall(call) {
+    call.on('data', function(value) {
+      call.write(response);
+    });
+    call.on('end', function() {
+      call.end();
+    });
+  };
+}
+
 /**
  * BenchmarkServer class. Constructed based on parameters from the driver and
  * stores statistics.
  * @param {string} host The host to serve on
  * @param {number} port The port to listen to
- * @param {tls} Indicates whether TLS should be used
+ * @param {boolean} tls Indicates whether TLS should be used
+ * @param {boolean} generic Indicates whether to use the generic service
+ * @param {number=} response_size The response size for the generic service
  */
-function BenchmarkServer(host, port, tls) {
+function BenchmarkServer(host, port, tls, generic, response_size) {
   var server_creds;
   var host_override;
   if (tls) {
@@ -109,10 +125,16 @@
 
   var server = new grpc.Server();
   this.port = server.bind(host + ':' + port, server_creds);
-  server.addProtoService(serviceProto.BenchmarkService.service, {
-    unaryCall: unaryCall,
-    streamingCall: streamingCall
-  });
+  if (generic) {
+    server.addService(genericService, {
+      streamingCall: makeStreamingGenericCall(response_size)
+    });
+  } else {
+    server.addProtoService(serviceProto.BenchmarkService.service, {
+      unaryCall: unaryCall,
+      streamingCall: streamingCall
+    });
+  }
   this.server = server;
 }
 
diff --git a/src/node/performance/generic_service.js b/src/node/performance/generic_service.js
new file mode 100644
index 0000000..ce09cc4
--- /dev/null
+++ b/src/node/performance/generic_service.js
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+var _ = require('lodash');
+
+module.exports = {
+  'streamingCall' : {
+    path: '/grpc.testing/BenchmarkService',
+    requestStream: true,
+    responseStream: true,
+    requestSerialize: _.identity,
+    requestDeserialize: _.identity,
+    responseSerialize: _.identity,
+    responseDeserialize: _.identity
+  }
+};
diff --git a/src/node/performance/worker_service_impl.js b/src/node/performance/worker_service_impl.js
index 1439249..2c46513 100644
--- a/src/node/performance/worker_service_impl.js
+++ b/src/node/performance/worker_service_impl.js
@@ -56,18 +56,31 @@
       client.on('error', function(error) {
         call.emit('error', error);
       });
+      var req_size, resp_size, generic;
+      switch (setup.payload_config.payload) {
+        case 'bytebuf_params':
+        req_size = setup.payload_config.bytebuf_params.req_size;
+        resp_size = setup.payload_config.bytebuf_params.resp_size;
+        generic = true;
+        break;
+        case 'simple_params':
+        req_size = setup.payload_config.simple_params.req_size;
+        resp_size = setup.payload_config.simple_params.resp_size;
+        generic = false;
+        break;
+        default:
+        call.emit('error', new Error('Unsupported PayloadConfig type' +
+            setup.payload_config.payload));
+      }
       switch (setup.load_params.load) {
         case 'closed_loop':
         client.startClosedLoop(setup.outstanding_rpcs_per_channel,
-                               setup.rpc_type,
-                               setup.payload_config.simple_params.req_size,
-                               setup.payload_config.simple_params.resp_size);
+                               setup.rpc_type, req_size, resp_size, generic);
         break;
         case 'poisson':
         client.startPoisson(setup.outstanding_rpcs_per_channel,
-                            setup.rpc_type, setup.payload_config.req_size,
-                            setup.payload_config.resp_size,
-                            setup.load_params.poisson.offered_load);
+                            setup.rpc_type, req_size, resp_size,
+                            setup.load_params.poisson.offered_load, generic);
         break;
         default:
         call.emit('error', new Error('Unsupported LoadParams type' +
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 9cc5a62..8214237 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -50,6 +50,7 @@
 'use strict';
 
 var _ = require('lodash');
+var arguejs = require('arguejs');
 
 var grpc = require('./grpc_extension');
 
@@ -149,6 +150,9 @@
   if (!status) {
     status = {code: grpc.status.OK, details: 'OK'};
   }
+  if (status.code !== grpc.status.OK) {
+    this.call.cancelWithStatus(status.code, status.details);
+  }
   this.finished = true;
   this.read_status = status;
   this._emitStatusIfDone();
@@ -350,21 +354,23 @@
    * @this {Client} Client object. Must have a channel member.
    * @param {*} argument The argument to the call. Should be serializable with
    *     serialize
-   * @param {function(?Error, value=)} callback The callback to for when the
-   *     response is received
    * @param {Metadata=} metadata Metadata to add to the call
    * @param {Object=} options Options map
+   * @param {function(?Error, value=)} callback The callback to for when the
+   *     response is received
    * @return {EventEmitter} An event emitter for stream related events
    */
-  function makeUnaryRequest(argument, callback, metadata, options) {
+  function makeUnaryRequest(argument, metadata, options, callback) {
     /* jshint validthis: true */
+    /* While the arguments are listed in the function signature, those variables
+     * are not used directly. Instead, ArgueJS processes the arguments
+     * object. This allows for simple handling of optional arguments in the
+     * middle of the argument list, and also provides type checking. */
+    var args = arguejs({argument: null, metadata: [Metadata, new Metadata()],
+                        options: [Object], callback: Function}, arguments);
     var emitter = new EventEmitter();
-    var call = getCall(this.$channel, method, options);
-    if (metadata === null || metadata === undefined) {
-      metadata = new Metadata();
-    } else {
-      metadata = metadata.clone();
-    }
+    var call = getCall(this.$channel, method, args.options);
+    metadata = args.metadata.clone();
     emitter.cancel = function cancel() {
       call.cancel();
     };
@@ -372,9 +378,9 @@
       return call.getPeer();
     };
     var client_batch = {};
-    var message = serialize(argument);
-    if (options) {
-      message.grpcWriteFlags = options.flags;
+    var message = serialize(args.argument);
+    if (args.options) {
+      message.grpcWriteFlags = args.options.flags;
     }
     client_batch[grpc.opType.SEND_INITIAL_METADATA] =
         metadata._getCoreRepresentation();
@@ -392,7 +398,7 @@
       if (status.code === grpc.status.OK) {
         if (err) {
           // Got a batch error, but OK status. Something went wrong
-          callback(err);
+          args.callback(err);
           return;
         } else {
           try {
@@ -411,9 +417,9 @@
         error = new Error(status.details);
         error.code = status.code;
         error.metadata = status.metadata;
-        callback(error);
+        args.callback(error);
       } else {
-        callback(null, deserialized);
+        args.callback(null, deserialized);
       }
       emitter.emit('status', status);
       emitter.emit('metadata', Metadata._fromCoreRepresentation(
@@ -437,21 +443,23 @@
    * Make a client stream request with this method on the given channel with the
    * given callback, etc.
    * @this {Client} Client object. Must have a channel member.
-   * @param {function(?Error, value=)} callback The callback to for when the
-   *     response is received
    * @param {Metadata=} metadata Array of metadata key/value pairs to add to the
    *     call
    * @param {Object=} options Options map
+   * @param {function(?Error, value=)} callback The callback to for when the
+   *     response is received
    * @return {EventEmitter} An event emitter for stream related events
    */
-  function makeClientStreamRequest(callback, metadata, options) {
+  function makeClientStreamRequest(metadata, options, callback) {
     /* jshint validthis: true */
-    var call = getCall(this.$channel, method, options);
-    if (metadata === null || metadata === undefined) {
-      metadata = new Metadata();
-    } else {
-      metadata = metadata.clone();
-    }
+    /* While the arguments are listed in the function signature, those variables
+     * are not used directly. Instead, ArgueJS processes the arguments
+     * object. This allows for simple handling of optional arguments in the
+     * middle of the argument list, and also provides type checking. */
+    var args = arguejs({metadata: [Metadata, new Metadata()],
+                        options: [Object], callback: Function}, arguments);
+    var call = getCall(this.$channel, method, args.options);
+    metadata = args.metadata.clone();
     var stream = new ClientWritableStream(call, serialize);
     var metadata_batch = {};
     metadata_batch[grpc.opType.SEND_INITIAL_METADATA] =
@@ -478,7 +486,7 @@
       if (status.code === grpc.status.OK) {
         if (err) {
           // Got a batch error, but OK status. Something went wrong
-          callback(err);
+          args.callback(err);
           return;
         } else {
           try {
@@ -497,9 +505,9 @@
         error = new Error(response.status.details);
         error.code = status.code;
         error.metadata = status.metadata;
-        callback(error);
+        args.callback(error);
       } else {
-        callback(null, deserialized);
+        args.callback(null, deserialized);
       }
       stream.emit('status', status);
     });
@@ -530,17 +538,18 @@
    */
   function makeServerStreamRequest(argument, metadata, options) {
     /* jshint validthis: true */
-    var call = getCall(this.$channel, method, options);
-    if (metadata === null || metadata === undefined) {
-      metadata = new Metadata();
-    } else {
-      metadata = metadata.clone();
-    }
+    /* While the arguments are listed in the function signature, those variables
+     * are not used directly. Instead, ArgueJS processes the arguments
+     * object. */
+    var args = arguejs({argument: null, metadata: [Metadata, new Metadata()],
+                        options: [Object]}, arguments);
+    var call = getCall(this.$channel, method, args.options);
+    metadata = args.metadata.clone();
     var stream = new ClientReadableStream(call, deserialize);
     var start_batch = {};
-    var message = serialize(argument);
-    if (options) {
-      message.grpcWriteFlags = options.flags;
+    var message = serialize(args.argument);
+    if (args.options) {
+      message.grpcWriteFlags = args.options.flags;
     }
     start_batch[grpc.opType.SEND_INITIAL_METADATA] =
         metadata._getCoreRepresentation();
@@ -592,12 +601,13 @@
    */
   function makeBidiStreamRequest(metadata, options) {
     /* jshint validthis: true */
-    var call = getCall(this.$channel, method, options);
-    if (metadata === null || metadata === undefined) {
-      metadata = new Metadata();
-    } else {
-      metadata = metadata.clone();
-    }
+    /* While the arguments are listed in the function signature, those variables
+     * are not used directly. Instead, ArgueJS processes the arguments
+     * object. */
+    var args = arguejs({metadata: [Metadata, new Metadata()],
+                        options: [Object]}, arguments);
+    var call = getCall(this.$channel, method, args.options);
+    metadata = args.metadata.clone();
     var stream = new ClientDuplexStream(call, serialize, deserialize);
     var start_batch = {};
     start_batch[grpc.opType.SEND_INITIAL_METADATA] =
@@ -640,6 +650,40 @@
   bidi: makeBidiStreamRequestFunction
 };
 
+function getDefaultValues(metadata, options) {
+  var res = {};
+  res.metadata = metadata || new Metadata();
+  res.options = options || {};
+  return res;
+}
+
+/**
+ * Map with wrappers for each type of requester function to make it use the old
+ * argument order with optional arguments after the callback.
+ */
+var deprecated_request_wrap = {
+  unary: function(makeUnaryRequest) {
+    return function makeWrappedUnaryRequest(argument, callback,
+                                            metadata, options) {
+      /* jshint validthis: true */
+      var opt_args = getDefaultValues(metadata, metadata);
+      return makeUnaryRequest.call(this, argument, opt_args.metadata,
+                                   opt_args.options, callback);
+    };
+  },
+  client_stream: function(makeServerStreamRequest) {
+    return function makeWrappedClientStreamRequest(callback, metadata,
+                                                   options) {
+      /* jshint validthis: true */
+      var opt_args = getDefaultValues(metadata, options);
+      return makeServerStreamRequest.call(this, opt_args.metadata,
+                                          opt_args.options, callback);
+    };
+  },
+  server_stream: _.identity,
+  bidi: _.identity
+};
+
 /**
  * Creates a constructor for a client with the given methods. The methods object
  * maps method name to an object with the following keys:
@@ -651,9 +695,19 @@
  * responseDeserialize: function to deserialize response objects
  * @param {Object} methods An object mapping method names to method attributes
  * @param {string} serviceName The fully qualified name of the service
+ * @param {Object} class_options An options object. Currently only uses the key
+ *     deprecatedArgumentOrder, a boolean that Indicates that the old argument
+ *     order should be used for methods, with optional arguments at the end
+ *     instead of the callback at the end. Defaults to false. This option is
+ *     only a temporary stopgap measure to smooth an API breakage.
+ *     It is deprecated, and new code should not use it.
  * @return {function(string, Object)} New client constructor
  */
-exports.makeClientConstructor = function(methods, serviceName) {
+exports.makeClientConstructor = function(methods, serviceName,
+                                         class_options) {
+  if (!class_options) {
+    class_options = {};
+  }
   /**
    * Create a client with the given methods
    * @constructor
@@ -700,8 +754,13 @@
     }
     var serialize = attrs.requestSerialize;
     var deserialize = attrs.responseDeserialize;
-    Client.prototype[name] = requester_makers[method_type](
+    var method_func = requester_makers[method_type](
         attrs.path, serialize, deserialize);
+    if (class_options.deprecatedArgumentOrder) {
+      Client.prototype[name] = deprecated_request_wrap(method_func);
+    } else {
+      Client.prototype[name] = method_func;
+    }
     // Associate all provided attributes with the method
     _.assign(Client.prototype[name], attrs);
   });
@@ -758,8 +817,13 @@
 exports.makeProtobufClientConstructor =  function(service, options) {
   var method_attrs = common.getProtobufServiceAttrs(service, service.name,
                                                     options);
+  var deprecatedArgumentOrder = false;
+  if (options) {
+    deprecatedArgumentOrder = options.deprecatedArgumentOrder;
+  }
   var Client = exports.makeClientConstructor(
-      method_attrs, common.fullyQualifiedName(service));
+      method_attrs, common.fullyQualifiedName(service),
+      deprecatedArgumentOrder);
   Client.service = service;
   Client.service.grpc_options = options;
   return Client;
diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js
index 1d73723..97c4bd7 100644
--- a/src/node/src/credentials.js
+++ b/src/node/src/credentials.js
@@ -118,7 +118,6 @@
 exports.createFromGoogleCredential = function(google_credential) {
   return exports.createFromMetadataGenerator(function(auth_context, callback) {
     var service_url = auth_context.service_url;
-    console.log('Service URL:', service_url);
     google_credential.getRequestMetadata(service_url, function(err, header) {
       if (err) {
         console.log('Auth error:', err);
@@ -127,7 +126,6 @@
       }
       var metadata = new Metadata();
       metadata.add('authorization', header.Authorization);
-      console.log(header.Authorization);
       callback(null, metadata);
     });
   });
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 0cf7ba3..dd0bc12 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -339,7 +339,7 @@
     try {
       deserialized = self.deserialize(data);
     } catch (e) {
-      e.code = grpc.status.INVALID_ARGUMENT;
+      e.code = grpc.status.INTERNAL;
       self.emit('error', e);
       return;
     }
@@ -475,7 +475,7 @@
     try {
       emitter.request = handler.deserialize(result.read);
     } catch (e) {
-      e.code = grpc.status.INVALID_ARGUMENT;
+      e.code = grpc.status.INTERNAL;
       handleError(call, e);
       return;
     }
@@ -516,7 +516,7 @@
     try {
       stream.request = handler.deserialize(result.read);
     } catch (e) {
-      e.code = grpc.status.INVALID_ARGUMENT;
+      e.code = grpc.status.INTERNAL;
       stream.emit('error', e);
       return;
     }
diff --git a/src/node/test/credentials_test.js b/src/node/test/credentials_test.js
index 294600c..73eadfa 100644
--- a/src/node/test/credentials_test.js
+++ b/src/node/test/credentials_test.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -398,18 +398,20 @@
           metadataUpdater);
     });
     it('Should update metadata on a unary call', function(done) {
-      var call = client.unary({}, function(err, data) {
-        assert.ifError(err);
-      }, null, {credentials: updater_creds});
+      var call = client.unary({}, {credentials: updater_creds},
+                              function(err, data) {
+                                assert.ifError(err);
+                              });
       call.on('metadata', function(metadata) {
         assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
         done();
       });
     });
     it('should update metadata on a client streaming call', function(done) {
-      var call = client.clientStream(function(err, data) {
-        assert.ifError(err);
-      }, null, {credentials: updater_creds});
+      var call = client.clientStream({credentials: updater_creds},
+                                     function(err, data) {
+                                       assert.ifError(err);
+                                     });
       call.on('metadata', function(metadata) {
         assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
         done();
@@ -417,7 +419,7 @@
       call.end();
     });
     it('should update metadata on a server streaming call', function(done) {
-      var call = client.serverStream({}, null, {credentials: updater_creds});
+      var call = client.serverStream({}, {credentials: updater_creds});
       call.on('data', function() {});
       call.on('metadata', function(metadata) {
         assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
@@ -425,7 +427,7 @@
       });
     });
     it('should update metadata on a bidi streaming call', function(done) {
-      var call = client.bidiStream(null, {credentials: updater_creds});
+      var call = client.bidiStream({credentials: updater_creds});
       call.on('data', function() {});
       call.on('metadata', function(metadata) {
         assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
@@ -443,9 +445,10 @@
           altMetadataUpdater);
       var combined_updater = grpc.credentials.combineCallCredentials(
           updater_creds, alt_updater_creds);
-      var call = client.unary({}, function(err, data) {
-        assert.ifError(err);
-      }, null, {credentials: combined_updater});
+      var call = client.unary({}, {credentials: combined_updater},
+                              function(err, data) {
+                                assert.ifError(err);
+                              });
       call.on('metadata', function(metadata) {
         assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
         assert.deepEqual(metadata.get('other_plugin_key'),
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 8a232d6..5a704ee 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -404,18 +404,18 @@
     server.forceShutdown();
   });
   it('with unary call', function(done) {
-    var call = client.unary({}, function(err, data) {
+    var call = client.unary({}, metadata, function(err, data) {
       assert.ifError(err);
-    }, metadata);
+    });
     call.on('metadata', function(metadata) {
       assert.deepEqual(metadata.get('key'), ['value']);
       done();
     });
   });
   it('with client stream call', function(done) {
-    var call = client.clientStream(function(err, data) {
+    var call = client.clientStream(metadata, function(err, data) {
       assert.ifError(err);
-    }, metadata);
+    });
     call.on('metadata', function(metadata) {
       assert.deepEqual(metadata.get('key'), ['value']);
       done();
@@ -441,8 +441,8 @@
   });
   it('shows the correct user-agent string', function(done) {
     var version = require('../../../package.json').version;
-    var call = client.unary({}, function(err, data) { assert.ifError(err); },
-                            metadata);
+    var call = client.unary({}, metadata,
+                            function(err, data) { assert.ifError(err); });
     call.on('metadata', function(metadata) {
       assert(_.startsWith(metadata.get('user-agent')[0],
                           'grpc-node/' + version));
@@ -452,8 +452,8 @@
   it('properly handles duplicate values', function(done) {
     var dup_metadata = metadata.clone();
     dup_metadata.add('key', 'value2');
-    var call = client.unary({}, function(err, data) {assert.ifError(err); },
-                            dup_metadata);
+    var call = client.unary({}, dup_metadata,
+                            function(err, data) {assert.ifError(err); });
     call.on('metadata', function(resp_metadata) {
       // Two arrays are equal iff their symmetric difference is empty
       assert.deepEqual(_.xor(dup_metadata.get('key'), resp_metadata.get('key')),
@@ -709,14 +709,14 @@
     it('should respond correctly to a unary call', function(done) {
       misbehavingClient.unary(badArg, function(err, data) {
         assert(err);
-        assert.strictEqual(err.code, grpc.status.INVALID_ARGUMENT);
+        assert.strictEqual(err.code, grpc.status.INTERNAL);
         done();
       });
     });
     it('should respond correctly to a client stream', function(done) {
       var call = misbehavingClient.clientStream(function(err, data) {
         assert(err);
-        assert.strictEqual(err.code, grpc.status.INVALID_ARGUMENT);
+        assert.strictEqual(err.code, grpc.status.INTERNAL);
         done();
       });
       call.write(badArg);
@@ -729,7 +729,7 @@
         assert.fail(data, null, 'Unexpected data', '===');
       });
       call.on('error', function(err) {
-        assert.strictEqual(err.code, grpc.status.INVALID_ARGUMENT);
+        assert.strictEqual(err.code, grpc.status.INTERNAL);
         done();
       });
     });
@@ -739,7 +739,7 @@
         assert.fail(data, null, 'Unexpected data', '===');
       });
       call.on('error', function(err) {
-        assert.strictEqual(err.code, grpc.status.INVALID_ARGUMENT);
+        assert.strictEqual(err.code, grpc.status.INTERNAL);
         done();
       });
       call.write(badArg);
@@ -954,7 +954,7 @@
       done = multiDone(done, 2);
       var call;
       proxy_impl.unary = function(parent, callback) {
-        client.unary(parent.request, function(err, value) {
+        client.unary(parent.request, {parent: parent}, function(err, value) {
           try {
             assert(err);
             assert.strictEqual(err.code, grpc.status.CANCELLED);
@@ -962,7 +962,7 @@
             callback(err, value);
             done();
           }
-        }, null, {parent: parent});
+        });
         call.cancel();
       };
       proxy.addProtoService(test_service, proxy_impl);
@@ -976,7 +976,7 @@
       done = multiDone(done, 2);
       var call;
       proxy_impl.clientStream = function(parent, callback) {
-        client.clientStream(function(err, value) {
+        client.clientStream({parent: parent}, function(err, value) {
           try {
             assert(err);
             assert.strictEqual(err.code, grpc.status.CANCELLED);
@@ -984,7 +984,7 @@
             callback(err, value);
             done();
           }
-        }, null, {parent: parent});
+        });
         call.cancel();
       };
       proxy.addProtoService(test_service, proxy_impl);
@@ -998,8 +998,7 @@
       done = multiDone(done, 2);
       var call;
       proxy_impl.serverStream = function(parent) {
-        var child = client.serverStream(parent.request, null,
-                                        {parent: parent});
+        var child = client.serverStream(parent.request, {parent: parent});
         child.on('data', function() {});
         child.on('error', function(err) {
           assert(err);
@@ -1023,7 +1022,7 @@
       done = multiDone(done, 2);
       var call;
       proxy_impl.bidiStream = function(parent) {
-        var child = client.bidiStream(null, {parent: parent});
+        var child = client.bidiStream({parent: parent});
         child.on('data', function() {});
         child.on('error', function(err) {
           assert(err);
@@ -1051,7 +1050,8 @@
     it('With a client stream call', function(done) {
       done = multiDone(done, 2);
       proxy_impl.clientStream = function(parent, callback) {
-        client.clientStream(function(err, value) {
+        var options = {parent: parent, propagate_flags: deadline_flags};
+        client.clientStream(options, function(err, value) {
           try {
             assert(err);
             assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
@@ -1060,7 +1060,7 @@
             callback(err, value);
             done();
           }
-        }, null, {parent: parent, propagate_flags: deadline_flags});
+        });
       };
       proxy.addProtoService(test_service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
@@ -1069,15 +1069,15 @@
                                     grpc.credentials.createInsecure());
       var deadline = new Date();
       deadline.setSeconds(deadline.getSeconds() + 1);
-      proxy_client.clientStream(function(err, value) {
+      proxy_client.clientStream({deadline: deadline}, function(err, value) {
         done();
-      }, null, {deadline: deadline});
+      });
     });
     it('With a bidi stream call', function(done) {
       done = multiDone(done, 2);
       proxy_impl.bidiStream = function(parent) {
         var child = client.bidiStream(
-            null, {parent: parent, propagate_flags: deadline_flags});
+            {parent: parent, propagate_flags: deadline_flags});
         child.on('data', function() {});
         child.on('error', function(err) {
           assert(err);
@@ -1093,7 +1093,7 @@
                                     grpc.credentials.createInsecure());
       var deadline = new Date();
       deadline.setSeconds(deadline.getSeconds() + 1);
-      var call = proxy_client.bidiStream(null, {deadline: deadline});
+      var call = proxy_client.bidiStream({deadline: deadline});
       call.on('data', function() {});
       call.on('error', function(err) {
         done();
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index f79b7d0..51263b0 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,8 @@
 #include <grpc/support/time.h>
 #import <RxLibrary/GRXConcurrentWriteable.h>
 
+#import "private/GRPCConnectivityMonitor.h"
+#import "private/GRPCHost.h"
 #import "private/GRPCRequestHeaders.h"
 #import "private/GRPCWrappedCall.h"
 #import "private/NSData+GRPC.h"
@@ -71,8 +73,11 @@
 @implementation GRPCCall {
   dispatch_queue_t _callQueue;
 
+  NSString *_host;
+  NSString *_path;
   GRPCWrappedCall *_wrappedCall;
   dispatch_once_t _callAlreadyInvoked;
+  GRPCConnectivityMonitor *_connectivityMonitor;
 
   // The C gRPC library has less guarantees on the ordering of events than we
   // do. Particularly, in the face of errors, there's no ordering guarantee at
@@ -115,13 +120,11 @@
                 format:@"The requests writer can't be already started."];
   }
   if ((self = [super init])) {
-    _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:host path:path];
-    if (!_wrappedCall) {
-      return nil;
-    }
+    _host = [host copy];
+    _path = [path copy];
 
     // Serial queue to invoke the non-reentrant methods of the grpc_call object.
-    _callQueue = dispatch_queue_create("org.grpc.call", NULL);
+    _callQueue = dispatch_queue_create("io.grpc.call", NULL);
 
     _requestWriter = requestWriter;
 
@@ -156,7 +159,7 @@
 - (void)cancel {
   [self finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
                                             code:GRPCErrorCodeCancelled
-                                        userInfo:nil]];
+                                        userInfo:@{NSLocalizedDescriptionKey: @"Canceled by app"}]];
   [self cancelCall];
 }
 
@@ -305,37 +308,30 @@
 }
 
 - (void)invokeCall {
-  __weak GRPCCall *weakSelf = self;
   [self invokeCallWithHeadersHandler:^(NSDictionary *headers) {
     // Response headers received.
-    GRPCCall *strongSelf = weakSelf;
-    if (strongSelf) {
-      strongSelf.responseHeaders = headers;
-      [strongSelf startNextRead];
-    }
+    self.responseHeaders = headers;
+    [self startNextRead];
   } completionHandler:^(NSError *error, NSDictionary *trailers) {
-    GRPCCall *strongSelf = weakSelf;
-    if (strongSelf) {
-      strongSelf.responseTrailers = trailers;
+    self.responseTrailers = trailers;
 
-      if (error) {
-        NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
-        if (error.userInfo) {
-          [userInfo addEntriesFromDictionary:error.userInfo];
-        }
-        userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers;
-        // TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be
-        // called before this one, so an error might end up with trailers but no headers. We
-        // shouldn't call finishWithError until ater both blocks are called. It is also when this is
-        // done that we can provide a merged view of response headers and trailers in a thread-safe
-        // way.
-        if (strongSelf.responseHeaders) {
-          userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders;
-        }
-        error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
+    if (error) {
+      NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
+      if (error.userInfo) {
+        [userInfo addEntriesFromDictionary:error.userInfo];
       }
-      [strongSelf finishWithError:error];
+      userInfo[kGRPCTrailersKey] = self.responseTrailers;
+      // TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be
+      // called before this one, so an error might end up with trailers but no headers. We
+      // shouldn't call finishWithError until ater both blocks are called. It is also when this is
+      // done that we can provide a merged view of response headers and trailers in a thread-safe
+      // way.
+      if (self.responseHeaders) {
+        userInfo[kGRPCHeadersKey] = self.responseHeaders;
+      }
+      error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
     }
+    [self finishWithError:error];
   }];
   // Now that the RPC has been initiated, request writes can start.
   @synchronized(_requestWriter) {
@@ -354,8 +350,28 @@
   _retainSelf = self;
 
   _responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable];
+
+  _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path];
+  NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?");
+
   [self sendHeaders:_requestHeaders];
   [self invokeCall];
+  // TODO(jcanizales): Extract this logic somewhere common.
+  NSString *host = [NSURL URLWithString:[@"https://" stringByAppendingString:_host]].host;
+  if (!host) {
+    // TODO(jcanizales): Check this on init.
+    [NSException raise:NSInvalidArgumentException format:@"host of %@ is nil", _host];
+  }
+  __weak typeof(self) weakSelf = self;
+  _connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host];
+  [_connectivityMonitor handleLossWithHandler:^{
+    typeof(self) strongSelf = weakSelf;
+    if (strongSelf) {
+      [strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
+                                                      code:GRPCErrorCodeUnavailable
+                                                  userInfo:@{NSLocalizedDescriptionKey: @"Connectivity lost."}]];
+    }
+  }];
 }
 
 - (void)setState:(GRXWriterState)newState {
@@ -385,4 +401,5 @@
       return;
   }
 }
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h
index 8661ae6..e49a6ac 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.h
@@ -35,6 +35,7 @@
 
 #include <grpc/grpc.h>
 
+@class GRPCCompletionQueue;
 struct grpc_channel_credentials;
 
 
@@ -80,4 +81,6 @@
 + (nonnull GRPCChannel *)insecureChannelWithHost:(nonnull NSString *)host
                                      channelArgs:(nullable NSDictionary *)channelArgs;
 
+- (nullable grpc_call *)unmanagedCallWithPath:(nonnull NSString *)path
+                              completionQueue:(nonnull GRPCCompletionQueue *)queue;
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index 7e55a47..d7de025 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -38,6 +38,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#import "GRPCCompletionQueue.h"
+
 /**
  * Returns @c grpc_channel_credentials from the specified @c path. If the file at the path could not
  * be read then NULL is returned. If NULL is returned, @c errorPtr may not be NULL if there are
@@ -205,4 +207,16 @@
                                channelArgs:channelArgs];
 }
 
+- (grpc_call *)unmanagedCallWithPath:(NSString *)path
+                     completionQueue:(GRPCCompletionQueue *)queue {
+  return grpc_channel_create_call(_unmanagedChannel,
+                                  NULL, GRPC_PROPAGATE_DEFAULTS,
+                                  queue.unmanagedQueue,
+                                  path.UTF8String,
+                                  // Get "host" from "host:port"
+                                  // TODO(jcanizales): Use NSURLs throughout, to clarify these.
+                                  [_host componentsSeparatedByString:@":"][0].UTF8String,
+                                  gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+}
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
index ff30316..d89602f 100644
--- a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
+++ b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
@@ -38,7 +38,12 @@
 @implementation GRPCCompletionQueue
 
 + (instancetype)completionQueue {
-  return [[self alloc] init];
+  static GRPCCompletionQueue *singleton = nil;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    singleton = [[self alloc] init];
+  });
+  return singleton;
 }
 
 - (instancetype)init {
diff --git a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
new file mode 100644
index 0000000..2fae410
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import <SystemConfiguration/SystemConfiguration.h>
+
+@interface GRPCReachabilityFlags : NSObject
+
++ (nonnull instancetype)flagsWithFlags:(SCNetworkReachabilityFlags)flags;
+
+/**
+ * One accessor method to query each of the different flags. Example:
+
+@property(nonatomic, readonly) BOOL isCell;
+
+ */
+#define GRPC_XMACRO_ITEM(methodName, FlagName) \
+@property(nonatomic, readonly) BOOL methodName;
+
+#include "GRPCReachabilityFlagNames.xmacro.h"
+#undef GRPC_XMACRO_ITEM
+
+@property(nonatomic, readonly) BOOL isHostReachable;
+@end
+
+
+@interface GRPCConnectivityMonitor : NSObject
+
++ (nullable instancetype)monitorWithHost:(nonnull NSString *)hostName;
+
+- (nonnull instancetype)init NS_UNAVAILABLE;
+
+/**
+ * Queue on which callbacks will be dispatched. Default is the main queue. Set it before calling
+ * handleLossWithHandler:.
+ */
+// TODO(jcanizales): Default to a serial background queue instead.
+@property(nonatomic, strong, null_resettable) dispatch_queue_t queue;
+
+/**
+ * Calls handler every time the connectivity to this instance's host is lost. If this instance is
+ * released before that happens, the handler won't be called.
+ * Only one handler is active at a time, so if this method is called again before the previous
+ * handler has been called, it might never be called at all (or yes, if it has already been queued).
+ */
+- (void)handleLossWithHandler:(nonnull void (^)())handler;
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
new file mode 100644
index 0000000..b4061bd
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
@@ -0,0 +1,192 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import "GRPCConnectivityMonitor.h"
+
+#pragma mark Flags
+
+@implementation GRPCReachabilityFlags {
+  SCNetworkReachabilityFlags _flags;
+}
+
++ (instancetype)flagsWithFlags:(SCNetworkReachabilityFlags)flags {
+  return [[self alloc] initWithFlags:flags];
+}
+
+- (instancetype)initWithFlags:(SCNetworkReachabilityFlags)flags {
+  if ((self = [super init])) {
+    _flags = flags;
+  }
+  return self;
+}
+
+/*
+ * One accessor method implementation per flag. Example:
+
+- (BOOL)isCell { \
+  return !!(_flags & kSCNetworkReachabilityFlagsIsWWAN); \
+}
+
+ */
+#define GRPC_XMACRO_ITEM(methodName, FlagName) \
+- (BOOL)methodName { \
+  return !!(_flags & kSCNetworkReachabilityFlags ## FlagName); \
+}
+#include "GRPCReachabilityFlagNames.xmacro.h"
+#undef GRPC_XMACRO_ITEM
+
+- (BOOL)isHostReachable {
+  // Note: connectionOnDemand means it'll be reachable only if using the CFSocketStream API or APIs
+  // on top of it.
+  // connectionRequired means we can't tell until a connection is attempted (e.g. for VPN on
+  // demand).
+  return self.reachable && !self.interventionRequired && !self.connectionOnDemand;
+}
+
+- (NSString *)description {
+  NSMutableArray *activeOptions = [NSMutableArray arrayWithCapacity:9];
+
+  /*
+   * For each flag, add its name to the array if it's ON. Example:
+
+  if (self.isCell) {
+    [activeOptions addObject:@"isCell"];
+  }
+
+   */
+#define GRPC_XMACRO_ITEM(methodName, FlagName) \
+  if (self.methodName) { \
+    [activeOptions addObject:@#methodName]; \
+  }
+#include "GRPCReachabilityFlagNames.xmacro.h"
+#undef GRPC_XMACRO_ITEM
+
+  return activeOptions.count == 0 ? @"(none)" : [activeOptions componentsJoinedByString:@", "];
+}
+
+- (BOOL)isEqual:(id)object {
+  return [object isKindOfClass:[GRPCReachabilityFlags class]] &&
+      _flags == ((GRPCReachabilityFlags *)object)->_flags;
+}
+
+- (NSUInteger)hash {
+  return _flags;
+}
+@end
+
+#pragma mark Connectivity Monitor
+
+// Assumes the third argument is a block that accepts a GRPCReachabilityFlags object, and passes the
+// received ones to it.
+static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
+                                        SCNetworkReachabilityFlags flags,
+                                        void *info) {
+  #pragma unused (target)
+  // This can be called many times with the same info. The info is retained by SCNetworkReachability
+  // while this function is being executed.
+  void (^handler)(GRPCReachabilityFlags *) = (__bridge void (^)(GRPCReachabilityFlags *))info;
+  handler([[GRPCReachabilityFlags alloc] initWithFlags:flags]);
+}
+
+@implementation GRPCConnectivityMonitor {
+  SCNetworkReachabilityRef _reachabilityRef;
+}
+
+- (nullable instancetype)initWithReachability:(nullable SCNetworkReachabilityRef)reachability {
+  if (!reachability) {
+    return nil;
+  }
+  if ((self = [super init])) {
+    _reachabilityRef = CFRetain(reachability);
+    _queue = dispatch_get_main_queue();
+  }
+  return self;
+}
+
++ (nullable instancetype)monitorWithHost:(nonnull NSString *)host {
+  const char *hostName = host.UTF8String;
+  if (!hostName) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"host.UTF8String returns NULL for %@", host];
+  }
+  SCNetworkReachabilityRef reachability =
+      SCNetworkReachabilityCreateWithName(NULL, hostName);
+
+  GRPCConnectivityMonitor *returnValue = [[self alloc] initWithReachability:reachability];
+  if (reachability) {
+    CFRelease(reachability);
+  }
+  return returnValue;
+}
+
+- (void)handleLossWithHandler:(void (^)())handler {
+  [self startListeningWithHandler:^(GRPCReachabilityFlags *flags) {
+    if (!flags.isHostReachable) {
+      handler();
+    }
+  }];
+}
+
+- (void)startListeningWithHandler:(void (^)(GRPCReachabilityFlags *))handler {
+  // Copy to ensure the handler block is in the heap (and so can't be deallocated when this method
+  // returns).
+  void (^copiedHandler)(GRPCReachabilityFlags *) = [handler copy];
+  SCNetworkReachabilityContext context = {
+    .version = 0,
+    .info = (__bridge void *)copiedHandler,
+    .retain = CFRetain,
+    .release = CFRelease,
+  };
+  // The following will retain context.info, and release it when the callback is set to NULL.
+  SCNetworkReachabilitySetCallback(_reachabilityRef, PassFlagsToContextInfoBlock, &context);
+  SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, _queue);
+}
+
+- (void)stopListening {
+  // This releases the block on context.info.
+  SCNetworkReachabilitySetCallback(_reachabilityRef, NULL, NULL);
+  SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, NULL);
+}
+
+- (void)setQueue:(dispatch_queue_t)queue {
+  _queue = queue ?: dispatch_get_main_queue();
+}
+
+- (void)dealloc {
+  if (_reachabilityRef) {
+    [self stopListening];
+    CFRelease(_reachabilityRef);
+  }
+}
+
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h
index 82c0ad6..987d3e9 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.h
+++ b/src/objective-c/GRPCClient/private/GRPCHost.h
@@ -33,27 +33,39 @@
 
 #import <Foundation/Foundation.h>
 
+NS_ASSUME_NONNULL_BEGIN
+
 @class GRPCCompletionQueue;
 struct grpc_call;
 
 @interface GRPCHost : NSObject
 
 @property(nonatomic, readonly) NSString *address;
-@property(nonatomic, copy) NSString *userAgentPrefix;
+@property(nonatomic, copy, nullable) NSString *userAgentPrefix;
 
 /** The following properties should only be modified for testing: */
 
 @property(nonatomic, getter=isSecure) BOOL secure;
 
-@property(nonatomic, copy) NSString *pathToCertificates;
-@property(nonatomic, copy) NSString *hostNameOverride;
+@property(nonatomic, copy, nullable) NSString *pathToCertificates;
+@property(nonatomic, copy, nullable) NSString *hostNameOverride;
 
+- (nullable instancetype)init NS_UNAVAILABLE;
 /** Host objects initialized with the same address are the same. */
-+ (instancetype)hostWithAddress:(NSString *)address;
-- (instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER;
++ (nullable instancetype)hostWithAddress:(NSString *)address;
+- (nullable instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER;
 
 /** Create a grpc_call object to the provided path on this host. */
-- (struct grpc_call *)unmanagedCallWithPath:(NSString *)path
-                            completionQueue:(GRPCCompletionQueue *)queue;
+- (nullable struct grpc_call *)unmanagedCallWithPath:(NSString *)path
+                                     completionQueue:(GRPCCompletionQueue *)queue;
 
+// TODO: There's a race when a new RPC is coming through just as an existing one is getting
+// notified that there's no connectivity. If connectivity comes back at that moment, the new RPC
+// will have its channel destroyed by the other RPC, and will never get notified of a problem, so
+// it'll hang (the C layer logs a timeout, with exponential back off). One solution could be to pass
+// the GRPCChannel to the GRPCCall, renaming this as "disconnectChannel:channel", which would only
+// act on that specific channel.
+- (void)disconnect;
 @end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index eb1db89..508cb20 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -34,33 +34,30 @@
 #import "GRPCHost.h"
 
 #include <grpc/grpc.h>
+#import <GRPCClient/GRPCCall.h>
 #import <GRPCClient/GRPCCall+ChannelArg.h>
 
 #import "GRPCChannel.h"
 #import "GRPCCompletionQueue.h"
 #import "NSDictionary+GRPC.h"
 
+NS_ASSUME_NONNULL_BEGIN
+
 // TODO(jcanizales): Generate the version in a standalone header, from templates. Like
 // templates/src/core/surface/version.c.template .
 #define GRPC_OBJC_VERSION_STRING @"0.13.0"
 
-@interface GRPCHost ()
-// TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
-@property(nonatomic, strong) GRPCChannel *channel;
-@end
+@implementation GRPCHost {
+  // TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
+  GRPCChannel *_channel;
+}
 
-@implementation GRPCHost
-
-+ (instancetype)hostWithAddress:(NSString *)address {
++ (nullable instancetype)hostWithAddress:(NSString *)address {
   return [[self alloc] initWithAddress:address];
 }
 
-- (instancetype)init {
-  return [self initWithAddress:nil];
-}
-
 // Default initializer.
-- (instancetype)initWithAddress:(NSString *)address {
+- (nullable instancetype)initWithAddress:(NSString *)address {
   if (!address) {
     return nil;
   }
@@ -95,46 +92,45 @@
   return self;
 }
 
-- (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue {
-  if (!queue || !path || !self.channel) {
-    return NULL;
+- (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path
+                              completionQueue:(GRPCCompletionQueue *)queue {
+  GRPCChannel *channel;
+  // This is racing -[GRPCHost disconnect].
+  @synchronized(self) {
+    if (!_channel) {
+      _channel = [self newChannel];
+    }
+    channel = _channel;
   }
-  return grpc_channel_create_call(self.channel.unmanagedChannel,
-                                  NULL, GRPC_PROPAGATE_DEFAULTS,
-                                  queue.unmanagedQueue,
-                                  path.UTF8String,
-                                  self.hostName.UTF8String,
-                                  gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+  return [channel unmanagedCallWithPath:path completionQueue:queue];
 }
 
-- (GRPCChannel *)channel {
-  // Create it lazily, because we don't want to open a connection just because someone is
-  // configuring a host.
+- (NSDictionary *)channelArgs {
+  NSMutableDictionary *args = [NSMutableDictionary dictionary];
 
-  if (!_channel) {
-    NSMutableDictionary *args = [NSMutableDictionary dictionary];
-
-    // TODO(jcanizales): Add OS and device information (see
-    // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#user-agents ).
-    NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING;
-    if (_userAgentPrefix) {
-      userAgent = [@[_userAgentPrefix, userAgent] componentsJoinedByString:@" "];
-    }
-    args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent;
-
-    if (_secure) {
-      if (_hostNameOverride) {
-        args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
-      }
-
-      _channel = [GRPCChannel secureChannelWithHost:_address
-                                 pathToCertificates:_pathToCertificates
-                                        channelArgs:args];
-    } else {
-      _channel = [GRPCChannel insecureChannelWithHost:_address channelArgs:args];
-    }
+  // TODO(jcanizales): Add OS and device information (see
+  // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#user-agents ).
+  NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING;
+  if (_userAgentPrefix) {
+    userAgent = [_userAgentPrefix stringByAppendingFormat:@" %@", userAgent];
   }
-  return _channel;
+  args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent;
+
+  if (_secure && _hostNameOverride) {
+    args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
+  }
+  return args;
+}
+
+- (GRPCChannel *)newChannel {
+  NSDictionary *args = [self channelArgs];
+  if (_secure) {
+    return [GRPCChannel secureChannelWithHost:_address
+                           pathToCertificates:_pathToCertificates
+                                  channelArgs:args];
+  } else {
+    return [GRPCChannel insecureChannelWithHost:_address channelArgs:args];
+  }
 }
 
 - (NSString *)hostName {
@@ -142,7 +138,16 @@
   return _hostNameOverride ?: _address;
 }
 
+- (void)disconnect {
+  // This is racing -[GRPCHost unmanagedCallWithPath:completionQueue:].
+  @synchronized(self) {
+    _channel = nil;
+  }
+}
+
 // TODO(jcanizales): Don't let set |secure| to |NO| if |pathToCertificates| or |hostNameOverride|
 // have been set. Don't let set either of the latter if |secure| has been set to |NO|.
 
 @end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h b/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
new file mode 100644
index 0000000..4b92504
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**
+ * "X-macro" file that lists the flags names of Apple's Network Reachability API, along with a nice
+ * Objective-C method name used to query each of them.
+ *
+ * Example usage: To generate a dictionary from flag value to name, one can do:
+
+  NSDictionary *flagNames = @{
+#define GRPC_XMACRO_ITEM(methodName, FlagName) \
+    @(kSCNetworkReachabilityFlags ## FlagName): @#methodName,
+#include "GRXReachabilityFlagNames.xmacro.h"
+#undef GRPC_XMACRO_ITEM
+  };
+
+  XCTAssertEqualObjects(flagNames[@(kSCNetworkReachabilityFlagsIsWWAN)], @"isCell");
+
+ */
+
+#ifndef GRPC_XMACRO_ITEM
+#error This file is to be used with the "X-macro" pattern: Please #define \
+       GRPC_XMACRO_ITEM(methodName, FlagName), then #include this file, and then #undef \
+       GRPC_XMACRO_ITEM.
+#endif
+
+#if TARGET_OS_IPHONE
+GRPC_XMACRO_ITEM(isCell, IsWWAN)
+#endif
+GRPC_XMACRO_ITEM(reachable, Reachable)
+GRPC_XMACRO_ITEM(transientConnection, TransientConnection)
+GRPC_XMACRO_ITEM(connectionRequired, ConnectionRequired)
+GRPC_XMACRO_ITEM(connectionOnTraffic, ConnectionOnTraffic)
+GRPC_XMACRO_ITEM(interventionRequired, InterventionRequired)
+GRPC_XMACRO_ITEM(connectionOnDemand, ConnectionOnDemand)
+GRPC_XMACRO_ITEM(isLocalAddress, IsLocalAddress)
+GRPC_XMACRO_ITEM(isDirect, IsDirect)
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
index 71e7e0e..e37ed1b 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
@@ -34,7 +34,6 @@
 #import <Foundation/Foundation.h>
 #include <grpc/grpc.h>
 
-#import "GRPCChannel.h"
 #import "GRPCRequestHeaders.h"
 
 @interface GRPCOperation : NSObject
@@ -94,4 +93,5 @@
 - (void)startBatchWithOperations:(NSArray *)ops;
 
 - (void)cancel;
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
index fe3d51d..f6527e2 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,7 +54,9 @@
 
 - (void)finish {
   if (_handler) {
-    _handler();
+    void(^handler)() = _handler;
+    _handler = nil;
+    handler();
   }
 }
 @end
diff --git a/src/objective-c/RxLibrary/GRXWriteable.m b/src/objective-c/RxLibrary/GRXWriteable.m
index 2729d62..028ba9b 100644
--- a/src/objective-c/RxLibrary/GRXWriteable.m
+++ b/src/objective-c/RxLibrary/GRXWriteable.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,11 +42,42 @@
   if (!handler) {
     return [[self alloc] init];
   }
-  return [[self alloc] initWithValueHandler:^(id value) {
-    handler(value, nil);
-  } completionHandler:^(NSError *errorOrNil) {
-    if (errorOrNil) {
-      handler(nil, errorOrNil);
+  // We nilify this variable when the block is invoked, so that handler is only invoked once even if
+  // the writer tries to write multiple values.
+  __block GRXEventHandler eventHandler = ^(BOOL done, id value, NSError *error) {
+    // Nillify eventHandler before invoking handler, in case the latter causes the former to be
+    // executed recursively. Because blocks can be deallocated even during execution, we have to
+    // first retain handler locally to guarantee it's valid.
+    // TODO(jcanizales): Just turn this craziness into a simple subclass of GRXWriteable.
+    GRXSingleHandler singleHandler = handler;
+    eventHandler = nil;
+
+    if (value) {
+      singleHandler(value, nil);
+    } else if (error) {
+      singleHandler(nil, error);
+    } else {
+      NSDictionary *userInfo = @{
+        NSLocalizedDescriptionKey: @"The writer finished without producing any value."
+      };
+      // Even though RxLibrary is independent of gRPC, the domain and code here are, for the moment,
+      // set to the values of kGRPCErrorDomain and GRPCErrorCodeInternal. This way, the error formed
+      // is the one user of gRPC would expect if the server failed to produce a response.
+      //
+      // TODO(jcanizales): Figure out a way to keep errors of RxLibrary generic without making users
+      // of gRPC take care of two different error domains and error code enums. A possibility is to
+      // add error handling to GRXWriters or GRXWriteables, and use them to translate errors between
+      // the two domains.
+      static NSString *kGRPCErrorDomain = @"io.grpc";
+      static NSUInteger kGRPCErrorCodeInternal = 13;
+      singleHandler(nil, [NSError errorWithDomain:kGRPCErrorDomain
+                                             code:kGRPCErrorCodeInternal
+                                         userInfo:userInfo]);
+    }
+  };
+  return [self writeableWithEventHandler:^(BOOL done, id value, NSError *error) {
+    if (eventHandler) {
+      eventHandler(done, value, error);
     }
   }];
 }
diff --git a/src/objective-c/tests/RxLibraryUnitTests.m b/src/objective-c/tests/RxLibraryUnitTests.m
index d342662..ae9465f 100644
--- a/src/objective-c/tests/RxLibraryUnitTests.m
+++ b/src/objective-c/tests/RxLibraryUnitTests.m
@@ -64,6 +64,8 @@
 }
 @end
 
+// TODO(jcanizales): Split into one file per tested class.
+
 @interface RxLibraryUnitTests : XCTestCase
 @end
 
@@ -79,6 +81,7 @@
   // If:
   id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block];
   [writeable writeValue:anyValue];
+  [writeable writesFinishedWithError:nil];
 
   // Then:
   XCTAssertEqual(handler.timesCalled, 1);
@@ -101,6 +104,54 @@
   XCTAssertEqualObjects(handler.errorOrNil, anyError);
 }
 
+- (void)testWriteableSingleHandlerIsCalledOnlyOnce_ValueThenError {
+  // Given:
+  CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler];
+  id anyValue = @7;
+  NSError *anyError = [NSError errorWithDomain:@"domain" code:7 userInfo:nil];
+
+  // If:
+  id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block];
+  [writeable writeValue:anyValue];
+  [writeable writesFinishedWithError:anyError];
+
+  // Then:
+  XCTAssertEqual(handler.timesCalled, 1);
+  XCTAssertEqualObjects(handler.value, anyValue);
+  XCTAssertEqualObjects(handler.errorOrNil, nil);
+}
+
+- (void)testWriteableSingleHandlerIsCalledOnlyOnce_ValueThenValue {
+  // Given:
+  CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler];
+  id anyValue = @7;
+
+  // If:
+  id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block];
+  [writeable writeValue:anyValue];
+  [writeable writeValue:anyValue];
+  [writeable writesFinishedWithError:nil];
+
+  // Then:
+  XCTAssertEqual(handler.timesCalled, 1);
+  XCTAssertEqualObjects(handler.value, anyValue);
+  XCTAssertEqualObjects(handler.errorOrNil, nil);
+}
+
+- (void)testWriteableSingleHandlerFailsOnEmptyWriter {
+  // Given:
+  CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler];
+
+  // If:
+  id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block];
+  [writeable writesFinishedWithError:nil];
+
+  // Then:
+  XCTAssertEqual(handler.timesCalled, 1);
+  XCTAssertEqualObjects(handler.value, nil);
+  XCTAssertNotNil(handler.errorOrNil);
+}
+
 #pragma mark BufferedPipe
 
 - (void)testBufferedPipePropagatesValue {
diff --git a/src/php/composer.json b/src/php/composer.json
index 59f846f..01674a2 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -2,7 +2,7 @@
   "name": "grpc/grpc",
   "type": "library",
   "description": "gRPC library for PHP",
-  "version": "0.13.0",
+  "version": "0.14.0",
   "keywords": ["rpc"],
   "homepage": "http://grpc.io",
   "license": "BSD-3-Clause",
diff --git a/src/php/ext/grpc/README.md b/src/php/ext/grpc/README.md
deleted file mode 100644
index 6e1cb20..0000000
--- a/src/php/ext/grpc/README.md
+++ /dev/null
@@ -1,67 +0,0 @@
-gRPC PHP Extension
-==================
-
-# Requirements
-
- * PHP 5.5+
- * [gRPC core library](https://github.com/grpc/grpc) 0.11.0
-
-# Installation
-
-## Install PHP 5
-
-```
-$ sudo apt-get install git php5 php5-dev php-pear unzip
-```
-
-## Compile gRPC Core Library
-
-Clone the gRPC source code repository
-
-```
-$ git clone https://github.com/grpc/grpc.git
-```
-
-Build and install the gRPC C core libraries
-
-```sh
-$ cd grpc
-$ git checkout --track origin/release-0_11
-$ git pull --recurse-submodules && git submodule update --init --recursive
-$ make
-$ sudo make install
-```
-
-Note: you may encounter a warning about the Protobuf compiler `protoc` 3.0.0+ not being installed. The following might help, and will be useful later on when we need to compile the `protoc-gen-php` tool.
-
-```sh
-$ cd grpc/third_party/protobuf
-$ sudo make install   # 'make' should have been run by core grpc
-```
-
-## Install the gRPC PHP extension
-
-Quick install
-
-```sh
-$ sudo pecl install grpc
-```
-
-Note: before a stable release, you may need to do
-
-```sh
-$ sudo pecl install grpc-beta
-```
-
-OR
-
-Compile from source
-
-```sh
-$ # from grpc
-$ cd src/php/ext/grpc
-$ phpize
-$ ./configure
-$ make
-$ sudo make install
-```
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index f0bc734..b7e7c26 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -110,9 +110,11 @@
     switch (Z_TYPE_P(*data)) {
       case IS_LONG:
         args->args[args_index].value.integer = (int)Z_LVAL_P(*data);
+        args->args[args_index].type = GRPC_ARG_INTEGER;
         break;
       case IS_STRING:
         args->args[args_index].value.string = Z_STRVAL_P(*data);
+        args->args[args_index].type = GRPC_ARG_STRING;
         break;
       default:
         zend_throw_exception(spl_ce_InvalidArgumentException,
diff --git a/src/php/tests/generated_code/math_client.php b/src/php/tests/generated_code/math_client.php
index 76ccabc..2085560 100644
--- a/src/php/tests/generated_code/math_client.php
+++ b/src/php/tests/generated_code/math_client.php
@@ -1,7 +1,7 @@
 <?php
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,9 @@
 
 $host = 'localhost:50051';
 p("Connecting to host: $host");
-$client = new math\MathClient($host, []);
+$client = new math\MathClient($host, [
+    'credentials' => Grpc\ChannelCredentials::createInsecure()
+]);
 p('Client class: '.get_class($client));
 p('');
 
diff --git a/src/proto/grpc/testing/echo_messages.proto b/src/proto/grpc/testing/echo_messages.proto
index d05a355..5ce0a1f 100644
--- a/src/proto/grpc/testing/echo_messages.proto
+++ b/src/proto/grpc/testing/echo_messages.proto
@@ -42,6 +42,7 @@
   bool echo_peer = 7;
   string expected_client_identity = 8; // will force check_auth_context.
   bool skip_cancelled_check = 9;
+  string expected_transport_security_type = 10;
 }
 
 message EchoRequest {
diff --git a/src/proto/grpc/testing/metrics.proto b/src/proto/grpc/testing/metrics.proto
index 4485d3a..df719af 100644
--- a/src/proto/grpc/testing/metrics.proto
+++ b/src/proto/grpc/testing/metrics.proto
@@ -1,5 +1,4 @@
-
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -28,12 +27,17 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// An integration test service that covers all the method signature permutations
-// of unary/streaming requests/responses.
+// Contains the definitions for a metrics service and the type of metrics
+// exposed by the service.
+//
+// Currently, 'Gauge' (i.e a metric that represents the measured value of
+// something at an instant of time) is the only metric type supported by the
+// service.
 syntax = "proto3";
 
 package grpc.testing;
 
+// Reponse message containing the gauge name and value
 message GaugeResponse {
   string name = 1;
   oneof value {
@@ -43,11 +47,18 @@
   }
 }
 
-message GaugeRequest { string name = 1; }
+// Request message containing the gauge name
+message GaugeRequest {
+  string name = 1;
+}
 
 message EmptyMessage {}
 
 service MetricsService {
+  // Returns the values of all the gauges that are currently being maintained by
+  // the service
   rpc GetAllGauges(EmptyMessage) returns (stream GaugeResponse);
+
+  // Returns the value of one gauge
   rpc GetGauge(GaugeRequest) returns (GaugeResponse);
 }
diff --git a/src/python/grpcio/README.rst b/src/python/grpcio/README.rst
index 3dfae50..33a462b 100644
--- a/src/python/grpcio/README.rst
+++ b/src/python/grpcio/README.rst
@@ -35,13 +35,14 @@
 
 ::
 
-  $ export REPO_ROOT=grpc
+  $ export REPO_ROOT=grpc  # REPO_ROOT can be any directory of your choice
   $ git clone https://github.com/grpc/grpc.git $REPO_ROOT
   $ cd $REPO_ROOT
-  $ pip install .
 
-Note that :code:`$REPO_ROOT` can be assigned to whatever directory name floats
-your fancy.
+  # For the next two commands do `sudo pip install` if you get permission-denied errors
+  $ pip install -rrequirements.txt
+  $ GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install .
+
 
 Troubleshooting
 ~~~~~~~~~~~~~~~
@@ -49,10 +50,43 @@
 Help, I ...
 
 * **... see a** :code:`pkg_resources.VersionConflict` **when I try to install
-  grpc!**
+  grpc**
 
   This is likely because :code:`pip` doesn't own the offending dependency,
   which in turn is likely because your operating system's package manager owns
   it. You'll need to force the installation of the dependency:
 
   :code:`pip install --ignore-installed $OFFENDING_DEPENDENCY`
+
+  For example, if you get an error like the following:
+
+  ::
+
+    Traceback (most recent call last):
+    File "<string>", line 17, in <module>
+     ...
+    File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 509, in find
+      raise VersionConflict(dist, req)
+    pkg_resources.VersionConflict: (six 1.8.0 (/usr/lib/python2.7/dist-packages), Requirement.parse('six>=1.10'))
+
+  You can fix it by doing:
+
+  ::
+
+    sudo pip install --ignore-installed six
+
+* **... see the following error on some platforms**
+
+  ::
+
+    /tmp/pip-build-U8pSsr/cython/Cython/Plex/Scanners.c:4:20: fatal error: Python.h: No such file or directory
+    #include "Python.h"
+                    ^
+    compilation terminated.
+
+  You can fix it by installing `python-dev` package. i.e
+
+  ::
+
+    sudo apt-get install python-dev
+
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index c1f444f..1d43547 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -288,15 +288,9 @@
       sys.exit('Test failure')
 
   def _add_eggs_to_path(self):
-    """Adds all egg files under .eggs to sys.path"""
-    # TODO(jtattemusch): there has to be a cleaner way to do this
-    import pkg_resources
-    eggs_dir = os.path.join(PYTHON_STEM, '../../../.eggs')
-    eggs = [os.path.join(eggs_dir, filename)
-            for filename in os.listdir(eggs_dir)
-            if filename.endswith('.egg')]
-    for egg in eggs:
-      sys.path.insert(0, pkg_resources.normalize_path(egg))
+    """Fetch install and test requirements"""
+    self.distribution.fetch_build_eggs(self.distribution.install_requires)
+    self.distribution.fetch_build_eggs(self.distribution.tests_require)
 
 
 class RunInterop(test.test):
diff --git a/src/python/grpcio/grpc/_adapter/_types.py b/src/python/grpcio/grpc/_adapter/_types.py
index 3d5ab33..f9e18f0 100644
--- a/src/python/grpcio/grpc/_adapter/_types.py
+++ b/src/python/grpcio/grpc/_adapter/_types.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
 import collections
 import enum
 
+import six
+
 from grpc._cython import cygrpc
 
 
@@ -247,8 +249,7 @@
   """
 
 
-class CompletionQueue:
-  __metaclass__ = abc.ABCMeta
+class CompletionQueue(six.with_metaclass(abc.ABCMeta)):
 
   @abc.abstractmethod
   def __init__(self):
@@ -262,6 +263,9 @@
     """
     return self
 
+  def __next__(self):
+    return self.next()
+
   @abc.abstractmethod
   def next(self, deadline=float('+inf')):
     """Get the next event on this completion queue.
@@ -285,8 +289,7 @@
     return None
 
 
-class Call:
-  __metaclass__ = abc.ABCMeta
+class Call(six.with_metaclass(abc.ABCMeta)):
 
   @abc.abstractmethod
   def start_batch(self, ops, tag):
@@ -334,8 +337,7 @@
     return None
 
 
-class Channel:
-  __metaclass__ = abc.ABCMeta
+class Channel(six.with_metaclass(abc.ABCMeta)):
 
   @abc.abstractmethod
   def __init__(self, target, args, credentials=None):
@@ -399,8 +401,7 @@
     return None
 
 
-class Server:
-  __metaclass__ = abc.ABCMeta
+class Server(six.with_metaclass(abc.ABCMeta)):
 
   @abc.abstractmethod
   def __init__(self, completion_queue, args):
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
index 80f4da5..d1b9c98 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -40,14 +40,17 @@
   def start_batch(self, operations, tag):
     if not self.is_valid:
       raise ValueError("invalid call object cannot be used from Python")
+    cdef grpc_call_error result
     cdef Operations cy_operations = Operations(operations)
     cdef OperationTag operation_tag = OperationTag(tag)
     operation_tag.operation_call = self
     operation_tag.batch_operations = cy_operations
     cpython.Py_INCREF(operation_tag)
-    return grpc_call_start_batch(
-        self.c_call, cy_operations.c_ops, cy_operations.c_nops,
-        <cpython.PyObject *>operation_tag, NULL)
+    with nogil:
+      result = grpc_call_start_batch(
+          self.c_call, cy_operations.c_ops, cy_operations.c_nops,
+          <cpython.PyObject *>operation_tag, NULL)
+    return result
 
   def cancel(
       self, grpc_status_code error_code=GRPC_STATUS__DO_NOT_USE,
@@ -57,6 +60,8 @@
     if (details is None) != (error_code == GRPC_STATUS__DO_NOT_USE):
       raise ValueError("if error_code is specified, so must details "
                        "(and vice-versa)")
+    cdef grpc_call_error result
+    cdef char *c_details = NULL
     if error_code != GRPC_STATUS__DO_NOT_USE:
       if isinstance(details, bytes):
         pass
@@ -65,25 +70,37 @@
       else:
         raise TypeError("expected details to be str or bytes")
       self.references.append(details)
-      return grpc_call_cancel_with_status(
-          self.c_call, error_code, details, NULL)
+      c_details = details
+      with nogil:
+        result = grpc_call_cancel_with_status(
+            self.c_call, error_code, c_details, NULL)
+      return result
     else:
-      return grpc_call_cancel(self.c_call, NULL)
+      with nogil:
+        result = grpc_call_cancel(self.c_call, NULL)
+      return result
 
   def set_credentials(
       self, CallCredentials call_credentials not None):
-    return grpc_call_set_credentials(
-        self.c_call, call_credentials.c_credentials)
+    cdef grpc_call_error result
+    with nogil:
+      result = grpc_call_set_credentials(
+          self.c_call, call_credentials.c_credentials)
+    return result
 
   def peer(self):
-    cdef char *peer = grpc_call_get_peer(self.c_call)
+    cdef char *peer = NULL
+    with nogil:
+      peer = grpc_call_get_peer(self.c_call)
     result = <bytes>peer
-    gpr_free(peer)
+    with nogil:
+      gpr_free(peer)
     return result
 
   def __dealloc__(self):
     if self.c_call != NULL:
-      grpc_call_destroy(self.c_call)
+      with nogil:
+        grpc_call_destroy(self.c_call)
 
   # The object *should* always be valid from Python. Used for debugging.
   @property
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
index 1f1833d..d612c90 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
@@ -35,6 +35,7 @@
   def __cinit__(self, target, ChannelArgs arguments=None,
                 ChannelCredentials channel_credentials=None):
     cdef grpc_channel_args *c_arguments = NULL
+    cdef char *c_target = NULL
     self.c_channel = NULL
     self.references = []
     if arguments is not None:
@@ -45,12 +46,15 @@
       target = target.encode()
     else:
       raise TypeError("expected target to be str or bytes")
+    c_target = target
     if channel_credentials is None:
-      self.c_channel = grpc_insecure_channel_create(target, c_arguments,
-                                                         NULL)
+      with nogil:
+        self.c_channel = grpc_insecure_channel_create(c_target, c_arguments,
+                                                      NULL)
     else:
-      self.c_channel = grpc_secure_channel_create(
-          channel_credentials.c_credentials, target, c_arguments, NULL)
+      with nogil:
+        self.c_channel = grpc_secure_channel_create(
+            channel_credentials.c_credentials, c_target, c_arguments, NULL)
       self.references.append(channel_credentials)
     self.references.append(target)
     self.references.append(arguments)
@@ -66,6 +70,7 @@
       method = method.encode()
     else:
       raise TypeError("expected method to be str or bytes")
+    cdef char *method_c_string = method
     cdef char *host_c_string = NULL
     if host is None:
       pass
@@ -81,32 +86,40 @@
     cdef grpc_call *parent_call = NULL
     if parent is not None:
       parent_call = parent.c_call
-    operation_call.c_call = grpc_channel_create_call(
-        self.c_channel, parent_call, flags,
-        queue.c_completion_queue, method, host_c_string, deadline.c_time,
-        NULL)
+    with nogil:
+      operation_call.c_call = grpc_channel_create_call(
+          self.c_channel, parent_call, flags,
+          queue.c_completion_queue, method_c_string, host_c_string,
+          deadline.c_time, NULL)
     return operation_call
 
   def check_connectivity_state(self, bint try_to_connect):
-    return grpc_channel_check_connectivity_state(self.c_channel,
-                                                 try_to_connect)
+    cdef grpc_connectivity_state result
+    with nogil:
+      result = grpc_channel_check_connectivity_state(self.c_channel,
+                                                     try_to_connect)
+    return result
 
   def watch_connectivity_state(
       self, grpc_connectivity_state last_observed_state,
       Timespec deadline not None, CompletionQueue queue not None, tag):
     cdef OperationTag operation_tag = OperationTag(tag)
-    operation_tag.references = [self, queue]
     cpython.Py_INCREF(operation_tag)
-    grpc_channel_watch_connectivity_state(
-        self.c_channel, last_observed_state, deadline.c_time,
-        queue.c_completion_queue, <cpython.PyObject *>operation_tag)
+    with nogil:
+      grpc_channel_watch_connectivity_state(
+          self.c_channel, last_observed_state, deadline.c_time,
+          queue.c_completion_queue, <cpython.PyObject *>operation_tag)
 
   def target(self):
-    cdef char * target = grpc_channel_get_target(self.c_channel)
+    cdef char *target = NULL
+    with nogil:
+      target = grpc_channel_get_target(self.c_channel)
     result = <bytes>target
-    gpr_free(target)
+    with nogil:
+      gpr_free(target)
     return result
 
   def __dealloc__(self):
     if self.c_channel != NULL:
-      grpc_channel_destroy(self.c_channel)
+      with nogil:
+        grpc_channel_destroy(self.c_channel)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
index e11138b..09e47d4 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
@@ -36,7 +36,8 @@
 cdef class CompletionQueue:
 
   def __cinit__(self):
-    self.c_completion_queue = grpc_completion_queue_create(NULL)
+    with nogil:
+      self.c_completion_queue = grpc_completion_queue_create(NULL)
     self.is_shutting_down = False
     self.is_shutdown = False
     self.pluck_condition = threading.Condition()
@@ -82,8 +83,9 @@
   def poll(self, Timespec deadline=None):
     # We name this 'poll' to avoid problems with CPython's expectations for
     # 'special' methods (like next and __next__).
-    cdef gpr_timespec c_deadline = gpr_inf_future(
-        GPR_CLOCK_REALTIME)
+    cdef gpr_timespec c_deadline
+    with nogil:
+      c_deadline = gpr_inf_future(GPR_CLOCK_REALTIME)
     if deadline is not None:
       c_deadline = deadline.c_time
     cdef grpc_event event
@@ -123,7 +125,8 @@
     return self._interpret_event(event)
 
   def shutdown(self):
-    grpc_completion_queue_shutdown(self.c_completion_queue)
+    with nogil:
+      grpc_completion_queue_shutdown(self.c_completion_queue)
     self.is_shutting_down = True
 
   def clear(self):
@@ -133,15 +136,19 @@
       pass
 
   def __dealloc__(self):
-    cdef gpr_timespec c_deadline = gpr_inf_future(GPR_CLOCK_REALTIME)
+    cdef gpr_timespec c_deadline
+    with nogil:
+      c_deadline = gpr_inf_future(GPR_CLOCK_REALTIME)
     if self.c_completion_queue != NULL:
       # Ensure shutdown
       if not self.is_shutting_down:
-        grpc_completion_queue_shutdown(self.c_completion_queue)
+        with nogil:
+          grpc_completion_queue_shutdown(self.c_completion_queue)
       # Pump the queue
       while not self.is_shutdown:
         with nogil:
           event = grpc_completion_queue_next(
               self.c_completion_queue, c_deadline, NULL)
         self._interpret_event(event)
-      grpc_completion_queue_destroy(self.c_completion_queue)
+      with nogil:
+        grpc_completion_queue_destroy(self.c_completion_queue)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
index 3f439c8..1d7adca 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,8 @@
 
   def __dealloc__(self):
     if self.c_credentials != NULL:
-      grpc_channel_credentials_release(self.c_credentials)
+      with nogil:
+        grpc_channel_credentials_release(self.c_credentials)
 
 
 cdef class CallCredentials:
@@ -63,7 +64,8 @@
 
   def __dealloc__(self):
     if self.c_credentials != NULL:
-      grpc_call_credentials_release(self.c_credentials)
+      with nogil:
+        grpc_call_credentials_release(self.c_credentials)
 
 
 cdef class ServerCredentials:
@@ -74,7 +76,8 @@
 
   def __dealloc__(self):
     if self.c_credentials != NULL:
-      grpc_server_credentials_release(self.c_credentials)
+      with nogil:
+        grpc_server_credentials_release(self.c_credentials)
 
 
 cdef class CredentialsMetadataPlugin:
@@ -139,7 +142,8 @@
 
 def channel_credentials_google_default():
   cdef ChannelCredentials credentials = ChannelCredentials();
-  credentials.c_credentials = grpc_google_default_credentials_create()
+  with nogil:
+    credentials.c_credentials = grpc_google_default_credentials_create()
   return credentials
 
 def channel_credentials_ssl(pem_root_certificates,
@@ -158,12 +162,14 @@
     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_ssl_credentials_create(
-        c_pem_root_certificates, &ssl_pem_key_cert_pair.c_pair, NULL)
+    with nogil:
+      credentials.c_credentials = grpc_ssl_credentials_create(
+          c_pem_root_certificates, &ssl_pem_key_cert_pair.c_pair, NULL)
     credentials.references.append(ssl_pem_key_cert_pair)
   else:
-    credentials.c_credentials = grpc_ssl_credentials_create(
-      c_pem_root_certificates, NULL, NULL)
+    with nogil:
+      credentials.c_credentials = grpc_ssl_credentials_create(
+        c_pem_root_certificates, NULL, NULL)
   return credentials
 
 def channel_credentials_composite(
@@ -172,8 +178,9 @@
   if not credentials_1.is_valid or not credentials_2.is_valid:
     raise ValueError("passed credentials must both be valid")
   cdef ChannelCredentials credentials = ChannelCredentials()
-  credentials.c_credentials = grpc_composite_channel_credentials_create(
-      credentials_1.c_credentials, credentials_2.c_credentials, NULL)
+  with nogil:
+    credentials.c_credentials = grpc_composite_channel_credentials_create(
+        credentials_1.c_credentials, credentials_2.c_credentials, NULL)
   credentials.references.append(credentials_1)
   credentials.references.append(credentials_2)
   return credentials
@@ -184,16 +191,18 @@
   if not credentials_1.is_valid or not credentials_2.is_valid:
     raise ValueError("passed credentials must both be valid")
   cdef CallCredentials credentials = CallCredentials()
-  credentials.c_credentials = grpc_composite_call_credentials_create(
-      credentials_1.c_credentials, credentials_2.c_credentials, NULL)
+  with nogil:
+    credentials.c_credentials = grpc_composite_call_credentials_create(
+        credentials_1.c_credentials, credentials_2.c_credentials, NULL)
   credentials.references.append(credentials_1)
   credentials.references.append(credentials_2)
   return credentials
 
 def call_credentials_google_compute_engine():
   cdef CallCredentials credentials = CallCredentials()
-  credentials.c_credentials = (
-      grpc_google_compute_engine_credentials_create(NULL))
+  with nogil:
+    credentials.c_credentials = (
+        grpc_google_compute_engine_credentials_create(NULL))
   return credentials
 
 def call_credentials_service_account_jwt_access(
@@ -205,9 +214,11 @@
   else:
     raise TypeError("expected json_key to be str or bytes")
   cdef CallCredentials credentials = CallCredentials()
-  credentials.c_credentials = (
-      grpc_service_account_jwt_access_credentials_create(
-          json_key, token_lifetime.c_time, NULL))
+  cdef char *json_key_c_string = json_key
+  with nogil:
+    credentials.c_credentials = (
+        grpc_service_account_jwt_access_credentials_create(
+            json_key_c_string, token_lifetime.c_time, NULL))
   credentials.references.append(json_key)
   return credentials
 
@@ -219,8 +230,10 @@
   else:
     raise TypeError("expected json_refresh_token to be str or bytes")
   cdef CallCredentials credentials = CallCredentials()
-  credentials.c_credentials = grpc_google_refresh_token_credentials_create(
-      json_refresh_token, NULL)
+  cdef char *json_refresh_token_c_string = json_refresh_token
+  with nogil:
+    credentials.c_credentials = grpc_google_refresh_token_credentials_create(
+        json_refresh_token_c_string, NULL)
   credentials.references.append(json_refresh_token)
   return credentials
 
@@ -238,17 +251,21 @@
   else:
     raise TypeError("expected authority_selector to be str or bytes")
   cdef CallCredentials credentials = CallCredentials()
-  credentials.c_credentials = grpc_google_iam_credentials_create(
-      authorization_token, authority_selector, NULL)
+  cdef char *authorization_token_c_string = authorization_token
+  cdef char *authority_selector_c_string = authority_selector
+  with nogil:
+    credentials.c_credentials = grpc_google_iam_credentials_create(
+        authorization_token_c_string, authority_selector_c_string, NULL)
   credentials.references.append(authorization_token)
   credentials.references.append(authority_selector)
   return credentials
 
 def call_credentials_metadata_plugin(CredentialsMetadataPlugin plugin):
   cdef CallCredentials credentials = CallCredentials()
-  credentials.c_credentials = (
-      grpc_metadata_credentials_create_from_plugin(plugin.make_c_plugin(),
-                                                        NULL))
+  cdef grpc_metadata_credentials_plugin c_plugin = plugin.make_c_plugin()
+  with nogil:
+    credentials.c_credentials = (
+        grpc_metadata_credentials_create_from_plugin(c_plugin, NULL))
   # TODO(atash): the following held reference is *probably* never necessary
   credentials.references.append(plugin)
   return credentials
@@ -274,11 +291,12 @@
   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_ssl_pem_key_cert_pair *>gpr_malloc(
-          sizeof(grpc_ssl_pem_key_cert_pair) *
-              credentials.c_ssl_pem_key_cert_pairs_count
-      ))
+  with nogil:
+    credentials.c_ssl_pem_key_cert_pairs = (
+        <grpc_ssl_pem_key_cert_pair *>gpr_malloc(
+            sizeof(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] = (
         (<SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index dbf0045..61165cb 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
@@ -38,27 +38,27 @@
 
   int pygrpc_load_core(char*)
 
-  void *gpr_malloc(size_t size)
-  void gpr_free(void *ptr)
-  void *gpr_realloc(void *p, size_t size)
+  void *gpr_malloc(size_t size) nogil
+  void gpr_free(void *ptr) nogil
+  void *gpr_realloc(void *p, size_t size) nogil
 
   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_ref(gpr_slice s) nogil
+  void gpr_slice_unref(gpr_slice s) nogil
+  gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) nogil
   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)
+      void *p, size_t len, void (*destroy)(void *, size_t)) nogil
+  gpr_slice gpr_slice_malloc(size_t length) nogil
+  gpr_slice gpr_slice_from_copied_string(const char *source) nogil
+  gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t len) nogil
 
   # 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)
+  void *gpr_slice_start_ptr "GPR_SLICE_START_PTR" (gpr_slice s) nogil
+  size_t gpr_slice_length "GPR_SLICE_LENGTH" (gpr_slice s) nogil
 
   ctypedef enum gpr_clock_type:
     GPR_CLOCK_MONOTONIC
@@ -71,14 +71,14 @@
     int32_t nanoseconds "tv_nsec"
     gpr_clock_type clock_type
 
-  gpr_timespec gpr_time_0(gpr_clock_type type)
-  gpr_timespec gpr_inf_future(gpr_clock_type type)
-  gpr_timespec gpr_inf_past(gpr_clock_type type)
+  gpr_timespec gpr_time_0(gpr_clock_type type) nogil
+  gpr_timespec gpr_inf_future(gpr_clock_type type) nogil
+  gpr_timespec gpr_inf_past(gpr_clock_type type) nogil
 
-  gpr_timespec gpr_now(gpr_clock_type clock)
+  gpr_timespec gpr_now(gpr_clock_type clock) nogil
 
   gpr_timespec gpr_convert_clock_type(gpr_timespec t,
-                                      gpr_clock_type target_clock)
+                                      gpr_clock_type target_clock) nogil
 
   ctypedef enum grpc_status_code:
     GRPC_STATUS_OK
@@ -114,15 +114,15 @@
     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)
+                                                size_t nslices) nogil
+  size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) nogil
+  void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer) nogil
 
   void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
-                                    grpc_byte_buffer *buffer)
+                                    grpc_byte_buffer *buffer) nogil
   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)
+                                   gpr_slice *slice) nogil
+  void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) nogil
 
   const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING
   const char *GRPC_ARG_ENABLE_CENSUS
@@ -221,8 +221,8 @@
     size_t capacity
     grpc_metadata *metadata
 
-  void grpc_metadata_array_init(grpc_metadata_array *array)
-  void grpc_metadata_array_destroy(grpc_metadata_array *array)
+  void grpc_metadata_array_init(grpc_metadata_array *array) nogil
+  void grpc_metadata_array_destroy(grpc_metadata_array *array) nogil
 
   ctypedef struct grpc_call_details:
     char *method
@@ -231,8 +231,8 @@
     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)
+  void grpc_call_details_init(grpc_call_details *details) nogil
+  void grpc_call_details_destroy(grpc_call_details *details) nogil
 
   ctypedef enum grpc_op_type:
     GRPC_OP_SEND_INITIAL_METADATA
@@ -277,61 +277,62 @@
     uint32_t flags
     grpc_op_data data
 
-  void grpc_init()
-  void grpc_shutdown()
+  void grpc_init() nogil
+  void grpc_shutdown() nogil
 
-  grpc_completion_queue *grpc_completion_queue_create(void *reserved)
+  grpc_completion_queue *grpc_completion_queue_create(void *reserved) nogil
   grpc_event grpc_completion_queue_next(grpc_completion_queue *cq,
                                         gpr_timespec deadline,
                                         void *reserved) nogil
   grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cq, void *tag,
                                          gpr_timespec deadline,
                                          void *reserved) nogil
-  void grpc_completion_queue_shutdown(grpc_completion_queue *cq)
-  void grpc_completion_queue_destroy(grpc_completion_queue *cq)
+  void grpc_completion_queue_shutdown(grpc_completion_queue *cq) nogil
+  void grpc_completion_queue_destroy(grpc_completion_queue *cq) nogil
 
-  grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
-                                        size_t nops, void *tag, void *reserved)
-  grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved)
+  grpc_call_error grpc_call_start_batch(
+      grpc_call *call, const grpc_op *ops, size_t nops, void *tag,
+      void *reserved) nogil
+  grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) nogil
   grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
                                                grpc_status_code status,
                                                const char *description,
-                                               void *reserved)
-  char *grpc_call_get_peer(grpc_call *call)
-  void grpc_call_destroy(grpc_call *call)
+                                               void *reserved) nogil
+  char *grpc_call_get_peer(grpc_call *call) nogil
+  void grpc_call_destroy(grpc_call *call) nogil
 
   grpc_channel *grpc_insecure_channel_create(const char *target,
                                              const grpc_channel_args *args,
-                                             void *reserved)
-  grpc_call *grpc_channel_create_call(grpc_channel *channel,
-                                      grpc_call *parent_call,
-                                      uint32_t propagation_mask,
-                                      grpc_completion_queue *completion_queue,
-                                      const char *method, const char *host,
-                                      gpr_timespec deadline, void *reserved)
+                                             void *reserved) nogil
+  grpc_call *grpc_channel_create_call(
+      grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
+      grpc_completion_queue *completion_queue, const char *method,
+      const char *host, gpr_timespec deadline, void *reserved) nogil
   grpc_connectivity_state grpc_channel_check_connectivity_state(
-      grpc_channel *channel, int try_to_connect)
+      grpc_channel *channel, int try_to_connect) nogil
   void grpc_channel_watch_connectivity_state(
       grpc_channel *channel, grpc_connectivity_state last_observed_state,
-      gpr_timespec deadline, grpc_completion_queue *cq, void *tag)
-  char *grpc_channel_get_target(grpc_channel *channel)
-  void grpc_channel_destroy(grpc_channel *channel)
+      gpr_timespec deadline, grpc_completion_queue *cq, void *tag) nogil
+  char *grpc_channel_get_target(grpc_channel *channel) nogil
+  void grpc_channel_destroy(grpc_channel *channel) nogil
 
-  grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved)
+  grpc_server *grpc_server_create(
+      const grpc_channel_args *args, void *reserved) nogil
   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)
+      *tag_new) nogil
   void grpc_server_register_completion_queue(grpc_server *server,
                                              grpc_completion_queue *cq,
-                                             void *reserved)
-  int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr)
-  void grpc_server_start(grpc_server *server)
+                                             void *reserved) nogil
+  int grpc_server_add_insecure_http2_port(
+      grpc_server *server, const char *addr) nogil
+  void grpc_server_start(grpc_server *server) nogil
   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)
+      grpc_server *server, grpc_completion_queue *cq, void *tag) nogil
+  void grpc_server_cancel_all_calls(grpc_server *server) nogil
+  void grpc_server_destroy(grpc_server *server) nogil
 
   ctypedef struct grpc_ssl_pem_key_cert_pair:
     const char *private_key
@@ -347,35 +348,36 @@
 
   ctypedef void (*grpc_ssl_roots_override_callback)(char **pem_root_certs)
 
-  void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb)
+  void grpc_set_ssl_roots_override_callback(
+      grpc_ssl_roots_override_callback cb) nogil
 
-  grpc_channel_credentials *grpc_google_default_credentials_create()
+  grpc_channel_credentials *grpc_google_default_credentials_create() nogil
   grpc_channel_credentials *grpc_ssl_credentials_create(
       const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
-      void *reserved)
+      void *reserved) nogil
   grpc_channel_credentials *grpc_composite_channel_credentials_create(
       grpc_channel_credentials *creds1, grpc_call_credentials *creds2,
-      void *reserved)
-  void grpc_channel_credentials_release(grpc_channel_credentials *creds)
+      void *reserved) nogil
+  void grpc_channel_credentials_release(grpc_channel_credentials *creds) nogil
 
   grpc_call_credentials *grpc_composite_call_credentials_create(
       grpc_call_credentials *creds1, grpc_call_credentials *creds2,
-      void *reserved)
+      void *reserved) nogil
   grpc_call_credentials *grpc_google_compute_engine_credentials_create(
-      void *reserved)
+      void *reserved) nogil
   grpc_call_credentials *grpc_service_account_jwt_access_credentials_create(
       const char *json_key,
-      gpr_timespec token_lifetime, void *reserved)
+      gpr_timespec token_lifetime, void *reserved) nogil
   grpc_call_credentials *grpc_google_refresh_token_credentials_create(
-      const char *json_refresh_token, void *reserved)
+      const char *json_refresh_token, void *reserved) nogil
   grpc_call_credentials *grpc_google_iam_credentials_create(
       const char *authorization_token, const char *authority_selector,
-      void *reserved)
-  void grpc_call_credentials_release(grpc_call_credentials *creds)
+      void *reserved) nogil
+  void grpc_call_credentials_release(grpc_call_credentials *creds) nogil
 
   grpc_channel *grpc_secure_channel_create(
       grpc_channel_credentials *creds, const char *target,
-      const grpc_channel_args *args, void *reserved)
+      const grpc_channel_args *args, void *reserved) nogil
 
   ctypedef struct grpc_server_credentials:
     # We don't care about the internals (and in fact don't know them)
@@ -385,13 +387,13 @@
       const char *pem_root_certs,
       grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
       size_t num_key_cert_pairs, int force_client_auth, void *reserved)
-  void grpc_server_credentials_release(grpc_server_credentials *creds)
+  void grpc_server_credentials_release(grpc_server_credentials *creds) nogil
 
   int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
-                                        grpc_server_credentials *creds)
+                                        grpc_server_credentials *creds) nogil
 
   grpc_call_error grpc_call_set_credentials(grpc_call *call,
-                                            grpc_call_credentials *creds)
+                                            grpc_call_credentials *creds) nogil
 
   ctypedef struct grpc_auth_context:
     # We don't care about the internals (and in fact don't know them)
@@ -415,4 +417,4 @@
     const char *type
 
   grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
-      grpc_metadata_credentials_plugin plugin, void *reserved)
+      grpc_metadata_credentials_plugin plugin, void *reserved) nogil
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
index fa4ea99..6ecdcf7 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -107,15 +107,18 @@
 
   def __cinit__(self, time):
     if time is None:
-      self.c_time = gpr_now(GPR_CLOCK_REALTIME)
+      with nogil:
+        self.c_time = gpr_now(GPR_CLOCK_REALTIME)
       return
     if isinstance(time, int):
       time = float(time)
     if isinstance(time, float):
       if time == float("+inf"):
-        self.c_time = gpr_inf_future(GPR_CLOCK_REALTIME)
+        with nogil:
+          self.c_time = gpr_inf_future(GPR_CLOCK_REALTIME)
       elif time == float("-inf"):
-        self.c_time = gpr_inf_past(GPR_CLOCK_REALTIME)
+        with nogil:
+          self.c_time = gpr_inf_past(GPR_CLOCK_REALTIME)
       else:
         self.c_time.seconds = time
         self.c_time.nanoseconds = (time - float(self.c_time.seconds)) * 1e9
@@ -131,8 +134,10 @@
     # TODO(atash) ensure that everywhere a Timespec is created that it's
     # converted to GPR_CLOCK_REALTIME then and not every time someone wants to
     # read values off in Python.
-    cdef gpr_timespec real_time = (
-        gpr_convert_clock_type(self.c_time, GPR_CLOCK_REALTIME))
+    cdef gpr_timespec real_time
+    with nogil:
+      real_time = (
+          gpr_convert_clock_type(self.c_time, GPR_CLOCK_REALTIME))
     return real_time.seconds
 
   @property
@@ -158,10 +163,12 @@
 cdef class CallDetails:
 
   def __cinit__(self):
-    grpc_call_details_init(&self.c_details)
+    with nogil:
+      grpc_call_details_init(&self.c_details)
 
   def __dealloc__(self):
-    grpc_call_details_destroy(&self.c_details)
+    with nogil:
+      grpc_call_details_destroy(&self.c_details)
 
   @property
   def method(self):
@@ -229,10 +236,15 @@
                       "ByteBuffer, not {}".format(type(data)))
 
     cdef char *c_data = data
-    data_slice = gpr_slice_from_copied_buffer(c_data, len(data))
-    self.c_byte_buffer = grpc_raw_byte_buffer_create(
-        &data_slice, 1)
-    gpr_slice_unref(data_slice)
+    cdef gpr_slice data_slice
+    cdef size_t data_length = len(data)
+    with nogil:
+      data_slice = gpr_slice_from_copied_buffer(c_data, data_length)
+    with nogil:
+      self.c_byte_buffer = grpc_raw_byte_buffer_create(
+          &data_slice, 1)
+    with nogil:
+      gpr_slice_unref(data_slice)
 
   def bytes(self):
     cdef grpc_byte_buffer_reader reader
@@ -240,20 +252,27 @@
     cdef size_t data_slice_length
     cdef void *data_slice_pointer
     if self.c_byte_buffer != NULL:
-      grpc_byte_buffer_reader_init(&reader, self.c_byte_buffer)
-      result = b""
-      while grpc_byte_buffer_reader_next(&reader, &data_slice):
-        data_slice_pointer = gpr_slice_start_ptr(data_slice)
-        data_slice_length = gpr_slice_length(data_slice)
-        result += (<char *>data_slice_pointer)[:data_slice_length]
-      grpc_byte_buffer_reader_destroy(&reader)
-      return result
+      with nogil:
+        grpc_byte_buffer_reader_init(&reader, self.c_byte_buffer)
+      result = bytearray()
+      with nogil:
+        while grpc_byte_buffer_reader_next(&reader, &data_slice):
+          data_slice_pointer = gpr_slice_start_ptr(data_slice)
+          data_slice_length = gpr_slice_length(data_slice)
+          with gil:
+            result += (<char *>data_slice_pointer)[:data_slice_length]
+      with nogil:
+        grpc_byte_buffer_reader_destroy(&reader)
+      return bytes(result)
     else:
       return None
 
   def __len__(self):
+    cdef size_t result
     if self.c_byte_buffer != NULL:
-      return grpc_byte_buffer_length(self.c_byte_buffer)
+      with nogil:
+        result = grpc_byte_buffer_length(self.c_byte_buffer)
+      return result
     else:
       return 0
 
@@ -262,7 +281,8 @@
 
   def __dealloc__(self):
     if self.c_byte_buffer != NULL:
-      grpc_byte_buffer_destroy(self.c_byte_buffer)
+      with nogil:
+        grpc_byte_buffer_destroy(self.c_byte_buffer)
 
 
 cdef class SslPemKeyCertPair:
@@ -319,14 +339,15 @@
       if not isinstance(arg, ChannelArg):
         raise TypeError("expected list of ChannelArg")
     self.c_args.arguments_length = len(self.args)
-    self.c_args.arguments = <grpc_arg *>gpr_malloc(
-        self.c_args.arguments_length*sizeof(grpc_arg)
-    )
+    with nogil:
+      self.c_args.arguments = <grpc_arg *>gpr_malloc(
+          self.c_args.arguments_length*sizeof(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):
-    gpr_free(self.c_args.arguments)
+    with nogil:
+      gpr_free(self.c_args.arguments)
 
   def __len__(self):
     # self.args is never stale; it's only updated from this file
@@ -407,21 +428,24 @@
     for metadatum in metadata:
       if not isinstance(metadatum, Metadatum):
         raise TypeError("expected list of Metadatum")
-    grpc_metadata_array_init(&self.c_metadata_array)
+    with nogil:
+      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_metadata *>gpr_malloc(
-        self.c_metadata_array.count*sizeof(grpc_metadata)
-    )
+    with nogil:
+      self.c_metadata_array.metadata = <grpc_metadata *>gpr_malloc(
+          self.c_metadata_array.count*sizeof(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_metadata_array_destroy(&self.c_metadata_array)
+    # it'd be nice if that were documented somewhere...)
+    # TODO(atash): document this in the C core
+    with nogil:
+      grpc_metadata_array_destroy(&self.c_metadata_array)
 
   def __len__(self):
     return self.c_metadata_array.count
@@ -526,7 +550,8 @@
     # 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_OP_RECV_STATUS_ON_CLIENT:
-      gpr_free(self._received_status_details)
+      with nogil:
+        gpr_free(self._received_status_details)
 
 def operation_send_initial_metadata(Metadata metadata):
   cdef Operation op = Operation()
@@ -648,8 +673,8 @@
       if not isinstance(operation, Operation):
         raise TypeError("expected operations to be iterable of Operation")
     self.c_nops = len(self.operations)
-    self.c_ops = <grpc_op *>gpr_malloc(
-        sizeof(grpc_op)*self.c_nops)
+    with nogil:
+      self.c_ops = <grpc_op *>gpr_malloc(sizeof(grpc_op)*self.c_nops)
     for i in range(self.c_nops):
       self.c_ops[i] = (<Operation>(self.operations[i])).c_op
 
@@ -661,7 +686,8 @@
     return self.operations[i]
 
   def __dealloc__(self):
-    gpr_free(self.c_ops)
+    with nogil:
+      gpr_free(self.c_ops)
 
   def __iter__(self):
     return _OperationsIterator(self)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
index fe93da6..a098f11 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
@@ -41,7 +41,8 @@
     if arguments is not None:
       c_arguments = &arguments.c_args
       self.references.append(arguments)
-    self.c_server = grpc_server_create(c_arguments, NULL)
+    with nogil:
+      self.c_server = grpc_server_create(c_arguments, NULL)
     self.is_started = False
     self.is_shutting_down = False
     self.is_shutdown = False
@@ -53,6 +54,7 @@
       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 grpc_call_error result
     cdef OperationTag operation_tag = OperationTag(tag)
     operation_tag.operation_call = Call()
     operation_tag.request_call_details = CallDetails()
@@ -61,19 +63,22 @@
     operation_tag.is_new_request = True
     operation_tag.batch_operations = Operations([])
     cpython.Py_INCREF(operation_tag)
-    return 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)
+    with nogil:
+      result = 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)
+    return result
 
   def register_completion_queue(
       self, CompletionQueue queue not None):
     if self.is_started:
       raise ValueError("cannot register completion queues after start")
-    grpc_server_register_completion_queue(
-        self.c_server, queue.c_completion_queue, NULL)
+    with nogil:
+      grpc_server_register_completion_queue(
+          self.c_server, queue.c_completion_queue, NULL)
     self.registered_completion_queues.append(queue)
 
   def start(self):
@@ -82,7 +87,8 @@
     self.backup_shutdown_queue = CompletionQueue()
     self.register_completion_queue(self.backup_shutdown_queue)
     self.is_started = True
-    grpc_server_start(self.c_server)
+    with nogil:
+      grpc_server_start(self.c_server)
     # Ensure the core has gotten a chance to do the start-up work
     self.backup_shutdown_queue.pluck(None, Timespec(None))
 
@@ -95,22 +101,28 @@
     else:
       raise TypeError("expected address to be a str or bytes")
     self.references.append(address)
+    cdef int result
+    cdef char *address_c_string = address
     if server_credentials is not None:
       self.references.append(server_credentials)
-      return grpc_server_add_secure_http2_port(
-          self.c_server, address, server_credentials.c_credentials)
+      with nogil:
+        result = grpc_server_add_secure_http2_port(
+            self.c_server, address_c_string, server_credentials.c_credentials)
     else:
-      return grpc_server_add_insecure_http2_port(self.c_server, address)
+      with nogil:
+        result = grpc_server_add_insecure_http2_port(self.c_server,
+                                                     address_c_string)
+    return result
 
   cdef _c_shutdown(self, CompletionQueue queue, tag):
     self.is_shutting_down = True
     operation_tag = OperationTag(tag)
     operation_tag.shutting_down_server = self
-    operation_tag.references.extend([self, queue])
     cpython.Py_INCREF(operation_tag)
-    grpc_server_shutdown_and_notify(
-        self.c_server, queue.c_completion_queue,
-        <cpython.PyObject *>operation_tag)
+    with nogil:
+      grpc_server_shutdown_and_notify(
+          self.c_server, queue.c_completion_queue,
+          <cpython.PyObject *>operation_tag)
 
   def shutdown(self, CompletionQueue queue not None, tag):
     cdef OperationTag operation_tag
@@ -135,7 +147,8 @@
     elif self.is_shutdown:
       return
     else:
-      grpc_server_cancel_all_calls(self.c_server)
+      with nogil:
+        grpc_server_cancel_all_calls(self.c_server)
 
   def __dealloc__(self):
     if self.c_server != NULL:
@@ -154,5 +167,6 @@
         # much but repeatedly release the GIL and wait
         while not self.is_shutdown:
           time.sleep(0)
-      grpc_server_destroy(self.c_server)
+      with nogil:
+        grpc_server_destroy(self.c_server)
 
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index 30cc7a1..8a0f171 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -57,14 +57,17 @@
           'grpc._cython', '_windows/grpc_c.64.python')
       if not pygrpc_load_core(filename):
         raise ImportError('failed to load core gRPC library')
-    grpc_init()
+    with nogil:
+      grpc_init()
     self.is_loaded = True
-    grpc_set_ssl_roots_override_callback(
-        <grpc_ssl_roots_override_callback>ssl_roots_override_callback)
+    with nogil:
+      grpc_set_ssl_roots_override_callback(
+          <grpc_ssl_roots_override_callback>ssl_roots_override_callback)
 
   def __dealloc__(self):
     if self.is_loaded:
-      grpc_shutdown()
+      with nogil:
+        grpc_shutdown()
 
 _module_state = _ModuleState()
 
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.h b/src/python/grpcio/grpc/_cython/imports.generated.h
index b70dccc..4d18369 100644
--- a/src/python/grpcio/grpc/_cython/imports.generated.h
+++ b/src/python/grpcio/grpc/_cython/imports.generated.h
@@ -166,7 +166,7 @@
 typedef int(*grpc_compression_algorithm_name_type)(grpc_compression_algorithm algorithm, char **name);
 extern grpc_compression_algorithm_name_type grpc_compression_algorithm_name_import;
 #define grpc_compression_algorithm_name grpc_compression_algorithm_name_import
-typedef grpc_compression_algorithm(*grpc_compression_algorithm_for_level_type)(grpc_compression_level level);
+typedef grpc_compression_algorithm(*grpc_compression_algorithm_for_level_type)(grpc_compression_level level, uint32_t accepted_encodings);
 extern grpc_compression_algorithm_for_level_type grpc_compression_algorithm_for_level_import;
 #define grpc_compression_algorithm_for_level grpc_compression_algorithm_for_level_import
 typedef void(*grpc_compression_options_init_type)(grpc_compression_options *opts);
diff --git a/src/python/grpcio/grpc/_links/invocation.py b/src/python/grpcio/grpc/_links/invocation.py
index 5ca0a0e..672e3e4 100644
--- a/src/python/grpcio/grpc/_links/invocation.py
+++ b/src/python/grpcio/grpc/_links/invocation.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,8 @@
 import threading
 import time
 
+import six
+
 from grpc._adapter import _intermediary_low
 from grpc._links import _constants
 from grpc.beta import interfaces as beta_interfaces
@@ -372,12 +374,11 @@
     pool.shutdown(wait=True)
 
 
-class InvocationLink(links.Link, activated.Activated):
+class InvocationLink(six.with_metaclass(abc.ABCMeta, 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):
diff --git a/src/python/grpcio/grpc/_links/service.py b/src/python/grpcio/grpc/_links/service.py
index 01edee6..e0f26a5 100644
--- a/src/python/grpcio/grpc/_links/service.py
+++ b/src/python/grpcio/grpc/_links/service.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -177,7 +177,7 @@
     call = service_acceptance.call
     call.accept(self._completion_queue, call)
     try:
-      group, method = service_acceptance.method.split('/')[1:3]
+      group, method = service_acceptance.method.split(b'/')[1:3]
     except ValueError:
       logging.info('Illegal path "%s"!', service_acceptance.method)
       return
diff --git a/src/python/grpcio/grpc/beta/_server.py b/src/python/grpcio/grpc/beta/_server.py
index 2b520cc..12d16e6 100644
--- a/src/python/grpcio/grpc/beta/_server.py
+++ b/src/python/grpcio/grpc/beta/_server.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -62,7 +62,7 @@
       if e.code is None and e.details is None:
         raise base.NoSuchMethodError(
             interfaces.StatusCode.UNIMPLEMENTED,
-            b'Method "%s" of service "%s" not implemented!' % (method, group))
+            'Method "%s" of service "%s" not implemented!' % (method, group))
       else:
         raise
 
diff --git a/src/python/grpcio/grpc/beta/interfaces.py b/src/python/grpcio/grpc/beta/interfaces.py
index 0663119..e29a5b3 100644
--- a/src/python/grpcio/grpc/beta/interfaces.py
+++ b/src/python/grpcio/grpc/beta/interfaces.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,8 @@
 import abc
 import enum
 
+import six
+
 from grpc._adapter import _types
 
 
@@ -105,19 +107,17 @@
   return GRPCCallOptions(disable_compression, None, credentials)
 
 
-class GRPCAuthMetadataContext(object):
+class GRPCAuthMetadataContext(six.with_metaclass(abc.ABCMeta)):
   """Provides information to call credentials metadata plugins.
 
   Attributes:
     service_url: A string URL of the service being called into.
     method_name: A string of the fully qualified method name being called.
   """
-  __metaclass__ = abc.ABCMeta
 
 
-class GRPCAuthMetadataPluginCallback(object):
+class GRPCAuthMetadataPluginCallback(six.with_metaclass(abc.ABCMeta)):
   """Callback object received by a metadata plugin."""
-  __metaclass__ = abc.ABCMeta
 
   def __call__(self, metadata, error):
     """Inform the gRPC runtime of the metadata to construct a CallCredentials.
@@ -130,10 +130,9 @@
     raise NotImplementedError()
 
 
-class GRPCAuthMetadataPlugin(object):
+class GRPCAuthMetadataPlugin(six.with_metaclass(abc.ABCMeta)):
   """
   """
-  __metaclass__ = abc.ABCMeta
 
   def __call__(self, context, callback):
     """Invoke the plugin.
@@ -149,9 +148,8 @@
     raise NotImplementedError()
 
 
-class GRPCServicerContext(object):
+class GRPCServicerContext(six.with_metaclass(abc.ABCMeta)):
   """Exposes gRPC-specific options and behaviors to code servicing RPCs."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def peer(self):
@@ -168,9 +166,8 @@
     raise NotImplementedError()
 
 
-class GRPCInvocationContext(object):
+class GRPCInvocationContext(six.with_metaclass(abc.ABCMeta)):
   """Exposes gRPC-specific options and behaviors to code invoking RPCs."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def disable_next_request_compression(self):
@@ -178,9 +175,8 @@
     raise NotImplementedError()
 
 
-class Server(object):
+class Server(six.with_metaclass(abc.ABCMeta)):
   """Services RPCs."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def add_insecure_port(self, address):
diff --git a/src/python/grpcio/grpc/framework/alpha/_face_utilities.py b/src/python/grpcio/grpc/framework/alpha/_face_utilities.py
index fb0cfe4..b5e4133 100644
--- a/src/python/grpcio/grpc/framework/alpha/_face_utilities.py
+++ b/src/python/grpcio/grpc/framework/alpha/_face_utilities.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,8 @@
 import abc
 import collections
 
+import six
+
 # face_interfaces is referenced from specification in this module.
 from grpc.framework.common import cardinality
 from grpc.framework.face import interfaces as face_interfaces  # pylint: disable=unused-import
@@ -45,7 +47,7 @@
 # TODO(nathaniel): This structure is getting bloated; it could be shrunk if
 # implementations._Stub used a generic rather than a dynamic underlying
 # face-layer stub.
-class InvocationBreakdown(object):
+class InvocationBreakdown(six.with_metaclass(abc.ABCMeta)):
   """An intermediate representation of invocation-side views of RPC methods.
 
   Attributes:
@@ -61,7 +63,6 @@
       to callable behavior to be used deserializing response values for the
       RPC.
   """
-  __metaclass__ = abc.ABCMeta
 
 
 class _EasyInvocationBreakdown(
@@ -73,7 +74,7 @@
   pass
 
 
-class ServiceBreakdown(object):
+class ServiceBreakdown(six.with_metaclass(abc.ABCMeta)):
   """An intermediate representation of service-side views of RPC methods.
 
   Attributes:
@@ -84,7 +85,6 @@
     response_serializers: A dictionary from service-qualified RPC method name
       to callable behavior to be used serializing response values for the RPC.
   """
-  __metaclass__ = abc.ABCMeta
 
 
 class _EasyServiceBreakdown(
@@ -111,7 +111,7 @@
   face_cardinalities = {}
   request_serializers = {}
   response_deserializers = {}
-  for name, method_description in method_descriptions.iteritems():
+  for name, method_description in six.iteritems(method_descriptions):
     qualified_name = _qualified_name(service_name, name)
     method_cardinality = method_description.cardinality()
     cardinalities[name] = method_description.cardinality()
@@ -139,7 +139,7 @@
   implementations = {}
   request_deserializers = {}
   response_serializers = {}
-  for name, method_description in method_descriptions.iteritems():
+  for name, method_description in six.iteritems(method_descriptions):
     qualified_name = _qualified_name(service_name, name)
     method_cardinality = method_description.cardinality()
     if method_cardinality is interfaces.Cardinality.UNARY_UNARY:
diff --git a/src/python/grpcio/grpc/framework/alpha/_reexport.py b/src/python/grpcio/grpc/framework/alpha/_reexport.py
index 198cb95..4ea0e94 100644
--- a/src/python/grpcio/grpc/framework/alpha/_reexport.py
+++ b/src/python/grpcio/grpc/framework/alpha/_reexport.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -27,6 +27,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.
 
+import six
+
 from grpc.framework.common import cardinality
 from grpc.framework.face import exceptions as face_exceptions
 from grpc.framework.face import interfaces as face_interfaces
@@ -181,7 +183,7 @@
 
 def common_cardinalities(early_adopter_cardinalities):
   common_cardinalities = {}
-  for name, early_adopter_cardinality in early_adopter_cardinalities.iteritems():
+  for name, early_adopter_cardinality in six.iteritems(early_adopter_cardinalities):
     common_cardinalities[name] = _EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY[
         early_adopter_cardinality]
   return common_cardinalities
diff --git a/src/python/grpcio/grpc/framework/alpha/exceptions.py b/src/python/grpcio/grpc/framework/alpha/exceptions.py
index 5234d3b..8ec2604 100644
--- a/src/python/grpcio/grpc/framework/alpha/exceptions.py
+++ b/src/python/grpcio/grpc/framework/alpha/exceptions.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,13 +31,12 @@
 
 Only GRPC should instantiate and raise these exceptions.
 """
-
 import abc
 
+import six
 
-class RpcError(Exception):
+class RpcError(six.with_metaclass(abc.ABCMeta, Exception)):
   """Common super type for all exceptions raised by GRPC."""
-  __metaclass__ = abc.ABCMeta
 
 
 class CancellationError(RpcError):
diff --git a/src/python/grpcio/grpc/framework/alpha/interfaces.py b/src/python/grpcio/grpc/framework/alpha/interfaces.py
index 8380567..cb6d58b 100644
--- a/src/python/grpcio/grpc/framework/alpha/interfaces.py
+++ b/src/python/grpcio/grpc/framework/alpha/interfaces.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,8 @@
 import abc
 import enum
 
+import six
+
 # exceptions is referenced from specification in this module.
 from grpc.framework.alpha import exceptions  # pylint: disable=unused-import
 from grpc.framework.foundation import activated
@@ -59,15 +61,17 @@
   SERVICER_FAILURE = 'servicer failure'
 
 
-class CancellableIterator(object):
+class CancellableIterator(six.with_metaclass(abc.ABCMeta)):
   """Implements the Iterator protocol and affords a cancel method."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __iter__(self):
     """Returns the self object in accordance with the Iterator protocol."""
     raise NotImplementedError()
 
+  def __next__(self):
+    return self.next()
+
   @abc.abstractmethod
   def next(self):
     """Returns a value or raises StopIteration per the Iterator protocol."""
@@ -79,9 +83,8 @@
     raise NotImplementedError()
 
 
-class RpcContext(object):
+class RpcContext(six.with_metaclass(abc.ABCMeta)):
   """Provides RPC-related information and action."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def is_active(self):
@@ -108,7 +111,7 @@
     raise NotImplementedError()
 
 
-class UnaryUnarySyncAsync(object):
+class UnaryUnarySyncAsync(six.with_metaclass(abc.ABCMeta)):
   """Affords invoking a unary-unary RPC synchronously or asynchronously.
   Values implementing this interface are directly callable and present an
   "async" method. Both calls take a request value and a numeric timeout.
@@ -117,7 +120,6 @@
   of a value of this type invokes its associated RPC and immediately returns a
   future.Future bound to the asynchronous execution of the RPC.
   """
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __call__(self, request, timeout):
@@ -147,7 +149,7 @@
     raise NotImplementedError()
 
 
-class StreamUnarySyncAsync(object):
+class StreamUnarySyncAsync(six.with_metaclass(abc.ABCMeta)):
   """Affords invoking a stream-unary RPC synchronously or asynchronously.
   Values implementing this interface are directly callable and present an
   "async" method. Both calls take an iterator of request values and a numeric
@@ -156,7 +158,6 @@
   of a value of this type invokes its associated RPC and immediately returns a
   future.Future bound to the asynchronous execution of the RPC.
   """
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __call__(self, request_iterator, timeout):
@@ -191,9 +192,8 @@
     raise NotImplementedError()
 
 
-class RpcMethodDescription(object):
+class RpcMethodDescription(six.with_metaclass(abc.ABCMeta)):
   """A type for the common aspects of RPC method descriptions."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def cardinality(self):
@@ -207,9 +207,8 @@
     raise NotImplementedError()
 
 
-class RpcMethodInvocationDescription(RpcMethodDescription):
+class RpcMethodInvocationDescription(six.with_metaclass(abc.ABCMeta, RpcMethodDescription)):
   """Invocation-side description of an RPC method."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def serialize_request(self, request):
@@ -240,9 +239,8 @@
     raise NotImplementedError()
 
 
-class RpcMethodServiceDescription(RpcMethodDescription):
+class RpcMethodServiceDescription(six.with_metaclass(abc.ABCMeta, RpcMethodDescription)):
   """Service-side description of an RPC method."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def deserialize_request(self, serialized_request):
@@ -345,7 +343,7 @@
     raise NotImplementedError()
 
 
-class Stub(object):
+class Stub(six.with_metaclass(abc.ABCMeta)):
   """A stub with callable RPC method names for attributes.
 
   Instances of this type are context managers and only afford RPC invocation
@@ -369,12 +367,10 @@
   exceptions.RpcError, exceptions.CancellationError,
   and exceptions.ExpirationError.
   """
-  __metaclass__ = abc.ABCMeta
 
 
-class Server(activated.Activated):
+class Server(six.with_metaclass(abc.ABCMeta, activated.Activated)):
   """A GRPC Server."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def port(self):
diff --git a/src/python/grpcio/grpc/framework/base/_ingestion.py b/src/python/grpcio/grpc/framework/base/_ingestion.py
index 06d5b92..090cb15 100644
--- a/src/python/grpcio/grpc/framework/base/_ingestion.py
+++ b/src/python/grpcio/grpc/framework/base/_ingestion.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,8 @@
 import abc
 import collections
 
+import six
+
 from grpc.framework.base import _constants
 from grpc.framework.base import _interfaces
 from grpc.framework.base import exceptions
@@ -72,9 +74,8 @@
     """See stream.Consumer.consume_and_terminate for specification."""
 
 
-class _ConsumerCreator(object):
+class _ConsumerCreator(six.with_metaclass(abc.ABCMeta)):
   """Common specification of different consumer-creating behavior."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def create_consumer(self, requirement):
diff --git a/src/python/grpcio/grpc/framework/base/_interfaces.py b/src/python/grpcio/grpc/framework/base/_interfaces.py
index d88cf76..c0cc866 100644
--- a/src/python/grpcio/grpc/framework/base/_interfaces.py
+++ b/src/python/grpcio/grpc/framework/base/_interfaces.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,14 +31,15 @@
 
 import abc
 
+import six
+
 # interfaces is referenced from specification in this module.
 from grpc.framework.base import interfaces  # pylint: disable=unused-import
 from grpc.framework.foundation import stream
 
 
-class TerminationManager(object):
+class TerminationManager(six.with_metaclass(abc.ABCMeta)):
   """An object responsible for handling the termination of an operation."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def set_expiration_manager(self, expiration_manager):
@@ -91,9 +92,8 @@
     raise NotImplementedError()
 
 
-class TransmissionManager(object):
+class TransmissionManager(six.with_metaclass(abc.ABCMeta)):
   """A manager responsible for transmitting to the other end of an operation."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def inmit(self, emission, complete):
@@ -117,9 +117,8 @@
     raise NotImplementedError()
 
 
-class EmissionManager(stream.Consumer):
+class EmissionManager(six.with_metaclass(abc.ABCMeta, stream.Consumer)):
   """A manager of values emitted by customer code."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def set_ingestion_manager_and_expiration_manager(
@@ -166,9 +165,8 @@
     raise NotImplementedError()
 
 
-class IngestionManager(stream.Consumer):
+class IngestionManager(six.with_metaclass(abc.ABCMeta, stream.Consumer)):
   """A manager responsible for executing customer code."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def set_expiration_manager(self, expiration_manager):
@@ -214,9 +212,8 @@
     raise NotImplementedError()
 
 
-class ExpirationManager(object):
+class ExpirationManager(six.with_metaclass(abc.ABCMeta)):
   """A manager responsible for aborting the operation if it runs out of time."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def change_timeout(self, timeout):
@@ -246,9 +243,8 @@
     raise NotImplementedError()
 
 
-class ReceptionManager(object):
+class ReceptionManager(six.with_metaclass(abc.ABCMeta)):
   """A manager responsible for receiving tickets from the other end."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def receive_ticket(self, ticket):
@@ -261,9 +257,8 @@
     raise NotImplementedError()
 
 
-class CancellationManager(object):
+class CancellationManager(six.with_metaclass(abc.ABCMeta)):
   """A manager of operation cancellation."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def cancel(self):
diff --git a/src/python/grpcio/grpc/framework/base/_reception.py b/src/python/grpcio/grpc/framework/base/_reception.py
index dd42896..2bee394 100644
--- a/src/python/grpcio/grpc/framework/base/_reception.py
+++ b/src/python/grpcio/grpc/framework/base/_reception.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
 
 import abc
 
+import six
+
 from grpc.framework.base import interfaces
 from grpc.framework.base import _interfaces
 
@@ -40,9 +42,8 @@
 )
 
 
-class _Receiver(object):
+class _Receiver(six.with_metaclass(abc.ABCMeta)):
   """Common specification of different ticket-handling behavior."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def abort_if_abortive(self, ticket):
diff --git a/src/python/grpcio/grpc/framework/base/_transmission.py b/src/python/grpcio/grpc/framework/base/_transmission.py
index 6845129..398faaf 100644
--- a/src/python/grpcio/grpc/framework/base/_transmission.py
+++ b/src/python/grpcio/grpc/framework/base/_transmission.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
 
 import abc
 
+import six
+
 from grpc.framework.base import _constants
 from grpc.framework.base import _interfaces
 from grpc.framework.base import interfaces
@@ -77,9 +79,8 @@
 }
 
 
-class _Ticketizer(object):
+class _Ticketizer(six.with_metaclass(abc.ABCMeta)):
   """Common specification of different ticket-creating behavior."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def ticketize(self, operation_id, sequence_number, payload, complete):
@@ -187,9 +188,8 @@
           operation_id, sequence_number, kind, None)
 
 
-class TransmissionManager(_interfaces.TransmissionManager):
+class TransmissionManager(six.with_metaclass(abc.ABCMeta, _interfaces.TransmissionManager)):
   """A _interfaces.TransmissionManager on which other managers may be set."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def set_ingestion_and_expiration_managers(
diff --git a/src/python/grpcio/grpc/framework/base/interfaces.py b/src/python/grpcio/grpc/framework/base/interfaces.py
index e22c10d..7c58a23 100644
--- a/src/python/grpcio/grpc/framework/base/interfaces.py
+++ b/src/python/grpcio/grpc/framework/base/interfaces.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,8 @@
 import collections
 import enum
 
+import six
+
 # stream is referenced from specification in this module.
 from grpc.framework.foundation import stream  # pylint: disable=unused-import
 
@@ -50,13 +52,12 @@
   SERVICED_FAILURE = 'serviced failure'
 
 
-class OperationContext(object):
+class OperationContext(six.with_metaclass(abc.ABCMeta)):
   """Provides operation-related information and action.
 
   Attributes:
     trace_id: A uuid.UUID identifying a particular set of related operations.
   """
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def is_active(self):
@@ -93,9 +94,8 @@
     raise NotImplementedError()
 
 
-class Servicer(object):
+class Servicer(six.with_metaclass(abc.ABCMeta)):
   """Interface for service implementations."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def service(self, name, context, output_consumer):
@@ -120,7 +120,7 @@
     raise NotImplementedError()
 
 
-class Operation(object):
+class Operation(six.with_metaclass(abc.ABCMeta)):
   """Representation of an in-progress operation.
 
   Attributes:
@@ -129,7 +129,6 @@
     context: An OperationContext affording information and action about the
       operation.
   """
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def cancel(self):
@@ -137,9 +136,8 @@
     raise NotImplementedError()
 
 
-class ServicedIngestor(object):
+class ServicedIngestor(six.with_metaclass(abc.ABCMeta)):
   """Responsible for accepting the result of an operation."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def consumer(self, operation_context):
@@ -159,7 +157,7 @@
     raise NotImplementedError()
 
 
-class ServicedSubscription(object):
+class ServicedSubscription(six.with_metaclass(abc.ABCMeta)):
   """A sum type representing a serviced's interest in an operation.
 
   Attributes:
@@ -167,7 +165,6 @@
     ingestor: A ServicedIngestor. Must be present if kind is Kind.FULL. Must
       be None if kind is Kind.TERMINATION_ONLY or Kind.NONE.
   """
-  __metaclass__ = abc.ABCMeta
 
   @enum.unique
   class Kind(enum.Enum):
@@ -178,9 +175,8 @@
     NONE = 'none'
 
 
-class End(object):
+class End(six.with_metaclass(abc.ABCMeta)):
   """Common type for entry-point objects on both sides of an operation."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def operation_stats(self):
@@ -202,9 +198,8 @@
     raise NotImplementedError()
 
 
-class Front(End):
+class Front(six.with_metaclass(abc.ABCMeta, End)):
   """Clientish objects that afford the invocation of operations."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def operate(
@@ -228,9 +223,8 @@
     raise NotImplementedError()
 
 
-class Back(End):
+class Back(six.with_metaclass(abc.ABCMeta, End)):
   """Serverish objects that perform the work of operations."""
-  __metaclass__ = abc.ABCMeta
 
 
 class FrontToBackTicket(
@@ -315,9 +309,8 @@
     TRANSMISSION_FAILURE = 'transmission failure'
 
 
-class ForeLink(object):
+class ForeLink(six.with_metaclass(abc.ABCMeta)):
   """Accepts back-to-front tickets and emits front-to-back tickets."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def accept_back_to_front_ticket(self, ticket):
@@ -334,9 +327,8 @@
     raise NotImplementedError()
 
 
-class RearLink(object):
+class RearLink(six.with_metaclass(abc.ABCMeta)):
   """Accepts front-to-back tickets and emits back-to-front tickets."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def accept_front_to_back_ticket(self, ticket):
@@ -353,11 +345,9 @@
     raise NotImplementedError()
 
 
-class FrontLink(Front, ForeLink):
+class FrontLink(six.with_metaclass(abc.ABCMeta, Front, ForeLink)):
   """Clientish objects that operate by sending and receiving tickets."""
-  __metaclass__ = abc.ABCMeta
 
 
-class BackLink(Back, RearLink):
+class BackLink(six.with_metaclass(abc.ABCMeta, Back, RearLink)):
   """Serverish objects that operate by sending and receiving tickets."""
-  __metaclass__ = abc.ABCMeta
diff --git a/src/python/grpcio/grpc/framework/core/_end.py b/src/python/grpcio/grpc/framework/core/_end.py
index 9c61567..dc2f485 100644
--- a/src/python/grpcio/grpc/framework/core/_end.py
+++ b/src/python/grpcio/grpc/framework/core/_end.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,8 @@
 import threading
 import uuid
 
+import six
+
 from grpc.framework.core import _operation
 from grpc.framework.core import _utilities
 from grpc.framework.foundation import callable_util
@@ -45,7 +47,7 @@
 _IDLE_ACTION_EXCEPTION_LOG_MESSAGE = 'Exception calling idle action!'
 
 
-class End(base.End, links.Link):
+class End(six.with_metaclass(abc.ABCMeta, base.End, links.Link)):
   """A bridge between base.End and links.Link.
 
   Implementations of this interface translate arriving tickets into
@@ -53,7 +55,6 @@
   translate calls from application objects implementing base interfaces
   into tickets sent to a joined link.
   """
-  __metaclass__ = abc.ABCMeta
 
 
 class _Cycle(object):
diff --git a/src/python/grpcio/grpc/framework/core/_ingestion.py b/src/python/grpcio/grpc/framework/core/_ingestion.py
index 4129a8c..1e1fd73 100644
--- a/src/python/grpcio/grpc/framework/core/_ingestion.py
+++ b/src/python/grpcio/grpc/framework/core/_ingestion.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,8 @@
 import collections
 import enum
 
+import six
+
 from grpc.framework.core import _constants
 from grpc.framework.core import _interfaces
 from grpc.framework.core import _utilities
@@ -70,9 +72,8 @@
     ABANDONED = 'abandoned'
 
 
-class _SubscriptionCreator(object):
+class _SubscriptionCreator(six.with_metaclass(abc.ABCMeta)):
   """Common specification of subscription-creating behavior."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def create(self, group, method):
diff --git a/src/python/grpcio/grpc/framework/core/_interfaces.py b/src/python/grpcio/grpc/framework/core/_interfaces.py
index ffa686b..985e5e8 100644
--- a/src/python/grpcio/grpc/framework/core/_interfaces.py
+++ b/src/python/grpcio/grpc/framework/core/_interfaces.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,17 +31,18 @@
 
 import abc
 
+import six
+
 from grpc.framework.interfaces.base import base
 
 
-class TerminationManager(object):
+class TerminationManager(six.with_metaclass(abc.ABCMeta)):
   """An object responsible for handling the termination of an operation.
 
   Attributes:
     outcome: None if the operation is active or a base.Outcome value if it has
       terminated.
   """
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def add_callback(self, callback):
@@ -105,9 +106,8 @@
     raise NotImplementedError()
 
 
-class TransmissionManager(object):
+class TransmissionManager(six.with_metaclass(abc.ABCMeta)):
   """A manager responsible for transmitting to the other end of an operation."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def kick_off(
@@ -171,9 +171,8 @@
     raise NotImplementedError()
 
 
-class ExpirationManager(object):
+class ExpirationManager(six.with_metaclass(abc.ABCMeta)):
   """A manager responsible for aborting the operation if it runs out of time."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def change_timeout(self, timeout):
@@ -203,9 +202,8 @@
     raise NotImplementedError()
 
 
-class ProtocolManager(object):
+class ProtocolManager(six.with_metaclass(abc.ABCMeta)):
   """A manager of protocol-specific values passing through an operation."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def set_protocol_receiver(self, protocol_receiver):
@@ -228,9 +226,8 @@
     raise NotImplementedError()
 
 
-class EmissionManager(base.Operator):
+class EmissionManager(six.with_metaclass(abc.ABCMeta, base.Operator)):
   """A manager of values emitted by customer code."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def advance(
@@ -254,14 +251,13 @@
     raise NotImplementedError()
 
 
-class IngestionManager(object):
+class IngestionManager(six.with_metaclass(abc.ABCMeta)):
   """A manager responsible for executing customer code.
 
   This name of this manager comes from its responsibility to pass successive
   values from the other side of the operation into the code of the local
   customer.
   """
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def set_group_and_method(self, group, method):
@@ -294,9 +290,8 @@
     raise NotImplementedError()
 
 
-class ReceptionManager(object):
+class ReceptionManager(six.with_metaclass(abc.ABCMeta)):
   """A manager responsible for receiving tickets from the other end."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def receive_ticket(self, ticket):
@@ -308,7 +303,7 @@
     raise NotImplementedError()
 
 
-class Operation(object):
+class Operation(six.with_metaclass(abc.ABCMeta)):
   """An ongoing operation.
 
   Attributes:
@@ -316,7 +311,6 @@
     operator: A base.Operator object for the operation for use by the customer
       of the operation.
   """
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def handle_ticket(self, ticket):
diff --git a/src/python/grpcio/grpc/framework/core/_termination.py b/src/python/grpcio/grpc/framework/core/_termination.py
index 364158b..e8c4ec6 100644
--- a/src/python/grpcio/grpc/framework/core/_termination.py
+++ b/src/python/grpcio/grpc/framework/core/_termination.py
@@ -31,6 +31,8 @@
 
 import abc
 
+import six
+
 from grpc.framework.core import _constants
 from grpc.framework.core import _interfaces
 from grpc.framework.core import _utilities
@@ -50,9 +52,8 @@
   return transmission_complete and ingestion_complete
 
 
-class TerminationManager(_interfaces.TerminationManager):
+class TerminationManager(six.with_metaclass(abc.ABCMeta, _interfaces.TerminationManager)):
   """A _interfaces.TransmissionManager on which another manager may be set."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def set_expiration_manager(self, expiration_manager):
diff --git a/src/python/grpcio/grpc/framework/crust/_control.py b/src/python/grpcio/grpc/framework/crust/_control.py
index 5e9efdf..c27fc91 100644
--- a/src/python/grpcio/grpc/framework/crust/_control.py
+++ b/src/python/grpcio/grpc/framework/crust/_control.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -405,6 +405,9 @@
   def __iter__(self):
     return self
 
+  def __next__(self):
+    return self.next()
+
   def next(self):
     with self._condition:
       while True:
diff --git a/src/python/grpcio/grpc/framework/crust/implementations.py b/src/python/grpcio/grpc/framework/crust/implementations.py
index 4ebc4e9..d0ecafc 100644
--- a/src/python/grpcio/grpc/framework/crust/implementations.py
+++ b/src/python/grpcio/grpc/framework/crust/implementations.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,6 +29,8 @@
 
 """Entry points into the Crust layer of RPC Framework."""
 
+import six
+
 from grpc.framework.common import cardinality
 from grpc.framework.common import style
 from grpc.framework.crust import _calls
@@ -271,7 +273,7 @@
 
 def _adapt_method_implementations(method_implementations, pool):
   adapted_implementations = {}
-  for name, method_implementation in method_implementations.iteritems():
+  for name, method_implementation in six.iteritems(method_implementations):
     if method_implementation.style is style.Service.INLINE:
       if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
         adapted_implementations[name] = _service.adapt_inline_unary_unary(
diff --git a/src/python/grpcio/grpc/framework/face/_control.py b/src/python/grpcio/grpc/framework/face/_control.py
index e918907..ec43203 100644
--- a/src/python/grpcio/grpc/framework/face/_control.py
+++ b/src/python/grpcio/grpc/framework/face/_control.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -120,6 +120,9 @@
   def __iter__(self):
     return self
 
+  def __next__(self):
+    return self.next()
+
   def next(self):
     with self._condition:
       while ((self._abortion is None) and
diff --git a/src/python/grpcio/grpc/framework/face/exceptions.py b/src/python/grpcio/grpc/framework/face/exceptions.py
index f112df7..c272ac7 100644
--- a/src/python/grpcio/grpc/framework/face/exceptions.py
+++ b/src/python/grpcio/grpc/framework/face/exceptions.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
 
 import abc
 
+import six
+
 
 class NoSuchMethodError(Exception):
   """Raised by customer code to indicate an unrecognized RPC method name.
@@ -49,12 +51,11 @@
     self.name = name
 
 
-class RpcError(Exception):
+class RpcError(six.with_metaclass(abc.ABCMeta, Exception)):
   """Common super type for all exceptions raised by the Face layer.
 
   Only RPC Framework should instantiate and raise these exceptions.
   """
-  __metaclass__ = abc.ABCMeta
 
 
 class CancellationError(RpcError):
diff --git a/src/python/grpcio/grpc/framework/face/implementations.py b/src/python/grpcio/grpc/framework/face/implementations.py
index 4a6de52..9c75a5f 100644
--- a/src/python/grpcio/grpc/framework/face/implementations.py
+++ b/src/python/grpcio/grpc/framework/face/implementations.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,6 +29,8 @@
 
 """Entry points into the Face layer of RPC Framework."""
 
+import six
+
 from grpc.framework.common import cardinality
 from grpc.framework.common import style
 from grpc.framework.base import exceptions as _base_exceptions
@@ -228,7 +230,7 @@
 
 def _adapt_method_implementations(method_implementations, pool):
   adapted_implementations = {}
-  for name, method_implementation in method_implementations.iteritems():
+  for name, method_implementation in six.iteritems(method_implementations):
     if method_implementation.style is style.Service.INLINE:
       if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
         adapted_implementations[name] = _service.adapt_inline_value_in_value_out(
diff --git a/src/python/grpcio/grpc/framework/face/interfaces.py b/src/python/grpcio/grpc/framework/face/interfaces.py
index b7cc4c1..9fc18d7 100644
--- a/src/python/grpcio/grpc/framework/face/interfaces.py
+++ b/src/python/grpcio/grpc/framework/face/interfaces.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,8 @@
 import abc
 import enum
 
+import six
+
 # cardinality, style, exceptions, abandonment, future, and stream are
 # referenced from specification in this module.
 from grpc.framework.common import cardinality  # pylint: disable=unused-import
@@ -52,15 +54,17 @@
   SERVICER_FAILURE = 'servicer failure'
 
 
-class CancellableIterator(object):
+class CancellableIterator(six.with_metaclass(abc.ABCMeta)):
   """Implements the Iterator protocol and affords a cancel method."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __iter__(self):
     """Returns the self object in accordance with the Iterator protocol."""
     raise NotImplementedError()
 
+  def __next__(self):
+    return self.next()
+
   @abc.abstractmethod
   def next(self):
     """Returns a value or raises StopIteration per the Iterator protocol."""
@@ -72,9 +76,8 @@
     raise NotImplementedError()
 
 
-class RpcContext(object):
+class RpcContext(six.with_metaclass(abc.ABCMeta)):
   """Provides RPC-related information and action."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def is_active(self):
@@ -103,13 +106,12 @@
     raise NotImplementedError()
 
 
-class Call(object):
+class Call(six.with_metaclass(abc.ABCMeta)):
   """Invocation-side representation of an RPC.
 
   Attributes:
     context: An RpcContext affording information about the RPC.
   """
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def cancel(self):
@@ -117,9 +119,8 @@
     raise NotImplementedError()
 
 
-class UnaryUnaryMultiCallable(object):
+class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
   """Affords invoking a unary-unary RPC in any call style."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __call__(self, request, timeout):
@@ -171,9 +172,8 @@
     raise NotImplementedError()
 
 
-class UnaryStreamMultiCallable(object):
+class UnaryStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
   """Affords invoking a unary-stream RPC in any call style."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __call__(self, request, timeout):
@@ -209,9 +209,8 @@
     raise NotImplementedError()
 
 
-class StreamUnaryMultiCallable(object):
+class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
   """Affords invoking a stream-unary RPC in any call style."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __call__(self, request_iterator, timeout):
@@ -264,9 +263,8 @@
     raise NotImplementedError()
 
 
-class StreamStreamMultiCallable(object):
+class StreamStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
   """Affords invoking a stream-stream RPC in any call style."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __call__(self, request_iterator, timeout):
@@ -302,7 +300,7 @@
     raise NotImplementedError()
 
 
-class MethodImplementation(object):
+class MethodImplementation(six.with_metaclass(abc.ABCMeta)):
   """A sum type that describes an RPC method implementation.
 
   Attributes:
@@ -347,12 +345,10 @@
       is cardinality.Cardinality.STREAM_STREAM and style is
       style.Service.EVENT.
   """
-  __metaclass__ = abc.ABCMeta
 
 
-class MultiMethodImplementation(object):
+class MultiMethodImplementation(six.with_metaclass(abc.ABCMeta)):
   """A general type able to service many RPC methods."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def service(self, name, response_consumer, context):
@@ -381,9 +377,8 @@
     raise NotImplementedError()
 
 
-class GenericStub(object):
+class GenericStub(six.with_metaclass(abc.ABCMeta)):
   """Affords RPC methods to callers."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def blocking_value_in_value_out(self, name, request, timeout):
@@ -622,7 +617,7 @@
     raise NotImplementedError()
 
 
-class DynamicStub(object):
+class DynamicStub(six.with_metaclass(abc.ABCMeta)):
   """A stub with RPC-method-bound multi-callable attributes.
 
   Instances of this type responsd to attribute access as follows: if the
@@ -637,4 +632,3 @@
   the attribute will be a StreamStreamMultiCallable with which to invoke the
   RPC method.
   """
-  __metaclass__ = abc.ABCMeta
diff --git a/src/python/grpcio/grpc/framework/foundation/activated.py b/src/python/grpcio/grpc/framework/foundation/activated.py
index 426a71c..9b49b63 100644
--- a/src/python/grpcio/grpc/framework/foundation/activated.py
+++ b/src/python/grpcio/grpc/framework/foundation/activated.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,14 +31,14 @@
 
 import abc
 
+import six
 
-class Activated(object):
+class Activated(six.with_metaclass(abc.ABCMeta)):
   """Interface for objects that may be started and stopped.
 
   Values implementing this type must also implement the context manager
   protocol.
   """
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __enter__(self):
diff --git a/src/python/grpcio/grpc/framework/foundation/callable_util.py b/src/python/grpcio/grpc/framework/foundation/callable_util.py
index 32b0751..e0a4cab 100644
--- a/src/python/grpcio/grpc/framework/foundation/callable_util.py
+++ b/src/python/grpcio/grpc/framework/foundation/callable_util.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,10 @@
 import functools
 import logging
 
+import six
 
-class Outcome(object):
+
+class Outcome(six.with_metaclass(abc.ABCMeta)):
   """A sum type describing the outcome of some call.
 
   Attributes:
@@ -47,7 +49,6 @@
     exception: The exception raised by the call. Must be present if kind is
       Kind.RAISED.
   """
-  __metaclass__ = abc.ABCMeta
 
   @enum.unique
   class Kind(enum.Enum):
diff --git a/src/python/grpcio/grpc/framework/foundation/future.py b/src/python/grpcio/grpc/framework/foundation/future.py
index bfc16fc..bb8ee3a 100644
--- a/src/python/grpcio/grpc/framework/foundation/future.py
+++ b/src/python/grpcio/grpc/framework/foundation/future.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,8 @@
 
 import abc
 
+import six
+
 
 class TimeoutError(Exception):
   """Indicates that a particular call timed out."""
@@ -58,13 +60,12 @@
   """Indicates that the computation underlying a Future was cancelled."""
 
 
-class Future(object):
+class Future(six.with_metaclass(abc.ABCMeta)):
   """A representation of a computation in another control flow.
 
   Computations represented by a Future may be yet to be begun, may be ongoing,
   or may have already completed.
   """
-  __metaclass__ = abc.ABCMeta
 
   # NOTE(nathaniel): This isn't the return type that I would want to have if it
   # were up to me. Were this interface being written from scratch, the return
diff --git a/src/python/grpcio/grpc/framework/foundation/relay.py b/src/python/grpcio/grpc/framework/foundation/relay.py
index 9c23946..ff4e227 100644
--- a/src/python/grpcio/grpc/framework/foundation/relay.py
+++ b/src/python/grpcio/grpc/framework/foundation/relay.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,6 @@
   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):
diff --git a/src/python/grpcio/grpc/framework/foundation/stream.py b/src/python/grpcio/grpc/framework/foundation/stream.py
index 75c0cf1..32a2e52 100644
--- a/src/python/grpcio/grpc/framework/foundation/stream.py
+++ b/src/python/grpcio/grpc/framework/foundation/stream.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,10 +31,10 @@
 
 import abc
 
+import six
 
-class Consumer(object):
+class Consumer(six.with_metaclass(abc.ABCMeta)):
   """Interface for consumers of finite streams of values or objects."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def consume(self, value):
diff --git a/src/python/grpcio/grpc/framework/foundation/stream_util.py b/src/python/grpcio/grpc/framework/foundation/stream_util.py
index 2210e4e..7d5977f 100644
--- a/src/python/grpcio/grpc/framework/foundation/stream_util.py
+++ b/src/python/grpcio/grpc/framework/foundation/stream_util.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -83,6 +83,9 @@
   def __iter__(self):
     return self
 
+  def __next__(self):
+    return self.next()
+
   def next(self):
     with self._condition:
       while self._active and not self._values:
diff --git a/src/python/grpcio/grpc/framework/interfaces/base/base.py b/src/python/grpcio/grpc/framework/interfaces/base/base.py
index a1e70be..69be37e 100644
--- a/src/python/grpcio/grpc/framework/interfaces/base/base.py
+++ b/src/python/grpcio/grpc/framework/interfaces/base/base.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,8 @@
 import enum
 import threading  # pylint: disable=unused-import
 
+import six
+
 # abandonment is referenced from specification in this module.
 from grpc.framework.foundation import abandonment  # pylint: disable=unused-import
 
@@ -95,7 +97,7 @@
     REMOTE_FAILURE = 'remote failure'
 
 
-class Completion(object):
+class Completion(six.with_metaclass(abc.ABCMeta)):
   """An aggregate of the values exchanged upon operation completion.
 
   Attributes:
@@ -103,12 +105,10 @@
     code: A code value for the operation.
     message: A message value for the operation.
   """
-  __metaclass__ = abc.ABCMeta
 
 
-class OperationContext(object):
+class OperationContext(six.with_metaclass(abc.ABCMeta)):
   """Provides operation-related information and action."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def outcome(self):
@@ -162,9 +162,8 @@
     raise NotImplementedError()
 
 
-class Operator(object):
+class Operator(six.with_metaclass(abc.ABCMeta)):
   """An interface through which to participate in an operation."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def advance(
@@ -184,9 +183,8 @@
     """
     raise NotImplementedError()
 
-class ProtocolReceiver(object):
+class ProtocolReceiver(six.with_metaclass(abc.ABCMeta)):
   """A means of receiving protocol values during an operation."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def context(self, protocol_context):
@@ -198,7 +196,7 @@
     raise NotImplementedError()
 
 
-class Subscription(object):
+class Subscription(six.with_metaclass(abc.ABCMeta)):
   """Describes customer code's interest in values from the other side.
 
   Attributes:
@@ -216,7 +214,6 @@
       become available during the operation. Must be non-None if kind is
       Kind.FULL.
   """
-  __metaclass__ = abc.ABCMeta
 
   @enum.unique
   class Kind(enum.Enum):
@@ -226,9 +223,8 @@
     FULL = 'full'
 
 
-class Servicer(object):
+class Servicer(six.with_metaclass(abc.ABCMeta)):
   """Interface for service implementations."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def service(self, group, method, context, output_operator):
@@ -255,9 +251,8 @@
     raise NotImplementedError()
 
 
-class End(object):
+class End(six.with_metaclass(abc.ABCMeta)):
   """Common type for entry-point objects on both sides of an operation."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def start(self):
diff --git a/src/python/grpcio/grpc/framework/interfaces/face/face.py b/src/python/grpcio/grpc/framework/interfaces/face/face.py
index 404c3a7..b994ace 100644
--- a/src/python/grpcio/grpc/framework/interfaces/face/face.py
+++ b/src/python/grpcio/grpc/framework/interfaces/face/face.py
@@ -33,6 +33,8 @@
 import collections
 import enum
 
+import six
+
 # cardinality, style, abandonment, future, and stream are
 # referenced from specification in this module.
 from grpc.framework.common import cardinality  # pylint: disable=unused-import
@@ -96,7 +98,7 @@
     REMOTE_FAILURE = 'remote failure'
 
 
-class AbortionError(Exception):
+class AbortionError(six.with_metaclass(abc.ABCMeta, Exception)):
   """Common super type for exceptions indicating RPC abortion.
 
     initial_metadata: The initial metadata from the other side of the RPC or
@@ -108,7 +110,6 @@
     details: The details value from the other side of the RPC or None if no
       details value was received.
   """
-  __metaclass__ = abc.ABCMeta
 
   def __init__(self, initial_metadata, terminal_metadata, code, details):
     super(AbortionError, self).__init__()
@@ -150,9 +151,8 @@
   """Indicates that an RPC has terminated due to a remote defect."""
 
 
-class RpcContext(object):
+class RpcContext(six.with_metaclass(abc.ABCMeta)):
   """Provides RPC-related information and action."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def is_active(self):
@@ -199,9 +199,8 @@
     raise NotImplementedError()
 
 
-class Call(RpcContext):
+class Call(six.with_metaclass(abc.ABCMeta, RpcContext)):
   """Invocation-side utility object for an RPC."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def initial_metadata(self):
@@ -256,9 +255,8 @@
     raise NotImplementedError()
 
 
-class ServicerContext(RpcContext):
+class ServicerContext(six.with_metaclass(abc.ABCMeta, RpcContext)):
   """A context object passed to method implementations."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def invocation_metadata(self):
@@ -326,9 +324,8 @@
     raise NotImplementedError()
 
 
-class ResponseReceiver(object):
+class ResponseReceiver(six.with_metaclass(abc.ABCMeta)):
   """Invocation-side object used to accept the output of an RPC."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def initial_metadata(self, initial_metadata):
@@ -362,9 +359,8 @@
     raise NotImplementedError()
 
 
-class UnaryUnaryMultiCallable(object):
+class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
   """Affords invoking a unary-unary RPC in any call style."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __call__(
@@ -434,9 +430,8 @@
     raise NotImplementedError()
 
 
-class UnaryStreamMultiCallable(object):
+class UnaryStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
   """Affords invoking a unary-stream RPC in any call style."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __call__(self, request, timeout, metadata=None, protocol_options=None):
@@ -480,9 +475,8 @@
     raise NotImplementedError()
 
 
-class StreamUnaryMultiCallable(object):
+class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
   """Affords invoking a stream-unary RPC in any call style."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __call__(
@@ -553,9 +547,8 @@
     raise NotImplementedError()
 
 
-class StreamStreamMultiCallable(object):
+class StreamStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
   """Affords invoking a stream-stream RPC in any call style."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def __call__(
@@ -600,7 +593,7 @@
     raise NotImplementedError()
 
 
-class MethodImplementation(object):
+class MethodImplementation(six.with_metaclass(abc.ABCMeta)):
   """A sum type that describes a method implementation.
 
   Attributes:
@@ -643,12 +636,10 @@
       is cardinality.Cardinality.STREAM_STREAM and style is
       style.Service.EVENT.
   """
-  __metaclass__ = abc.ABCMeta
 
 
-class MultiMethodImplementation(object):
+class MultiMethodImplementation(six.with_metaclass(abc.ABCMeta)):
   """A general type able to service many methods."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def service(self, group, method, response_consumer, context):
@@ -678,9 +669,8 @@
     raise NotImplementedError()
 
 
-class GenericStub(object):
+class GenericStub(six.with_metaclass(abc.ABCMeta)):
   """Affords RPC invocation via generic methods."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def blocking_unary_unary(
@@ -977,7 +967,7 @@
     raise NotImplementedError()
 
 
-class DynamicStub(object):
+class DynamicStub(six.with_metaclass(abc.ABCMeta)):
   """Affords RPC invocation via attributes corresponding to afforded methods.
 
   Instances of this type may be scoped to a single group so that attribute
@@ -993,4 +983,3 @@
   if the requested attribute is the name of a stream-stream method, the value of
   the attribute will be a StreamStreamMultiCallable with which to invoke an RPC.
   """
-  __metaclass__ = abc.ABCMeta
diff --git a/src/python/grpcio/grpc/framework/interfaces/links/links.py b/src/python/grpcio/grpc/framework/interfaces/links/links.py
index 24f0e3b..8081679 100644
--- a/src/python/grpcio/grpc/framework/interfaces/links/links.py
+++ b/src/python/grpcio/grpc/framework/interfaces/links/links.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,8 @@
 import collections
 import enum
 
+import six
+
 
 class Protocol(collections.namedtuple('Protocol', ('kind', 'value',))):
   """A sum type for handles to a system that transmits tickets.
@@ -123,9 +125,8 @@
     REMOTE_FAILURE = 'remote failure'
 
 
-class Link(object):
+class Link(six.with_metaclass(abc.ABCMeta)):
   """Accepts and emits tickets."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def accept_ticket(self, ticket):
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index a543791..3c57ad7 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -30,206 +30,211 @@
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_core_dependencies.py.template`!!!
 
 CORE_SOURCE_FILES = [
-  'src/core/profiling/basic_timers.c',
-  'src/core/profiling/stap_timers.c',
-  'src/core/support/alloc.c',
-  'src/core/support/avl.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/histogram.c',
-  'src/core/support/host_port.c',
-  'src/core/support/load_file.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/subprocess_windows.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_precise.c',
-  'src/core/support/time_win32.c',
-  'src/core/support/tls_pthread.c',
-  'src/core/support/tmpfile_posix.c',
-  'src/core/support/tmpfile_win32.c',
-  'src/core/support/wrap_memcpy.c',
-  'src/core/census/grpc_context.c',
-  'src/core/census/grpc_filter.c',
-  'src/core/channel/channel_args.c',
-  'src/core/channel/channel_stack.c',
-  'src/core/channel/client_channel.c',
-  'src/core/channel/client_uchannel.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/subchannel_call_holder.c',
-  'src/core/client_config/client_config.c',
-  'src/core/client_config/connector.c',
-  'src/core/client_config/default_initial_connect_string.c',
-  'src/core/client_config/initial_connect_string.c',
-  'src/core/client_config/lb_policies/load_balancer_api.c',
-  'src/core/client_config/lb_policies/pick_first.c',
-  'src/core/client_config/lb_policies/round_robin.c',
-  'src/core/client_config/lb_policy.c',
-  'src/core/client_config/lb_policy_factory.c',
-  'src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c',
-  'src/core/client_config/subchannel.c',
-  'src/core/client_config/subchannel_factory.c',
-  'src/core/client_config/subchannel_index.c',
-  'src/core/client_config/uri_parser.c',
-  'src/core/compression/compression_algorithm.c',
-  'src/core/compression/message_compress.c',
-  'src/core/debug/trace.c',
-  'src/core/httpcli/format_request.c',
-  'src/core/httpcli/httpcli.c',
-  'src/core/httpcli/parser.c',
-  'src/core/iomgr/closure.c',
-  'src/core/iomgr/endpoint.c',
-  'src/core/iomgr/endpoint_pair_posix.c',
-  'src/core/iomgr/endpoint_pair_windows.c',
-  'src/core/iomgr/exec_ctx.c',
-  'src/core/iomgr/executor.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_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/timer.c',
-  'src/core/iomgr/timer_heap.c',
-  'src/core/iomgr/udp_server.c',
-  'src/core/iomgr/wakeup_fd_eventfd.c',
-  'src/core/iomgr/wakeup_fd_nospecial.c',
-  'src/core/iomgr/wakeup_fd_pipe.c',
-  'src/core/iomgr/wakeup_fd_posix.c',
-  'src/core/iomgr/workqueue_posix.c',
-  'src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c',
-  'src/core/surface/alarm.c',
-  'src/core/surface/api_trace.c',
-  'src/core/surface/byte_buffer.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_connectivity.c',
-  'src/core/surface/channel_create.c',
-  'src/core/surface/channel_ping.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/validate_metadata.c',
-  'src/core/surface/version.c',
-  'src/core/transport/byte_stream.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_encoder.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_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/metadata_batch.c',
-  'src/core/transport/static_metadata.c',
-  'src/core/transport/transport.c',
-  'src/core/transport/transport_op_string.c',
-  'src/core/httpcli/httpcli_security_connector.c',
-  'src/core/security/b64.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/handshake.c',
-  'src/core/security/json_token.c',
-  'src/core/security/jwt_verifier.c',
-  'src/core/security/secure_endpoint.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/context.c',
-  'src/core/census/initialize.c',
-  'src/core/census/mlog.c',
-  'src/core/census/operation.c',
-  'src/core/census/placeholders.c',
-  'src/core/census/tracing.c',
+  'src/core/lib/profiling/basic_timers.c',
+  'src/core/lib/profiling/stap_timers.c',
+  'src/core/lib/support/alloc.c',
+  'src/core/lib/support/avl.c',
+  'src/core/lib/support/backoff.c',
+  'src/core/lib/support/cmdline.c',
+  'src/core/lib/support/cpu_iphone.c',
+  'src/core/lib/support/cpu_linux.c',
+  'src/core/lib/support/cpu_posix.c',
+  'src/core/lib/support/cpu_windows.c',
+  'src/core/lib/support/env_linux.c',
+  'src/core/lib/support/env_posix.c',
+  'src/core/lib/support/env_win32.c',
+  'src/core/lib/support/histogram.c',
+  'src/core/lib/support/host_port.c',
+  'src/core/lib/support/load_file.c',
+  'src/core/lib/support/log.c',
+  'src/core/lib/support/log_android.c',
+  'src/core/lib/support/log_linux.c',
+  'src/core/lib/support/log_posix.c',
+  'src/core/lib/support/log_win32.c',
+  'src/core/lib/support/murmur_hash.c',
+  'src/core/lib/support/slice.c',
+  'src/core/lib/support/slice_buffer.c',
+  'src/core/lib/support/stack_lockfree.c',
+  'src/core/lib/support/string.c',
+  'src/core/lib/support/string_posix.c',
+  'src/core/lib/support/string_win32.c',
+  'src/core/lib/support/subprocess_posix.c',
+  'src/core/lib/support/subprocess_windows.c',
+  'src/core/lib/support/sync.c',
+  'src/core/lib/support/sync_posix.c',
+  'src/core/lib/support/sync_win32.c',
+  'src/core/lib/support/thd.c',
+  'src/core/lib/support/thd_posix.c',
+  'src/core/lib/support/thd_win32.c',
+  'src/core/lib/support/time.c',
+  'src/core/lib/support/time_posix.c',
+  'src/core/lib/support/time_precise.c',
+  'src/core/lib/support/time_win32.c',
+  'src/core/lib/support/tls_pthread.c',
+  'src/core/lib/support/tmpfile_posix.c',
+  'src/core/lib/support/tmpfile_win32.c',
+  'src/core/lib/support/wrap_memcpy.c',
+  'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
+  'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
+  'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
+  'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c',
+  'src/core/ext/transport/chttp2/transport/alpn.c',
+  'src/core/ext/transport/chttp2/transport/bin_encoder.c',
+  'src/core/ext/transport/chttp2/transport/chttp2_transport.c',
+  'src/core/ext/transport/chttp2/transport/frame_data.c',
+  'src/core/ext/transport/chttp2/transport/frame_goaway.c',
+  'src/core/ext/transport/chttp2/transport/frame_ping.c',
+  'src/core/ext/transport/chttp2/transport/frame_rst_stream.c',
+  'src/core/ext/transport/chttp2/transport/frame_settings.c',
+  'src/core/ext/transport/chttp2/transport/frame_window_update.c',
+  'src/core/ext/transport/chttp2/transport/hpack_encoder.c',
+  'src/core/ext/transport/chttp2/transport/hpack_parser.c',
+  'src/core/ext/transport/chttp2/transport/hpack_table.c',
+  'src/core/ext/transport/chttp2/transport/huffsyms.c',
+  'src/core/ext/transport/chttp2/transport/incoming_metadata.c',
+  'src/core/ext/transport/chttp2/transport/parsing.c',
+  'src/core/ext/transport/chttp2/transport/status_conversion.c',
+  'src/core/ext/transport/chttp2/transport/stream_lists.c',
+  'src/core/ext/transport/chttp2/transport/stream_map.c',
+  'src/core/ext/transport/chttp2/transport/timeout_encoding.c',
+  'src/core/ext/transport/chttp2/transport/varint.c',
+  'src/core/ext/transport/chttp2/transport/writing.c',
+  'src/core/lib/census/context.c',
+  'src/core/lib/census/grpc_context.c',
+  'src/core/lib/census/grpc_filter.c',
+  'src/core/lib/census/grpc_plugin.c',
+  'src/core/lib/census/initialize.c',
+  'src/core/lib/census/mlog.c',
+  'src/core/lib/census/operation.c',
+  'src/core/lib/census/placeholders.c',
+  'src/core/lib/census/tracing.c',
+  'src/core/lib/channel/channel_args.c',
+  'src/core/lib/channel/channel_stack.c',
+  'src/core/lib/channel/channel_stack_builder.c',
+  'src/core/lib/channel/client_channel.c',
+  'src/core/lib/channel/compress_filter.c',
+  'src/core/lib/channel/connected_channel.c',
+  'src/core/lib/channel/http_client_filter.c',
+  'src/core/lib/channel/http_server_filter.c',
+  'src/core/lib/channel/subchannel_call_holder.c',
+  'src/core/lib/client_config/client_config.c',
+  'src/core/lib/client_config/connector.c',
+  'src/core/lib/client_config/default_initial_connect_string.c',
+  'src/core/lib/client_config/initial_connect_string.c',
+  'src/core/lib/client_config/lb_policies/load_balancer_api.c',
+  'src/core/lib/client_config/lb_policies/pick_first.c',
+  'src/core/lib/client_config/lb_policies/round_robin.c',
+  'src/core/lib/client_config/lb_policy.c',
+  'src/core/lib/client_config/lb_policy_factory.c',
+  'src/core/lib/client_config/lb_policy_registry.c',
+  'src/core/lib/client_config/resolver.c',
+  'src/core/lib/client_config/resolver_factory.c',
+  'src/core/lib/client_config/resolver_registry.c',
+  'src/core/lib/client_config/resolvers/dns_resolver.c',
+  'src/core/lib/client_config/resolvers/sockaddr_resolver.c',
+  'src/core/lib/client_config/subchannel.c',
+  'src/core/lib/client_config/subchannel_factory.c',
+  'src/core/lib/client_config/subchannel_index.c',
+  'src/core/lib/client_config/uri_parser.c',
+  'src/core/lib/compression/compression_algorithm.c',
+  'src/core/lib/compression/message_compress.c',
+  'src/core/lib/debug/trace.c',
+  'src/core/lib/http/format_request.c',
+  'src/core/lib/http/httpcli.c',
+  'src/core/lib/http/httpcli_security_connector.c',
+  'src/core/lib/http/parser.c',
+  'src/core/lib/iomgr/closure.c',
+  'src/core/lib/iomgr/endpoint.c',
+  'src/core/lib/iomgr/endpoint_pair_posix.c',
+  'src/core/lib/iomgr/endpoint_pair_windows.c',
+  'src/core/lib/iomgr/exec_ctx.c',
+  'src/core/lib/iomgr/executor.c',
+  'src/core/lib/iomgr/fd_posix.c',
+  'src/core/lib/iomgr/iocp_windows.c',
+  'src/core/lib/iomgr/iomgr.c',
+  'src/core/lib/iomgr/iomgr_posix.c',
+  'src/core/lib/iomgr/iomgr_windows.c',
+  'src/core/lib/iomgr/pollset_multipoller_with_epoll.c',
+  'src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c',
+  'src/core/lib/iomgr/pollset_posix.c',
+  'src/core/lib/iomgr/pollset_set_posix.c',
+  'src/core/lib/iomgr/pollset_set_windows.c',
+  'src/core/lib/iomgr/pollset_windows.c',
+  'src/core/lib/iomgr/resolve_address_posix.c',
+  'src/core/lib/iomgr/resolve_address_windows.c',
+  'src/core/lib/iomgr/sockaddr_utils.c',
+  'src/core/lib/iomgr/socket_utils_common_posix.c',
+  'src/core/lib/iomgr/socket_utils_linux.c',
+  'src/core/lib/iomgr/socket_utils_posix.c',
+  'src/core/lib/iomgr/socket_windows.c',
+  'src/core/lib/iomgr/tcp_client_posix.c',
+  'src/core/lib/iomgr/tcp_client_windows.c',
+  'src/core/lib/iomgr/tcp_posix.c',
+  'src/core/lib/iomgr/tcp_server_posix.c',
+  'src/core/lib/iomgr/tcp_server_windows.c',
+  'src/core/lib/iomgr/tcp_windows.c',
+  'src/core/lib/iomgr/time_averaged_stats.c',
+  'src/core/lib/iomgr/timer.c',
+  'src/core/lib/iomgr/timer_heap.c',
+  'src/core/lib/iomgr/udp_server.c',
+  'src/core/lib/iomgr/unix_sockets_posix.c',
+  'src/core/lib/iomgr/unix_sockets_posix_noop.c',
+  'src/core/lib/iomgr/wakeup_fd_eventfd.c',
+  'src/core/lib/iomgr/wakeup_fd_nospecial.c',
+  'src/core/lib/iomgr/wakeup_fd_pipe.c',
+  'src/core/lib/iomgr/wakeup_fd_posix.c',
+  'src/core/lib/iomgr/workqueue_posix.c',
+  'src/core/lib/iomgr/workqueue_windows.c',
+  'src/core/lib/json/json.c',
+  'src/core/lib/json/json_reader.c',
+  'src/core/lib/json/json_string.c',
+  'src/core/lib/json/json_writer.c',
+  'src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c',
+  'src/core/lib/security/b64.c',
+  'src/core/lib/security/client_auth_filter.c',
+  'src/core/lib/security/credentials.c',
+  'src/core/lib/security/credentials_metadata.c',
+  'src/core/lib/security/credentials_posix.c',
+  'src/core/lib/security/credentials_win32.c',
+  'src/core/lib/security/google_default_credentials.c',
+  'src/core/lib/security/handshake.c',
+  'src/core/lib/security/json_token.c',
+  'src/core/lib/security/jwt_verifier.c',
+  'src/core/lib/security/secure_endpoint.c',
+  'src/core/lib/security/security_connector.c',
+  'src/core/lib/security/security_context.c',
+  'src/core/lib/security/server_auth_filter.c',
+  'src/core/lib/surface/alarm.c',
+  'src/core/lib/surface/api_trace.c',
+  'src/core/lib/surface/byte_buffer.c',
+  'src/core/lib/surface/byte_buffer_reader.c',
+  'src/core/lib/surface/call.c',
+  'src/core/lib/surface/call_details.c',
+  'src/core/lib/surface/call_log_batch.c',
+  'src/core/lib/surface/channel.c',
+  'src/core/lib/surface/channel_connectivity.c',
+  'src/core/lib/surface/channel_init.c',
+  'src/core/lib/surface/channel_ping.c',
+  'src/core/lib/surface/channel_stack_type.c',
+  'src/core/lib/surface/completion_queue.c',
+  'src/core/lib/surface/event_string.c',
+  'src/core/lib/surface/init.c',
+  'src/core/lib/surface/init_secure.c',
+  'src/core/lib/surface/lame_client.c',
+  'src/core/lib/surface/metadata_array.c',
+  'src/core/lib/surface/server.c',
+  'src/core/lib/surface/validate_metadata.c',
+  'src/core/lib/surface/version.c',
+  'src/core/lib/transport/byte_stream.c',
+  'src/core/lib/transport/connectivity_state.c',
+  'src/core/lib/transport/metadata.c',
+  'src/core/lib/transport/metadata_batch.c',
+  'src/core/lib/transport/static_metadata.c',
+  'src/core/lib/transport/transport.c',
+  'src/core/lib/transport/transport_op_string.c',
+  'src/core/lib/tsi/fake_transport_security.c',
+  'src/core/lib/tsi/ssl_transport_security.c',
+  'src/core/lib/tsi/transport_security.c',
   'third_party/nanopb/pb_common.c',
   'third_party/nanopb/pb_decode.c',
   'third_party/nanopb/pb_encode.c',
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index db23de2..75b88cf 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
 
-VERSION='0.13.1rc1'
+VERSION='0.14.0.dev0'
diff --git a/src/python/grpcio/precompiled.py b/src/python/grpcio/precompiled.py
index d34250b..aeeb275 100644
--- a/src/python/grpcio/precompiled.py
+++ b/src/python/grpcio/precompiled.py
@@ -91,6 +91,9 @@
 
 
 def update_setup_arguments(setup_arguments):
+  if not USE_PRECOMPILED_BINARIES:
+    sys.stderr.write('not using precompiled extension')
+    return
   url = '{}/{}.so'.format(BINARIES_REPOSITORY, _tagged_ext_name('cygrpc'))
   target_path = os.path.join(PYTHON_STEM, 'grpc/_cython/cygrpc.so')
   try:
diff --git a/src/python/grpcio/tests/__init__.py b/src/python/grpcio/tests/__init__.py
index b76b398..c3b80d7 100644
--- a/src/python/grpcio/tests/__init__.py
+++ b/src/python/grpcio/tests/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -27,6 +27,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.
 
+from __future__ import absolute_import
+
 from tests import _loader
 from tests import _runner
 
diff --git a/src/python/grpcio/tests/_loader.py b/src/python/grpcio/tests/_loader.py
index 6992029..2f9e5c6 100644
--- a/src/python/grpcio/tests/_loader.py
+++ b/src/python/grpcio/tests/_loader.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -27,6 +27,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.
 
+from __future__ import absolute_import
+
 import importlib
 import pkgutil
 import re
diff --git a/src/python/grpcio/tests/_result.py b/src/python/grpcio/tests/_result.py
index 0670be9..18b0f43 100644
--- a/src/python/grpcio/tests/_result.py
+++ b/src/python/grpcio/tests/_result.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,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.
 
-import cStringIO as StringIO
+from __future__ import absolute_import
+
 import collections
 import itertools
 import traceback
@@ -35,6 +36,7 @@
 from xml.etree import ElementTree
 
 import coverage
+from six import moves
 
 from tests import _loader
 
@@ -202,7 +204,7 @@
     """
     case_id = self.id_map(test)
     self.cases[case_id] = self.cases[case_id].updated(
-        stdout=stdout, stderr=stderr)
+        stdout=stdout.decode(), stderr=stderr.decode())
 
   def augmented_results(self, filter):
     """Convenience method to retrieve filtered case results.
@@ -356,7 +358,7 @@
   Returns:
     str: Formatted exception descriptive string.
   """
-  buffer = StringIO.StringIO()
+  buffer = moves.cStringIO()
   traceback.print_exception(type, value, trace, file=buffer)
   return buffer.getvalue()
 
diff --git a/src/python/grpcio/tests/_runner.py b/src/python/grpcio/tests/_runner.py
index b0dbd92..173a170 100644
--- a/src/python/grpcio/tests/_runner.py
+++ b/src/python/grpcio/tests/_runner.py
@@ -27,7 +27,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.
 
-import cStringIO as StringIO
+from __future__ import absolute_import
+
 import collections
 import fcntl
 import multiprocessing
@@ -35,69 +36,59 @@
 import select
 import signal
 import sys
+import tempfile
 import threading
 import time
 import unittest
 import uuid
 
+import six
+from six import moves
+
 from tests import _loader
 from tests import _result
 
 
-class CapturePipe(object):
-  """A context-manager pipe to redirect output to a byte array.
+class CaptureFile(object):
+  """A context-managed file to redirect output to a byte array.
+
+  Use by invoking `start` (`__enter__`) and at some point invoking `stop`
+  (`__exit__`). At any point after the initial call to `start` call `output` to
+  get the current redirected output. Note that we don't currently use file
+  locking, so calling `output` between calls to `start` and `stop` may muddle
+  the result (you should only be doing this during a Python-handled interrupt as
+  a last ditch effort to provide output to the user).
 
   Attributes:
-    _redirect_fd (int): File descriptor of file to redirect writes from.
+    _redirected_fd (int): File descriptor of file to redirect writes from.
     _saved_fd (int): A copy of the original value of the redirected file
       descriptor.
-    _read_thread (threading.Thread or None): Thread upon which reads through the
-      pipe are performed. Only non-None when self is started.
-    _read_fd (int or None): File descriptor of the read end of the redirect
-      pipe. Only non-None when self is started.
-    _write_fd (int or None): File descriptor of the write end of the redirect
-      pipe. Only non-None when self is started.
-    output (bytearray or None): Redirected output from writes to the redirected
-      file descriptor. Only valid during and after self has started.
+    _into_file (TemporaryFile or None): File to which writes are redirected.
+      Only non-None when self is started.
   """
 
   def __init__(self, fd):
-    self._redirect_fd = fd
-    self._saved_fd = os.dup(self._redirect_fd)
-    self._read_thread = None
-    self._read_fd = None
-    self._write_fd = None
-    self.output = None
+    self._redirected_fd = fd
+    self._saved_fd = os.dup(self._redirected_fd)
+    self._into_file = None
+
+  def output(self):
+    """Get all output from the redirected-to file if it exists."""
+    if self._into_file:
+      self._into_file.seek(0)
+      return bytes(self._into_file.read())
+    else:
+      return bytes()
 
   def start(self):
     """Start redirection of writes to the file descriptor."""
-    self._read_fd, self._write_fd = os.pipe()
-    os.dup2(self._write_fd, self._redirect_fd)
-    flags = fcntl.fcntl(self._read_fd, fcntl.F_GETFL)
-    fcntl.fcntl(self._read_fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
-    self._read_thread = threading.Thread(target=self._read)
-    self._read_thread.start()
+    self._into_file = tempfile.TemporaryFile()
+    os.dup2(self._into_file.fileno(), self._redirected_fd)
 
   def stop(self):
     """Stop redirection of writes to the file descriptor."""
-    os.close(self._write_fd)
-    os.dup2(self._saved_fd, self._redirect_fd)  # auto-close self._redirect_fd
-    self._read_thread.join()
-    self._read_thread = None
-    # we waited for the read thread to finish, so _read_fd has been read and we
-    # can close it.
-    os.close(self._read_fd)
-
-  def _read(self):
-    """Read-thread target for self."""
-    self.output = bytearray()
-    while True:
-      select.select([self._read_fd], [], [])
-      read_bytes = os.read(self._read_fd, 1024)
-      if read_bytes:
-        self.output.extend(read_bytes)
-      else:
-        break
+    # n.b. this dup2 call auto-closes self._redirected_fd
+    os.dup2(self._saved_fd, self._redirected_fd)
 
   def write_bypass(self, value):
     """Bypass the redirection and write directly to the original file.
@@ -105,6 +96,8 @@
     Arguments:
       value (str): What to write to the original file.
     """
+    if six.PY3 and not isinstance(value, six.binary_type):
+      value = bytes(value, 'ascii')
     if self._saved_fd is None:
       os.write(self._redirect_fd, value)
     else:
@@ -156,11 +149,11 @@
                        for case in filtered_cases]
     case_id_by_case = dict((augmented_case.case, augmented_case.id)
                            for augmented_case in augmented_cases)
-    result_out = StringIO.StringIO()
+    result_out = moves.cStringIO()
     result = _result.TerminalResult(
         result_out, id_map=lambda case: case_id_by_case[case])
-    stdout_pipe = CapturePipe(sys.stdout.fileno())
-    stderr_pipe = CapturePipe(sys.stderr.fileno())
+    stdout_pipe = CaptureFile(sys.stdout.fileno())
+    stderr_pipe = CaptureFile(sys.stderr.fileno())
     kill_flag = [False]
 
     def sigint_handler(signal_number, frame):
@@ -171,7 +164,8 @@
     def fault_handler(signal_number, frame):
       stdout_pipe.write_bypass(
           'Received fault signal {}\nstdout:\n{}\n\nstderr:{}\n'
-          .format(signal_number, stdout_pipe.output, stderr_pipe.output))
+          .format(signal_number, stdout_pipe.output(),
+                  stderr_pipe.output()))
       os._exit(1)
 
     def check_kill_self():
@@ -180,9 +174,9 @@
         result.stopTestRun()
         stdout_pipe.write_bypass(result_out.getvalue())
         stdout_pipe.write_bypass(
-            '\ninterrupted stdout:\n{}\n'.format(stdout_pipe.output))
+            '\ninterrupted stdout:\n{}\n'.format(stdout_pipe.output().decode()))
         stderr_pipe.write_bypass(
-            '\ninterrupted stderr:\n{}\n'.format(stderr_pipe.output))
+            '\ninterrupted stderr:\n{}\n'.format(stderr_pipe.output().decode()))
         os._exit(1)
     signal.signal(signal.SIGINT, sigint_handler)
     signal.signal(signal.SIGSEGV, fault_handler)
@@ -212,7 +206,7 @@
         # re-raise the exception after forcing the with-block to end
         raise
       result.set_output(
-          augmented_case.case, stdout_pipe.output, stderr_pipe.output)
+          augmented_case.case, stdout_pipe.output(), stderr_pipe.output())
       sys.stdout.write(result_out.getvalue())
       sys.stdout.flush()
       result_out.truncate(0)
@@ -225,7 +219,7 @@
     sys.stdout.write(result_out.getvalue())
     sys.stdout.flush()
     signal.signal(signal.SIGINT, signal.SIG_DFL)
-    with open('report.xml', 'w') as report_xml_file:
+    with open('report.xml', 'wb') as report_xml_file:
       _result.jenkins_junit_xml(result).write(report_xml_file)
     return result
 
diff --git a/src/python/grpcio/tests/interop/methods.py b/src/python/grpcio/tests/interop/methods.py
index b3591ae..7f42b4a 100644
--- a/src/python/grpcio/tests/interop/methods.py
+++ b/src/python/grpcio/tests/interop/methods.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,6 +29,8 @@
 
 """Implementations of interoperability test methods."""
 
+from __future__ import print_function
+
 import enum
 import json
 import os
@@ -173,6 +175,9 @@
   def __iter__(self):
     return self
 
+  def __next__(self):
+    return self.next()
+
   def next(self):
     with self._condition:
       while not self._values and self._open:
@@ -205,7 +210,7 @@
 
   with stub, _Pipe() as pipe:
     response_iterator = stub.FullDuplexCall(pipe, _TIMEOUT)
-    print 'Starting ping-pong with response iterator %s' % response_iterator
+    print('Starting ping-pong with response iterator %s' % response_iterator)
     for response_size, payload_size in zip(
         request_response_sizes, request_payload_sizes):
       request = messages_pb2.StreamingOutputCallRequest(
diff --git a/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py b/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
index ba5b219..230ec64 100644
--- a/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
+++ b/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,8 @@
 import time
 import unittest
 
+from six import moves
+
 from grpc.beta import implementations
 from grpc.framework.foundation import future
 from grpc.framework.interfaces.face import face
@@ -250,7 +252,7 @@
   def testImportAttributes(self):
     # check that we can access the generated module and its members.
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     self.assertIsNotNone(getattr(test_pb2, SERVICER_IDENTIFIER, None))
     self.assertIsNotNone(getattr(test_pb2, STUB_IDENTIFIER, None))
     self.assertIsNotNone(getattr(test_pb2, SERVER_FACTORY_IDENTIFIER, None))
@@ -258,13 +260,13 @@
 
   def testUpDown(self):
     import protoc_plugin_test_pb2 as test_pb2
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     with _CreateService(test_pb2) as (servicer, stub):
       request = test_pb2.SimpleRequest(response_size=13)
 
   def testUnaryCall(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       request = test_pb2.SimpleRequest(response_size=13)
       response = stub.UnaryCall(request, test_constants.LONG_TIMEOUT)
@@ -273,7 +275,7 @@
 
   def testUnaryCallFuture(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     request = test_pb2.SimpleRequest(response_size=13)
     with _CreateService(test_pb2) as (methods, stub):
       # Check that the call does not block waiting for the server to respond.
@@ -286,7 +288,7 @@
 
   def testUnaryCallFutureExpired(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       request = test_pb2.SimpleRequest(response_size=13)
       with methods.pause():
@@ -297,7 +299,7 @@
 
   def testUnaryCallFutureCancelled(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     request = test_pb2.SimpleRequest(response_size=13)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.pause():
@@ -307,7 +309,7 @@
 
   def testUnaryCallFutureFailed(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     request = test_pb2.SimpleRequest(response_size=13)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.fail():
@@ -317,20 +319,20 @@
 
   def testStreamingOutputCall(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     request = _streaming_output_request(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       responses = stub.StreamingOutputCall(
           request, test_constants.LONG_TIMEOUT)
       expected_responses = methods.StreamingOutputCall(
           request, 'not a real RpcContext!')
-      for expected_response, response in itertools.izip_longest(
+      for expected_response, response in moves.zip_longest(
           expected_responses, responses):
         self.assertEqual(expected_response, response)
 
   def testStreamingOutputCallExpired(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     request = _streaming_output_request(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.pause():
@@ -341,7 +343,7 @@
 
   def testStreamingOutputCallCancelled(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     request = _streaming_output_request(test_pb2)
     with _CreateService(test_pb2) as (unused_methods, stub):
       responses = stub.StreamingOutputCall(
@@ -353,7 +355,7 @@
 
   def testStreamingOutputCallFailed(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     request = _streaming_output_request(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.fail():
@@ -364,7 +366,7 @@
 
   def testStreamingInputCall(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       response = stub.StreamingInputCall(
           _streaming_input_request_iterator(test_pb2),
@@ -375,7 +377,7 @@
 
   def testStreamingInputCallFuture(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.pause():
         response_future = stub.StreamingInputCall.future(
@@ -388,7 +390,7 @@
 
   def testStreamingInputCallFutureExpired(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.pause():
         response_future = stub.StreamingInputCall.future(
@@ -401,7 +403,7 @@
 
   def testStreamingInputCallFutureCancelled(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.pause():
         response_future = stub.StreamingInputCall.future(
@@ -414,7 +416,7 @@
 
   def testStreamingInputCallFutureFailed(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.fail():
         response_future = stub.StreamingInputCall.future(
@@ -424,19 +426,19 @@
 
   def testFullDuplexCall(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       responses = stub.FullDuplexCall(
           _full_duplex_request_iterator(test_pb2), test_constants.LONG_TIMEOUT)
       expected_responses = methods.FullDuplexCall(
           _full_duplex_request_iterator(test_pb2), 'not a real RpcContext!')
-      for expected_response, response in itertools.izip_longest(
+      for expected_response, response in moves.zip_longest(
           expected_responses, responses):
         self.assertEqual(expected_response, response)
 
   def testFullDuplexCallExpired(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     request_iterator = _full_duplex_request_iterator(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.pause():
@@ -447,7 +449,7 @@
 
   def testFullDuplexCallCancelled(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       request_iterator = _full_duplex_request_iterator(test_pb2)
       responses = stub.FullDuplexCall(
@@ -459,7 +461,7 @@
 
   def testFullDuplexCallFailed(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     request_iterator = _full_duplex_request_iterator(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       with methods.fail():
@@ -471,7 +473,7 @@
 
   def testHalfDuplexCall(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     with _CreateService(test_pb2) as (methods, stub):
       def half_duplex_request_iterator():
         request = test_pb2.StreamingOutputCallRequest()
@@ -485,13 +487,13 @@
           half_duplex_request_iterator(), test_constants.LONG_TIMEOUT)
       expected_responses = methods.HalfDuplexCall(
           half_duplex_request_iterator(), 'not a real RpcContext!')
-      for check in itertools.izip_longest(expected_responses, responses):
+      for check in moves.zip_longest(expected_responses, responses):
         expected_response, response = check
         self.assertEqual(expected_response, response)
 
   def testHalfDuplexCallWedged(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
-    reload(test_pb2)
+    moves.reload_module(test_pb2)
     condition = threading.Condition()
     wait_cell = [False]
     @contextlib.contextmanager
diff --git a/src/python/grpcio/tests/tests.json b/src/python/grpcio/tests/tests.json
index 388d040..84870aa 100644
--- a/src/python/grpcio/tests/tests.json
+++ b/src/python/grpcio/tests/tests.json
@@ -12,31 +12,22 @@
   "_core_over_links_base_interface_test.SyncEasyTest", 
   "_core_over_links_base_interface_test.SyncPeasyTest", 
   "_crust_over_core_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_face_interface_test.DynamicInvokerEventInvocationSynchronousEventServiceTest", 
   "_crust_over_core_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_crust_over_core_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_face_interface_test.GenericInvokerEventInvocationSynchronousEventServiceTest", 
   "_crust_over_core_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_crust_over_core_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_face_interface_test.MultiCallableInvokerEventInvocationSynchronousEventServiceTest", 
   "_crust_over_core_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_crust_over_core_over_links_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_over_links_face_interface_test.DynamicInvokerEventInvocationSynchronousEventServiceTest", 
   "_crust_over_core_over_links_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_crust_over_core_over_links_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_over_links_face_interface_test.GenericInvokerEventInvocationSynchronousEventServiceTest", 
   "_crust_over_core_over_links_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_crust_over_core_over_links_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_over_links_face_interface_test.MultiCallableInvokerEventInvocationSynchronousEventServiceTest", 
   "_crust_over_core_over_links_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest", 
-  "_face_interface_test.DynamicInvokerEventInvocationSynchronousEventServiceTest", 
   "_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest", 
-  "_face_interface_test.GenericInvokerEventInvocationSynchronousEventServiceTest", 
   "_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest", 
-  "_face_interface_test.MultiCallableInvokerEventInvocationSynchronousEventServiceTest", 
   "_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_implementations_test.ChannelCredentialsTest", 
   "_insecure_interop_test.InsecureInteropTest", 
diff --git a/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py b/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
index a6fd823..06bfc34 100644
--- a/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
+++ b/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,11 +29,13 @@
 
 """Tests for the old '_low'."""
 
-import Queue
 import threading
 import time
 import unittest
 
+import six
+from six.moves import queue
+
 from grpc._adapter import _intermediary_low as _low
 
 _STREAM_LENGTH = 300
@@ -67,7 +69,7 @@
     second_event = completion_queue.get(after_deadline)
     self.assertIsNotNone(second_event)
     kinds = [event.kind for event in (first_event, second_event)]
-    self.assertItemsEqual(
+    six.assertCountEqual(self,
         (_low.Event.Kind.METADATA_ACCEPTED, _low.Event.Kind.FINISH),
         kinds)
 
@@ -99,7 +101,7 @@
     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_events = queue.Queue()
     self.server_completion_queue_thread = threading.Thread(
         target=_drive_completion_queue,
         args=(self.server_completion_queue, self.server_events))
@@ -107,7 +109,7 @@
 
     self.client_completion_queue = _low.CompletionQueue()
     self.channel = _low.Channel('%s:%d' % (self.host, port), None)
-    self.client_events = Queue.Queue()
+    self.client_events = queue.Queue()
     self.client_completion_queue_thread = threading.Thread(
         target=_drive_completion_queue,
         args=(self.client_completion_queue, self.client_events))
@@ -315,7 +317,7 @@
     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_events = queue.Queue()
     self.server_completion_queue_thread = threading.Thread(
         target=_drive_completion_queue,
         args=(self.server_completion_queue, self.server_events))
@@ -323,7 +325,7 @@
 
     self.client_completion_queue = _low.CompletionQueue()
     self.channel = _low.Channel('%s:%d' % (self.host, port), None)
-    self.client_events = Queue.Queue()
+    self.client_events = queue.Queue()
     self.client_completion_queue_thread = threading.Thread(
         target=_drive_completion_queue,
         args=(self.client_completion_queue, self.client_events))
diff --git a/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py b/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py
index f55a7a2..c9f3663 100644
--- a/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py
+++ b/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,13 @@
 import abc
 import threading
 
+import six
+
 from tests.unit._junkdrawer import math_pb2
 
 
-class ProtoScenario(object):
+class ProtoScenario(six.with_metaclass(abc.ABCMeta)):
   """An RPC test scenario using protocol buffers."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def method(self):
diff --git a/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py b/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py
index efc9904..8816337 100644
--- a/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py
+++ b/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,8 @@
 import time
 import unittest
 
+import six
+
 from grpc._adapter import _intermediary_low
 from grpc._links import invocation
 from grpc._links import service
@@ -68,7 +70,7 @@
   request_deserializers = {}
   response_serializers = {}
   response_deserializers = {}
-  for (group, method), serialization in serializations.iteritems():
+  for (group, method), serialization in six.iteritems(serializations):
     request_serializers[group, method] = serialization.serialize_request
     request_deserializers[group, method] = serialization.deserialize_request
     response_serializers[group, method] = serialization.serialize_response
diff --git a/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py b/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py
index 4faaaad..3be3b05 100644
--- a/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py
+++ b/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,8 @@
 import collections
 import unittest
 
+import six
+
 from grpc._adapter import _intermediary_low
 from grpc._links import invocation
 from grpc._links import service
@@ -59,7 +61,7 @@
   request_deserializers = {}
   response_serializers = {}
   response_deserializers = {}
-  for (group, method), test_method in test_methods.iteritems():
+  for (group, method), test_method in six.iteritems(test_methods):
     request_serializers[group, method] = test_method.serialize_request
     request_deserializers[group, method] = test_method.deserialize_request
     response_serializers[group, method] = test_method.serialize_response
@@ -108,7 +110,7 @@
     # _digest.TestServiceDigest.
     cardinalities = {
         method: method_object.cardinality()
-        for (group, method), method_object in methods.iteritems()}
+        for (group, method), method_object in six.iteritems(methods)}
     dynamic_stub = crust_implementations.dynamic_stub(
         invocation_end_link, group, cardinalities, pool)
 
diff --git a/src/python/grpcio/tests/unit/_links/_proto_scenarios.py b/src/python/grpcio/tests/unit/_links/_proto_scenarios.py
index f69ff51..acd4891 100644
--- a/src/python/grpcio/tests/unit/_links/_proto_scenarios.py
+++ b/src/python/grpcio/tests/unit/_links/_proto_scenarios.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,13 +32,14 @@
 import abc
 import threading
 
+import six
+
 from tests.unit._junkdrawer import math_pb2
 from tests.unit.framework.common import test_constants
 
 
-class ProtoScenario(object):
+class ProtoScenario(six.with_metaclass(abc.ABCMeta)):
   """An RPC test scenario using protocol buffers."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def group_and_method(self):
diff --git a/src/python/grpcio/tests/unit/beta/_beta_features_test.py b/src/python/grpcio/tests/unit/beta/_beta_features_test.py
index ea44177..ebdedcc 100644
--- a/src/python/grpcio/tests/unit/beta/_beta_features_test.py
+++ b/src/python/grpcio/tests/unit/beta/_beta_features_test.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -125,6 +125,9 @@
   def __iter__(self):
     return self
 
+  def __next__(self):
+    return self.next()
+
   def next(self):
     with self._condition:
       while True:
diff --git a/src/python/grpcio/tests/unit/beta/_face_interface_test.py b/src/python/grpcio/tests/unit/beta/_face_interface_test.py
index 1c21dfd..cb302bb 100644
--- a/src/python/grpcio/tests/unit/beta/_face_interface_test.py
+++ b/src/python/grpcio/tests/unit/beta/_face_interface_test.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,8 @@
 import collections
 import unittest
 
+import six
+
 from grpc.beta import implementations
 from grpc.beta import interfaces
 from tests.unit import resources
@@ -57,7 +59,7 @@
   request_deserializers = {}
   response_serializers = {}
   response_deserializers = {}
-  for (group, method), test_method in test_methods.iteritems():
+  for (group, method), test_method in six.iteritems(test_methods):
     request_serializers[group, method] = test_method.serialize_request
     request_deserializers[group, method] = test_method.deserialize_request
     response_serializers[group, method] = test_method.serialize_response
@@ -79,7 +81,7 @@
     # _digest.TestServiceDigest.
     cardinalities = {
         method: method_object.cardinality()
-        for (group, method), method_object in methods.iteritems()}
+        for (group, method), method_object in six.iteritems(methods)}
 
     server_options = implementations.server_options(
         request_deserializers=serialization_behaviors.request_deserializers,
diff --git a/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py b/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py
index 360ecc9..fd2d429 100644
--- a/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py
+++ b/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,8 @@
 import collections
 import unittest
 
+import six
+
 from grpc.framework.core import implementations as core_implementations
 from grpc.framework.crust import implementations as crust_implementations
 from grpc.framework.foundation import logging_pool
@@ -66,7 +68,7 @@
     # _digest.TestServiceDigest.
     cardinalities = {
         method: method_object.cardinality()
-        for (group, method), method_object in methods.iteritems()}
+        for (group, method), method_object in six.iteritems(methods)}
     dynamic_stub = crust_implementations.dynamic_stub(
         invocation_end_link, group, cardinalities, pool)
 
diff --git a/src/python/grpcio/tests/unit/framework/common/test_control.py b/src/python/grpcio/tests/unit/framework/common/test_control.py
index 8d6eba5..0387668 100644
--- a/src/python/grpcio/tests/unit/framework/common/test_control.py
+++ b/src/python/grpcio/tests/unit/framework/common/test_control.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,8 @@
 import contextlib
 import threading
 
+import six
+
 
 class Defect(Exception):
   """Simulates a programming defect raised into in a system under test.
@@ -42,7 +44,7 @@
   """
 
 
-class Control(object):
+class Control(six.with_metaclass(abc.ABCMeta)):
   """An object that accepts program control from a system under test.
 
   Systems under test passed a Control should call its control() method
@@ -51,8 +53,6 @@
   the system under test to simulate hanging, failing, or functioning.
   """
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def control(self):
     """Potentially does anything."""
diff --git a/src/python/grpcio/tests/unit/framework/common/test_coverage.py b/src/python/grpcio/tests/unit/framework/common/test_coverage.py
index a7ed358..184621f 100644
--- a/src/python/grpcio/tests/unit/framework/common/test_coverage.py
+++ b/src/python/grpcio/tests/unit/framework/common/test_coverage.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,13 +31,14 @@
 
 import abc
 
+import six
+
 # This code is designed for use with the unittest module.
 # pylint: disable=invalid-name
 
 
-class Coverage(object):
+class Coverage(six.with_metaclass(abc.ABCMeta)):
   """Specification of test coverage."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def testSuccessfulUnaryRequestUnaryResponse(self):
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/base_util.py b/src/python/grpcio/tests/unit/framework/face/testing/base_util.py
index 1df1529..60ab5bc 100644
--- a/src/python/grpcio/tests/unit/framework/face/testing/base_util.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/base_util.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
 
 import abc
 
+import six
+
 # interfaces is referenced from specification in this module.
 from grpc.framework.base import util as _base_util
 from grpc.framework.base import implementations
@@ -43,7 +45,7 @@
 _MAXIMUM_TIMEOUT = 90
 
 
-class LinkedPair(object):
+class LinkedPair(six.with_metaclass(abc.ABCMeta)):
   """A Front and Back that are linked to one another.
 
   Attributes:
@@ -51,8 +53,6 @@
     back: An interfaces.Back.
   """
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def shut_down(self):
     """Shuts down this object and releases its resources."""
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py
index 0613516..b0b00bf 100644
--- a/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,8 @@
 import abc
 import unittest  # pylint: disable=unused-import
 
+import six
+
 from grpc.framework.face import exceptions
 from tests.unit.framework.common import test_constants
 from tests.unit.framework.face.testing import control
@@ -43,12 +45,12 @@
 
 
 class BlockingInvocationInlineServiceTestCase(
-    test_case.FaceTestCase, coverage.BlockingCoverage):
+    six.with_metaclass(abc.ABCMeta,
+    test_case.FaceTestCase, coverage.BlockingCoverage)):
   """A test of the Face layer of RPC Framework.
 
   Concrete subclasses must also extend unittest.TestCase.
   """
-  __metaclass__ = abc.ABCMeta
 
   def setUp(self):
     """See unittest.TestCase.setUp for full specification.
@@ -72,7 +74,7 @@
 
   def testSuccessfulUnaryRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -83,7 +85,7 @@
 
   def testSuccessfulUnaryRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -95,7 +97,7 @@
 
   def testSuccessfulStreamRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -106,7 +108,7 @@
 
   def testSuccessfulStreamRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -118,7 +120,7 @@
 
   def testSequentialInvocations(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         first_request = test_messages.request()
         second_request = test_messages.request()
@@ -135,7 +137,7 @@
 
   def testExpiredUnaryRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -146,7 +148,7 @@
 
   def testExpiredUnaryRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -158,7 +160,7 @@
 
   def testExpiredStreamRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -169,7 +171,7 @@
 
   def testExpiredStreamRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -181,7 +183,7 @@
 
   def testFailedUnaryRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -191,7 +193,7 @@
 
   def testFailedUnaryRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -202,7 +204,7 @@
 
   def testFailedStreamRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -212,7 +214,7 @@
 
   def testFailedStreamRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/control.py b/src/python/grpcio/tests/unit/framework/face/testing/control.py
index 3960c4e..0d40331 100644
--- a/src/python/grpcio/tests/unit/framework/face/testing/control.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/control.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,10 @@
 import contextlib
 import threading
 
+import six
 
-class Control(object):
+
+class Control(six.with_metaclass(abc.ABCMeta)):
   """An object that accepts program control from a system under test.
 
   Systems under test passed a Control should call its control() method
@@ -43,8 +45,6 @@
   the system under test to simulate hanging, failing, or functioning.
   """
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def control(self):
     """Potentially does anything."""
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/coverage.py b/src/python/grpcio/tests/unit/framework/face/testing/coverage.py
index f3aca11..9f53810 100644
--- a/src/python/grpcio/tests/unit/framework/face/testing/coverage.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/coverage.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,15 +31,15 @@
 
 import abc
 
+import six
+
 # These classes are only valid when inherited by unittest.TestCases.
 # pylint: disable=invalid-name
 
 
-class BlockingCoverage(object):
+class BlockingCoverage(six.with_metaclass(abc.ABCMeta)):
   """Specification of test coverage for blocking behaviors."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def testSuccessfulUnaryRequestUnaryResponse(self):
     raise NotImplementedError()
@@ -93,11 +93,9 @@
     raise NotImplementedError()
 
 
-class FullCoverage(BlockingCoverage):
+class FullCoverage(six.with_metaclass(abc.ABCMeta, BlockingCoverage)):
   """Specification of test coverage for non-blocking behaviors."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def testParallelInvocations(self):
     raise NotImplementedError()
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/digest.py b/src/python/grpcio/tests/unit/framework/face/testing/digest.py
index 39f28b9..100067c 100644
--- a/src/python/grpcio/tests/unit/framework/face/testing/digest.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/digest.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,8 @@
 import collections
 import threading
 
+import six
+
 # testing_control, interfaces, and testing_service are referenced from
 # specification in this module.
 from grpc.framework.common import cardinality
@@ -368,7 +370,7 @@
   events = {}
   adaptations = {}
   messages = {}
-  for name, scenario in scenarios.iteritems():
+  for name, scenario in six.iteritems(scenarios):
     if name in names:
       raise ValueError('Repeated name "%s"!' % name)
 
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
index 179f3a2..db901cf 100644
--- a/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,8 @@
 import abc
 import unittest
 
+import six
+
 from grpc.framework.face import interfaces
 from tests.unit.framework.common import test_constants
 from tests.unit.framework.face.testing import callback as testing_callback
@@ -43,12 +45,12 @@
 
 
 class EventInvocationSynchronousEventServiceTestCase(
-    test_case.FaceTestCase, coverage.FullCoverage):
+    six.with_metaclass(abc.ABCMeta,
+    test_case.FaceTestCase, coverage.FullCoverage)):
   """A test of the Face layer of RPC Framework.
 
   Concrete subclasses must also extend unittest.TestCase.
   """
-  __metaclass__ = abc.ABCMeta
 
   def setUp(self):
     """See unittest.TestCase.setUp for full specification.
@@ -72,7 +74,7 @@
 
   def testSuccessfulUnaryRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
         callback = testing_callback.Callback()
@@ -87,7 +89,7 @@
 
   def testSuccessfulUnaryRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
         callback = testing_callback.Callback()
@@ -102,7 +104,7 @@
 
   def testSuccessfulStreamRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         callback = testing_callback.Callback()
@@ -120,7 +122,7 @@
 
   def testSuccessfulStreamRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         callback = testing_callback.Callback()
@@ -138,7 +140,7 @@
   def testSequentialInvocations(self):
     # pylint: disable=cell-var-from-loop
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         first_request = test_messages.request()
         second_request = test_messages.request()
@@ -163,7 +165,7 @@
 
   def testExpiredUnaryRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
         callback = testing_callback.Callback()
@@ -178,7 +180,7 @@
 
   def testExpiredUnaryRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
         callback = testing_callback.Callback()
@@ -193,7 +195,7 @@
 
   def testExpiredStreamRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_unary_messages_sequences)):
       for unused_test_messages in test_messages_sequence:
         callback = testing_callback.Callback()
 
@@ -206,7 +208,7 @@
 
   def testExpiredStreamRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         callback = testing_callback.Callback()
@@ -221,7 +223,7 @@
 
   def testFailedUnaryRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
         callback = testing_callback.Callback()
@@ -237,7 +239,7 @@
 
   def testFailedUnaryRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
         callback = testing_callback.Callback()
@@ -253,7 +255,7 @@
 
   def testFailedStreamRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         callback = testing_callback.Callback()
@@ -272,7 +274,7 @@
 
   def testFailedStreamRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         callback = testing_callback.Callback()
@@ -289,7 +291,7 @@
 
   def testParallelInvocations(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         first_request = test_messages.request()
         first_callback = testing_callback.Callback()
@@ -316,7 +318,7 @@
 
   def testCancelledUnaryRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
         callback = testing_callback.Callback()
@@ -332,7 +334,7 @@
 
   def testCancelledUnaryRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
         callback = testing_callback.Callback()
@@ -347,7 +349,7 @@
 
   def testCancelledStreamRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         callback = testing_callback.Callback()
@@ -364,7 +366,7 @@
 
   def testCancelledStreamRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_stream_messages_sequences)):
       for unused_test_messages in test_messages_sequence:
         callback = testing_callback.Callback()
 
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
index 485524a..d8706aa 100644
--- a/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,8 @@
 import threading
 import unittest
 
+import six
+
 from grpc.framework.face import exceptions
 from grpc.framework.foundation import future
 from grpc.framework.foundation import logging_pool
@@ -66,6 +68,9 @@
   def __iter__(self):
     return self
 
+  def __next__(self):
+    return self.next()
+
   def next(self):
     with self._condition:
       while self._paused:
@@ -74,12 +79,12 @@
 
 
 class FutureInvocationAsynchronousEventServiceTestCase(
-    test_case.FaceTestCase, coverage.FullCoverage):
+    six.with_metaclass(abc.ABCMeta,
+    test_case.FaceTestCase, coverage.FullCoverage)):
   """A test of the Face layer of RPC Framework.
 
   Concrete subclasses must also extend unittest.TestCase.
   """
-  __metaclass__ = abc.ABCMeta
 
   def setUp(self):
     """See unittest.TestCase.setUp for full specification.
@@ -105,7 +110,7 @@
 
   def testSuccessfulUnaryRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -117,7 +122,7 @@
 
   def testSuccessfulUnaryRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -129,7 +134,7 @@
 
   def testSuccessfulStreamRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         request_iterator = _PauseableIterator(iter(requests))
@@ -145,7 +150,7 @@
 
   def testSuccessfulStreamRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         request_iterator = _PauseableIterator(iter(requests))
@@ -161,7 +166,7 @@
 
   def testSequentialInvocations(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         first_request = test_messages.request()
         second_request = test_messages.request()
@@ -180,7 +185,7 @@
 
   def testExpiredUnaryRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -195,7 +200,7 @@
 
   def testExpiredUnaryRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -207,7 +212,7 @@
 
   def testExpiredStreamRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -222,7 +227,7 @@
 
   def testExpiredStreamRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -234,7 +239,7 @@
 
   def testFailedUnaryRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -253,7 +258,7 @@
 
   def testFailedUnaryRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -268,7 +273,7 @@
 
   def testFailedStreamRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -287,7 +292,7 @@
 
   def testFailedStreamRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -302,7 +307,7 @@
 
   def testParallelInvocations(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         first_request = test_messages.request()
         second_request = test_messages.request()
@@ -324,7 +329,7 @@
 
   def testCancelledUnaryRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -338,7 +343,7 @@
 
   def testCancelledUnaryRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -352,7 +357,7 @@
 
   def testCancelledStreamRequestUnaryResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -366,7 +371,7 @@
 
   def testCancelledStreamRequestStreamResponse(self):
     for name, test_messages_sequence in (
-        self.digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self.digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py b/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py
index 5932dab..87be836 100644
--- a/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,13 +31,14 @@
 
 import abc
 
+import six
+
 # cardinality is referenced from specification in this module.
 from grpc.framework.common import cardinality  # pylint: disable=unused-import
 
 
-class Method(object):
+class Method(six.with_metaclass(abc.ABCMeta)):
   """An RPC method to be used in tests of RPC implementations."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def name(self):
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/service.py b/src/python/grpcio/tests/unit/framework/face/testing/service.py
index ac0b89b..dc0f204 100644
--- a/src/python/grpcio/tests/unit/framework/face/testing/service.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/service.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,16 +31,16 @@
 
 import abc
 
+import six
+
 # interfaces is referenced from specification in this module.
 from grpc.framework.face import interfaces as face_interfaces  # pylint: disable=unused-import
 from tests.unit.framework.face.testing import interfaces
 
 
-class UnaryUnaryTestMethodImplementation(interfaces.Method):
+class UnaryUnaryTestMethodImplementation(six.with_metaclass(abc.ABCMeta, interfaces.Method)):
   """A controllable implementation of a unary-unary RPC method."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def service(self, request, response_callback, context, control):
     """Services an RPC that accepts one message and produces one message.
@@ -59,11 +59,9 @@
     raise NotImplementedError()
 
 
-class UnaryUnaryTestMessages(object):
+class UnaryUnaryTestMessages(six.with_metaclass(abc.ABCMeta)):
   """A type for unary-request-unary-response message pairings."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def request(self):
     """Affords a request message.
@@ -93,11 +91,9 @@
     raise NotImplementedError()
 
 
-class UnaryStreamTestMethodImplementation(interfaces.Method):
+class UnaryStreamTestMethodImplementation(six.with_metaclass(abc.ABCMeta, interfaces.Method)):
   """A controllable implementation of a unary-stream RPC method."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def service(self, request, response_consumer, context, control):
     """Services an RPC that takes one message and produces a stream of messages.
@@ -116,11 +112,9 @@
     raise NotImplementedError()
 
 
-class UnaryStreamTestMessages(object):
+class UnaryStreamTestMessages(six.with_metaclass(abc.ABCMeta)):
   """A type for unary-request-stream-response message pairings."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def request(self):
     """Affords a request message.
@@ -150,11 +144,9 @@
     raise NotImplementedError()
 
 
-class StreamUnaryTestMethodImplementation(interfaces.Method):
+class StreamUnaryTestMethodImplementation(six.with_metaclass(abc.ABCMeta, interfaces.Method)):
   """A controllable implementation of a stream-unary RPC method."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def service(self, response_callback, context, control):
     """Services an RPC that takes a stream of messages and produces one message.
@@ -180,11 +172,9 @@
     raise NotImplementedError()
 
 
-class StreamUnaryTestMessages(object):
+class StreamUnaryTestMessages(six.with_metaclass(abc.ABCMeta)):
   """A type for stream-request-unary-response message pairings."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def requests(self):
     """Affords a sequence of request messages.
@@ -214,11 +204,9 @@
     raise NotImplementedError()
 
 
-class StreamStreamTestMethodImplementation(interfaces.Method):
+class StreamStreamTestMethodImplementation(six.with_metaclass(abc.ABCMeta, interfaces.Method)):
   """A controllable implementation of a stream-stream RPC method."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def service(self, response_consumer, context, control):
     """Services an RPC that accepts and produces streams of messages.
@@ -244,11 +232,9 @@
     raise NotImplementedError()
 
 
-class StreamStreamTestMessages(object):
+class StreamStreamTestMessages(six.with_metaclass(abc.ABCMeta)):
   """A type for stream-request-stream-response message pairings."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def requests(self):
     """Affords a sequence of request messages.
@@ -278,11 +264,9 @@
     raise NotImplementedError()
 
 
-class TestService(object):
+class TestService(six.with_metaclass(abc.ABCMeta)):
   """A specification of implemented RPC methods to use in tests."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def name(self):
     """Identifies the RPC service name used during the test.
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/test_case.py
index 23d4d91..5be9330 100644
--- a/src/python/grpcio/tests/unit/framework/face/testing/test_case.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/test_case.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,18 +31,19 @@
 
 import abc
 
+import six
+
 # face_interfaces and interfaces are referenced in specification in this module.
 from grpc.framework.face import interfaces as face_interfaces  # pylint: disable=unused-import
 from tests.unit.framework.face.testing import interfaces  # pylint: disable=unused-import
 
 
-class FaceTestCase(object):
+class FaceTestCase(six.with_metaclass(abc.ABCMeta)):
   """Describes a test of the Face Layer of RPC Framework.
 
   Concrete subclasses must also inherit from unittest.TestCase and from at least
   one class that defines test methods.
   """
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def set_up_implementation(
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py b/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py
index 38102b1..94bcc14 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,6 +29,8 @@
 
 """Part of the tests of the base interface of RPC Framework."""
 
+from __future__ import division
+
 import abc
 import collections
 import enum
@@ -36,6 +38,8 @@
 import threading
 import time
 
+import six
+
 from grpc.framework.interfaces.base import base
 from tests.unit.framework.common import test_constants
 from tests.unit.framework.interfaces.base import _sequence
@@ -45,8 +49,8 @@
 _GROUP = 'base test cases test group'
 _METHOD = 'base test cases test method'
 
-_PAYLOAD_RANDOM_SECTION_MAXIMUM_SIZE = test_constants.PAYLOAD_SIZE / 20
-_MINIMUM_PAYLOAD_SIZE = test_constants.PAYLOAD_SIZE / 600
+_PAYLOAD_RANDOM_SECTION_MAXIMUM_SIZE = test_constants.PAYLOAD_SIZE // 20
+_MINIMUM_PAYLOAD_SIZE = test_constants.PAYLOAD_SIZE // 600
 
 
 def _create_payload(randomness):
@@ -57,7 +61,7 @@
   random_section = bytes(
       bytearray(
           randomness.getrandbits(8) for _ in range(random_section_length)))
-  sevens_section = '\x07' * (length - random_section_length)
+  sevens_section = b'\x07' * (length - random_section_length)
   return b''.join(randomness.sample((random_section, sevens_section), 2))
 
 
@@ -247,8 +251,7 @@
     CONCLUDE = 'CONCLUDE'
 
 
-class Controller(object):
-  __metaclass__ = abc.ABCMeta
+class Controller(six.with_metaclass(abc.ABCMeta)):
 
   @abc.abstractmethod
   def failed(self, message):
@@ -308,8 +311,7 @@
     raise NotImplementedError()
 
 
-class ControllerCreator(object):
-  __metaclass__ = abc.ABCMeta
+class ControllerCreator(six.with_metaclass(abc.ABCMeta)):
 
   @abc.abstractmethod
   def name(self):
@@ -385,13 +387,13 @@
     return request + request
 
   def deserialize_request(self, serialized_request):
-    return serialized_request[:len(serialized_request) / 2]
+    return serialized_request[:len(serialized_request) // 2]
 
   def serialize_response(self, response):
     return response * 3
 
   def deserialize_response(self, serialized_response):
-    return serialized_response[2 * len(serialized_response) / 3:]
+    return serialized_response[2 * len(serialized_response) // 3:]
 
   def invocation(self):
     with self._condition:
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py b/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py
index 84afd24..0594cfe 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,12 +31,13 @@
 
 import abc
 
+import six
+
 from grpc.framework.interfaces.base import base  # pylint: disable=unused-import
 
 
-class Serialization(object):
+class Serialization(six.with_metaclass(abc.ABCMeta)):
   """Specifies serialization and deserialization of test payloads."""
-  __metaclass__ = abc.ABCMeta
 
   def serialize_request(self, request):
     """Serializes a request value used in a test.
@@ -85,9 +86,8 @@
     raise NotImplementedError()
 
 
-class Implementation(object):
+class Implementation(six.with_metaclass(abc.ABCMeta)):
   """Specifies an implementation of the Base layer."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def instantiate(self, serializations, servicer):
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
index c8a3a1b..936b87f 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
@@ -29,11 +29,15 @@
 
 """Test code for the Face layer of RPC Framework."""
 
+from __future__ import division
+
 import abc
 import itertools
 import unittest
 from concurrent import futures
 
+import six
+
 # test_interfaces is referenced from specification in this module.
 from grpc.framework.foundation import logging_pool
 from grpc.framework.interfaces.face import face
@@ -46,14 +50,13 @@
 from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
 
 
-class TestCase(test_coverage.Coverage, unittest.TestCase):
+class TestCase(six.with_metaclass(abc.ABCMeta, test_coverage.Coverage, unittest.TestCase)):
   """A test of the Face layer of RPC Framework.
 
   Concrete subclasses must have an "implementation" attribute of type
   test_interfaces.Implementation and an "invoker_constructor" attribute of type
   _invocation.InvokerConstructor.
   """
-  __metaclass__ = abc.ABCMeta
 
   NAME = 'BlockingInvocationInlineServiceTest'
 
@@ -81,7 +84,7 @@
 
   def testSuccessfulUnaryRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -92,7 +95,7 @@
 
   def testSuccessfulUnaryRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -104,7 +107,7 @@
 
   def testSuccessfulStreamRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -115,7 +118,7 @@
 
   def testSuccessfulStreamRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -127,7 +130,7 @@
 
   def testSequentialInvocations(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         first_request = test_messages.request()
         second_request = test_messages.request()
@@ -145,7 +148,7 @@
   def testParallelInvocations(self):
     pool = logging_pool.pool(test_constants.PARALLELISM)
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = []
         response_futures = []
@@ -167,7 +170,7 @@
   def testWaitingForSomeButNotAllParallelInvocations(self):
     pool = logging_pool.pool(test_constants.PARALLELISM)
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = []
         response_futures_to_indices = {}
@@ -181,7 +184,7 @@
 
         some_completed_response_futures_iterator = itertools.islice(
             futures.as_completed(response_futures_to_indices),
-            test_constants.PARALLELISM / 2)
+            test_constants.PARALLELISM // 2)
         for response_future in some_completed_response_futures_iterator:
           index = response_futures_to_indices[response_future]
           test_messages.verify(requests[index], response_future.result(), self)
@@ -205,7 +208,7 @@
 
   def testExpiredUnaryRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -216,7 +219,7 @@
 
   def testExpiredUnaryRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -228,7 +231,7 @@
 
   def testExpiredStreamRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -239,7 +242,7 @@
 
   def testExpiredStreamRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -251,7 +254,7 @@
 
   def testFailedUnaryRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -261,7 +264,7 @@
 
   def testFailedUnaryRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -272,7 +275,7 @@
 
   def testFailedStreamRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -282,7 +285,7 @@
 
   def testFailedStreamRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py
index 9304b6b..40c03f9 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,8 @@
 import collections
 import threading
 
+import six
+
 # test_control, _service, and test_interfaces are referenced from specification
 # in this module.
 from grpc.framework.common import cardinality
@@ -363,7 +365,7 @@
   events = {}
   adaptations = {}
   messages = {}
-  for identifier, scenario in scenarios.iteritems():
+  for identifier, scenario in six.iteritems(scenarios):
     if identifier in identifiers:
       raise ValueError('Repeated identifier "(%s, %s)"!' % identifier)
 
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py
deleted file mode 100644
index 34db6c3..0000000
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py
+++ /dev/null
@@ -1,381 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Test code for the Face layer of RPC Framework."""
-
-import abc
-import unittest
-
-# test_interfaces is referenced from specification in this module.
-from grpc.framework.interfaces.face import face
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.common import test_control
-from tests.unit.framework.common import test_coverage
-from tests.unit.framework.interfaces.face import _3069_test_constant
-from tests.unit.framework.interfaces.face import _digest
-from tests.unit.framework.interfaces.face import _receiver
-from tests.unit.framework.interfaces.face import _stock_service
-from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
-
-
-class TestCase(test_coverage.Coverage, unittest.TestCase):
-  """A test of the Face layer of RPC Framework.
-
-  Concrete subclasses must have an "implementation" attribute of type
-  test_interfaces.Implementation and an "invoker_constructor" attribute of type
-  _invocation.InvokerConstructor.
-  """
-  __metaclass__ = abc.ABCMeta
-
-  NAME = 'EventInvocationSynchronousEventServiceTest'
-
-  def setUp(self):
-    """See unittest.TestCase.setUp for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-    self._control = test_control.PauseFailControl()
-    self._digest = _digest.digest(
-        _stock_service.STOCK_TEST_SERVICE, self._control, None)
-
-    generic_stub, dynamic_stubs, self._memo = self.implementation.instantiate(
-        self._digest.methods, self._digest.event_method_implementations, None)
-    self._invoker = self.invoker_constructor.construct_invoker(
-        generic_stub, dynamic_stubs, self._digest.methods)
-
-  def tearDown(self):
-    """See unittest.TestCase.tearDown for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-    self._invoker = None
-    self.implementation.destantiate(self._memo)
-
-  def testSuccessfulUnaryRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        self._invoker.event(group, method)(
-            request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        receiver.block_until_terminated()
-        response = receiver.unary_response()
-
-        test_messages.verify(request, response, self)
-
-  def testSuccessfulUnaryRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        self._invoker.event(group, method)(
-            request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        receiver.block_until_terminated()
-        responses = receiver.stream_responses()
-
-        test_messages.verify(request, responses, self)
-
-  def testSuccessfulStreamRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        receiver = _receiver.Receiver()
-
-        call_consumer = self._invoker.event(group, method)(
-            receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        for request in requests:
-          call_consumer.consume(request)
-        call_consumer.terminate()
-        receiver.block_until_terminated()
-        response = receiver.unary_response()
-
-        test_messages.verify(requests, response, self)
-
-  def testSuccessfulStreamRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        receiver = _receiver.Receiver()
-
-        call_consumer = self._invoker.event(group, method)(
-            receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        for request in requests:
-          call_consumer.consume(request)
-        call_consumer.terminate()
-        receiver.block_until_terminated()
-        responses = receiver.stream_responses()
-
-        test_messages.verify(requests, responses, self)
-
-  def testSequentialInvocations(self):
-    # pylint: disable=cell-var-from-loop
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        first_request = test_messages.request()
-        second_request = test_messages.request()
-        second_receiver = _receiver.Receiver()
-
-        def make_second_invocation():
-          self._invoker.event(group, method)(
-              second_request, second_receiver, second_receiver.abort,
-              test_constants.LONG_TIMEOUT)
-
-        class FirstReceiver(_receiver.Receiver):
-
-          def complete(self, terminal_metadata, code, details):
-            super(FirstReceiver, self).complete(
-                terminal_metadata, code, details)
-            make_second_invocation()
-
-        first_receiver = FirstReceiver()
-
-        self._invoker.event(group, method)(
-            first_request, first_receiver, first_receiver.abort,
-            test_constants.LONG_TIMEOUT)
-        second_receiver.block_until_terminated()
-
-        first_response = first_receiver.unary_response()
-        second_response = second_receiver.unary_response()
-        test_messages.verify(first_request, first_response, self)
-        test_messages.verify(second_request, second_response, self)
-
-  def testParallelInvocations(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        first_request = test_messages.request()
-        first_receiver = _receiver.Receiver()
-        second_request = test_messages.request()
-        second_receiver = _receiver.Receiver()
-
-        self._invoker.event(group, method)(
-            first_request, first_receiver, first_receiver.abort,
-            test_constants.LONG_TIMEOUT)
-        self._invoker.event(group, method)(
-            second_request, second_receiver, second_receiver.abort,
-            test_constants.LONG_TIMEOUT)
-        first_receiver.block_until_terminated()
-        second_receiver.block_until_terminated()
-
-        first_response = first_receiver.unary_response()
-        second_response = second_receiver.unary_response()
-        test_messages.verify(first_request, first_response, self)
-        test_messages.verify(second_request, second_response, self)
-
-  @unittest.skip('TODO(nathaniel): implement.')
-  def testWaitingForSomeButNotAllParallelInvocations(self):
-    raise NotImplementedError()
-
-  def testCancelledUnaryRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        with self._control.pause():
-          call = self._invoker.event(group, method)(
-              request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-          call.cancel()
-          receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind)
-
-  def testCancelledUnaryRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        call = self._invoker.event(group, method)(
-            request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        call.cancel()
-        receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind)
-
-  def testCancelledStreamRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        receiver = _receiver.Receiver()
-
-        call_consumer = self._invoker.event(group, method)(
-            receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        for request in requests:
-          call_consumer.consume(request)
-        call_consumer.cancel()
-        receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind)
-
-  def testCancelledStreamRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
-      for unused_test_messages in test_messages_sequence:
-        receiver = _receiver.Receiver()
-
-        call_consumer = self._invoker.event(group, method)(
-            receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        call_consumer.cancel()
-        receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind)
-
-  def testExpiredUnaryRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        with self._control.pause():
-          self._invoker.event(group, method)(
-              request, receiver, receiver.abort,
-              _3069_test_constant.REALLY_SHORT_TIMEOUT)
-          receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
-
-  def testExpiredUnaryRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        with self._control.pause():
-          self._invoker.event(group, method)(
-              request, receiver, receiver.abort,
-              _3069_test_constant.REALLY_SHORT_TIMEOUT)
-          receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
-
-  def testExpiredStreamRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
-      for unused_test_messages in test_messages_sequence:
-        receiver = _receiver.Receiver()
-
-        self._invoker.event(group, method)(
-            receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT)
-        receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
-
-  def testExpiredStreamRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        receiver = _receiver.Receiver()
-
-        call_consumer = self._invoker.event(group, method)(
-            receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT)
-        for request in requests:
-          call_consumer.consume(request)
-        receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
-
-  def testFailedUnaryRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        with self._control.fail():
-          self._invoker.event(group, method)(
-              request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-          receiver.block_until_terminated()
-
-        self.assertIs(
-            face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind)
-
-  def testFailedUnaryRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        with self._control.fail():
-          self._invoker.event(group, method)(
-              request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-          receiver.block_until_terminated()
-
-        self.assertIs(
-            face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind)
-
-  def testFailedStreamRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        receiver = _receiver.Receiver()
-
-        with self._control.fail():
-          call_consumer = self._invoker.event(group, method)(
-              receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-          for request in requests:
-            call_consumer.consume(request)
-          call_consumer.terminate()
-          receiver.block_until_terminated()
-
-        self.assertIs(
-            face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind)
-
-  def testFailedStreamRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        receiver = _receiver.Receiver()
-
-        with self._control.fail():
-          call_consumer = self._invoker.event(group, method)(
-              receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-          for request in requests:
-            call_consumer.consume(request)
-          call_consumer.terminate()
-          receiver.block_until_terminated()
-
-        self.assertIs(
-            face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind)
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
index 1d36a93..401b52f 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
@@ -29,6 +29,8 @@
 
 """Test code for the Face layer of RPC Framework."""
 
+from __future__ import division
+
 import abc
 import contextlib
 import itertools
@@ -36,6 +38,8 @@
 import unittest
 from concurrent import futures
 
+import six
+
 # test_interfaces is referenced from specification in this module.
 from grpc.framework.foundation import logging_pool
 from grpc.framework.interfaces.face import face
@@ -67,6 +71,9 @@
   def __iter__(self):
     return self
 
+  def __next__(self):
+    return self.next()
+
   def next(self):
     with self._condition:
       while self._paused:
@@ -104,14 +111,13 @@
           self._condition.wait()
 
 
-class TestCase(test_coverage.Coverage, unittest.TestCase):
+class TestCase(six.with_metaclass(abc.ABCMeta, test_coverage.Coverage, unittest.TestCase)):
   """A test of the Face layer of RPC Framework.
 
   Concrete subclasses must have an "implementation" attribute of type
   test_interfaces.Implementation and an "invoker_constructor" attribute of type
   _invocation.InvokerConstructor.
   """
-  __metaclass__ = abc.ABCMeta
 
   NAME = 'FutureInvocationAsynchronousEventServiceTest'
 
@@ -141,7 +147,7 @@
 
   def testSuccessfulUnaryRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
         callback = _Callback()
@@ -156,7 +162,7 @@
 
   def testSuccessfulUnaryRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -168,7 +174,7 @@
 
   def testSuccessfulStreamRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         request_iterator = _PauseableIterator(iter(requests))
@@ -188,7 +194,7 @@
 
   def testSuccessfulStreamRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         request_iterator = _PauseableIterator(iter(requests))
@@ -204,7 +210,7 @@
 
   def testSequentialInvocations(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         first_request = test_messages.request()
         second_request = test_messages.request()
@@ -223,7 +229,7 @@
 
   def testParallelInvocations(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         first_request = test_messages.request()
         second_request = test_messages.request()
@@ -239,7 +245,7 @@
         test_messages.verify(second_request, second_response, self)
 
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = []
         response_futures = []
@@ -259,7 +265,7 @@
   def testWaitingForSomeButNotAllParallelInvocations(self):
     pool = logging_pool.pool(test_constants.PARALLELISM)
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = []
         response_futures_to_indices = {}
@@ -273,7 +279,7 @@
 
         some_completed_response_futures_iterator = itertools.islice(
             futures.as_completed(response_futures_to_indices),
-            test_constants.PARALLELISM / 2)
+            test_constants.PARALLELISM // 2)
         for response_future in some_completed_response_futures_iterator:
           index = response_futures_to_indices[response_future]
           test_messages.verify(requests[index], response_future.result(), self)
@@ -281,7 +287,7 @@
 
   def testCancelledUnaryRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
         callback = _Callback()
@@ -298,7 +304,7 @@
 
   def testCancelledUnaryRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -312,7 +318,7 @@
 
   def testCancelledStreamRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         callback = _Callback()
@@ -329,7 +335,7 @@
 
   def testCancelledStreamRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -343,7 +349,7 @@
 
   def testExpiredUnaryRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
         callback = _Callback()
@@ -360,7 +366,7 @@
 
   def testExpiredUnaryRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -372,7 +378,7 @@
 
   def testExpiredStreamRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         callback = _Callback()
@@ -389,7 +395,7 @@
 
   def testExpiredStreamRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
@@ -401,7 +407,7 @@
 
   def testFailedUnaryRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
         callback = _Callback()
@@ -423,7 +429,7 @@
 
   def testFailedUnaryRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.unary_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         request = test_messages.request()
 
@@ -438,7 +444,7 @@
 
   def testFailedStreamRequestUnaryResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_unary_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
         callback = _Callback()
@@ -460,7 +466,7 @@
 
   def testFailedStreamRequestStreamResponse(self):
     for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
+        six.iteritems(self._digest.stream_stream_messages_sequences)):
       for test_messages in test_messages_sequence:
         requests = test_messages.requests()
 
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py
index 448e845..ff38dc2 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
 
 import abc
 
+import six
+
 from grpc.framework.common import cardinality
 
 _CARDINALITY_TO_GENERIC_BLOCKING_BEHAVIOR = {
@@ -62,9 +64,8 @@
 }
 
 
-class Invoker(object):
+class Invoker(six.with_metaclass(abc.ABCMeta)):
   """A type used to invoke test RPCs."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def blocking(self, group, name):
@@ -82,9 +83,8 @@
     raise NotImplementedError()
 
 
-class InvokerConstructor(object):
+class InvokerConstructor(six.with_metaclass(abc.ABCMeta)):
   """A type used to create Invokers."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def name(self):
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py
index 28941e2..bec8d51 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,16 +31,16 @@
 
 import abc
 
+import six
+
 # face is referenced from specification in this module.
 from grpc.framework.interfaces.face import face  # pylint: disable=unused-import
 from tests.unit.framework.interfaces.face import test_interfaces
 
 
-class UnaryUnaryTestMethodImplementation(test_interfaces.Method):
+class UnaryUnaryTestMethodImplementation(six.with_metaclass(abc.ABCMeta, test_interfaces.Method)):
   """A controllable implementation of a unary-unary method."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def service(self, request, response_callback, context, control):
     """Services an RPC that accepts one message and produces one message.
@@ -59,11 +59,9 @@
     raise NotImplementedError()
 
 
-class UnaryUnaryTestMessages(object):
+class UnaryUnaryTestMessages(six.with_metaclass(abc.ABCMeta)):
   """A type for unary-request-unary-response message pairings."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def request(self):
     """Affords a request message.
@@ -93,11 +91,9 @@
     raise NotImplementedError()
 
 
-class UnaryStreamTestMethodImplementation(test_interfaces.Method):
+class UnaryStreamTestMethodImplementation(six.with_metaclass(abc.ABCMeta, test_interfaces.Method)):
   """A controllable implementation of a unary-stream method."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def service(self, request, response_consumer, context, control):
     """Services an RPC that takes one message and produces a stream of messages.
@@ -116,11 +112,9 @@
     raise NotImplementedError()
 
 
-class UnaryStreamTestMessages(object):
+class UnaryStreamTestMessages(six.with_metaclass(abc.ABCMeta)):
   """A type for unary-request-stream-response message pairings."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def request(self):
     """Affords a request message.
@@ -150,11 +144,9 @@
     raise NotImplementedError()
 
 
-class StreamUnaryTestMethodImplementation(test_interfaces.Method):
+class StreamUnaryTestMethodImplementation(six.with_metaclass(abc.ABCMeta, test_interfaces.Method)):
   """A controllable implementation of a stream-unary method."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def service(self, response_callback, context, control):
     """Services an RPC that takes a stream of messages and produces one message.
@@ -180,11 +172,9 @@
     raise NotImplementedError()
 
 
-class StreamUnaryTestMessages(object):
+class StreamUnaryTestMessages(six.with_metaclass(abc.ABCMeta)):
   """A type for stream-request-unary-response message pairings."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def requests(self):
     """Affords a sequence of request messages.
@@ -214,11 +204,9 @@
     raise NotImplementedError()
 
 
-class StreamStreamTestMethodImplementation(test_interfaces.Method):
+class StreamStreamTestMethodImplementation(six.with_metaclass(abc.ABCMeta, test_interfaces.Method)):
   """A controllable implementation of a stream-stream method."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def service(self, response_consumer, context, control):
     """Services an RPC that accepts and produces streams of messages.
@@ -244,11 +232,9 @@
     raise NotImplementedError()
 
 
-class StreamStreamTestMessages(object):
+class StreamStreamTestMessages(six.with_metaclass(abc.ABCMeta)):
   """A type for stream-request-stream-response message pairings."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def requests(self):
     """Affords a sequence of request messages.
@@ -278,11 +264,9 @@
     raise NotImplementedError()
 
 
-class TestService(object):
+class TestService(six.with_metaclass(abc.ABCMeta)):
   """A specification of implemented methods to use in tests."""
 
-  __metaclass__ = abc.ABCMeta
-
   @abc.abstractmethod
   def unary_unary_scenarios(self):
     """Affords unary-request-unary-response test methods and their messages.
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py
index 462829b..06b9d77 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -34,14 +34,12 @@
 
 # test_interfaces is referenced from specification in this module.
 from tests.unit.framework.interfaces.face import _blocking_invocation_inline_service
-from tests.unit.framework.interfaces.face import _event_invocation_synchronous_event_service
 from tests.unit.framework.interfaces.face import _future_invocation_asynchronous_event_service
 from tests.unit.framework.interfaces.face import _invocation
 from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
 
 _TEST_CASE_SUPERCLASSES = (
     _blocking_invocation_inline_service.TestCase,
-    _event_invocation_synchronous_event_service.TestCase,
     _future_invocation_asynchronous_event_service.TestCase,
 )
 
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py b/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py
index b2b5c10..a5e28b7 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,13 +31,14 @@
 
 import abc
 
+import six
+
 from grpc.framework.common import cardinality  # pylint: disable=unused-import
 from grpc.framework.interfaces.face import face  # pylint: disable=unused-import
 
 
-class Method(object):
+class Method(six.with_metaclass(abc.ABCMeta)):
   """Specifies a method to be used in tests."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def group(self):
@@ -126,9 +127,8 @@
     raise NotImplementedError()
 
 
-class Implementation(object):
+class Implementation(six.with_metaclass(abc.ABCMeta)):
   """Specifies an implementation of the Face layer."""
-  __metaclass__ = abc.ABCMeta
 
   @abc.abstractmethod
   def instantiate(
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py
index dace6c2..2283e79 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,8 @@
 import abc
 import unittest  # pylint: disable=unused-import
 
+import six
+
 from grpc.framework.interfaces.links import links
 from tests.unit.framework.common import test_constants
 from tests.unit.framework.interfaces.links import test_utilities
@@ -58,13 +60,12 @@
 _TRANSMISSION_METHOD = 'TestMethod'
 
 
-class TransmissionTest(object):
+class TransmissionTest(six.with_metaclass(abc.ABCMeta)):
   """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
diff --git a/src/python/grpcio/tests/unit/test_common.py b/src/python/grpcio/tests/unit/test_common.py
index 29431bf..824f1cb 100644
--- a/src/python/grpcio/tests/unit/test_common.py
+++ b/src/python/grpcio/tests/unit/test_common.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
 
 import collections
 
+import six
+
 INVOCATION_INITIAL_METADATA = ((b'0', b'abc'), (b'1', b'def'), (b'2', b'ghi'),)
 SERVICE_INITIAL_METADATA = ((b'3', b'jkl'), (b'4', b'mno'), (b'5', b'pqr'),)
 SERVICE_TERMINAL_METADATA = ((b'6', b'stu'), (b'7', b'vwx'), (b'8', b'yza'),)
@@ -65,7 +67,7 @@
     key, value = tuple(key_value_pair)
     transmitted[key].append(value)
 
-  for key, values in original.iteritems():
+  for key, values in six.iteritems(original):
     transmitted_values = transmitted[key]
     transmitted_iterator = iter(transmitted_values)
     try:
diff --git a/src/ruby/ext/grpc/rb_call_credentials.c b/src/ruby/ext/grpc/rb_call_credentials.c
index 7c4b69f..2b978fc 100644
--- a/src/ruby/ext/grpc/rb_call_credentials.c
+++ b/src/ruby/ext/grpc/rb_call_credentials.c
@@ -41,6 +41,7 @@
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
 
 #include "rb_call.h"
 #include "rb_event_thread.h"
@@ -81,14 +82,23 @@
 static VALUE grpc_rb_call_credentials_callback_rescue(VALUE args,
                                                       VALUE exception_object) {
   VALUE result = rb_hash_new();
+  VALUE backtrace = rb_funcall(
+      rb_funcall(exception_object, rb_intern("backtrace"), 0),
+      rb_intern("join"),
+      1, rb_str_new2("\n\tfrom "));
+  VALUE exception_info = rb_funcall(exception_object, rb_intern("to_s"), 0);
+  const char *exception_classname = rb_obj_classname(exception_object);
   (void)args;
+  gpr_log(GPR_INFO, "Call credentials callback failed: %s: %s\n%s",
+          exception_classname, StringValueCStr(exception_info),
+          StringValueCStr(backtrace));
   rb_hash_aset(result, rb_str_new2("metadata"), Qnil);
   /* Currently only gives the exception class name. It should be possible get
      more details */
   rb_hash_aset(result, rb_str_new2("status"),
                INT2NUM(GRPC_STATUS_PERMISSION_DENIED));
   rb_hash_aset(result, rb_str_new2("details"),
-               rb_str_new2(rb_obj_classname(exception_object)));
+               rb_str_new2(exception_classname));
   return result;
 }
 
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index b972f60..3bf81af 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -166,7 +166,7 @@
 typedef int(*grpc_compression_algorithm_name_type)(grpc_compression_algorithm algorithm, char **name);
 extern grpc_compression_algorithm_name_type grpc_compression_algorithm_name_import;
 #define grpc_compression_algorithm_name grpc_compression_algorithm_name_import
-typedef grpc_compression_algorithm(*grpc_compression_algorithm_for_level_type)(grpc_compression_level level);
+typedef grpc_compression_algorithm(*grpc_compression_algorithm_for_level_type)(grpc_compression_level level, uint32_t accepted_encodings);
 extern grpc_compression_algorithm_for_level_type grpc_compression_algorithm_for_level_import;
 #define grpc_compression_algorithm_for_level grpc_compression_algorithm_for_level_import
 typedef void(*grpc_compression_options_init_type)(grpc_compression_options *opts);
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 42c94f0..ef08761 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.13.1.pre1'
+  VERSION = '0.14.0.dev'
 end
diff --git a/summerofcode/ideas.md b/summerofcode/ideas.md
index 83f2cec..d87cf1b 100644
--- a/summerofcode/ideas.md
+++ b/summerofcode/ideas.md
@@ -36,7 +36,7 @@
  * **Required skills:** Python programming language, PyPy Python interpreter.
  * **Likely mentors:** [Nathaniel Manista](https://github.com/nathanielmanistaatgoogle), [Masood Malekghassemi](https://github.com/soltanmm).
 1. Develop and test Python 3.5 Support for gRPC. Make necessary changes to port gRPC and package it for supported platforms.
- * **Required skills:** Python programming language, PyPy Python interpreter.
+ * **Required skills:** Python programming language, Python 3.5 interpreter.
  * **Likely mentors:** [Nathaniel Manista](https://github.com/nathanielmanistaatgoogle), [Masood Malekghassemi](https://github.com/soltanmm).
  
 gRPC Ruby/Java:
diff --git a/templates/BUILD.template b/templates/BUILD.template
index 54dc697..23a656c 100644
--- a/templates/BUILD.template
+++ b/templates/BUILD.template
@@ -49,7 +49,9 @@
       ]
     if target_dict.get('build', None) == 'protoc':
       deps.append("//external:protobuf_compiler")
-    if target_dict['name'] == 'grpc++_unsecure' or target_dict['name'] == 'grpc++':
+    if (target_dict['name'] == 'grpc++_unsecure' or
+        target_dict['name'] == 'grpc++' or
+        target_dict['name'] == 'grpc++_codegen_lib'):
       deps.append("//external:protobuf_clib")
     elif target_dict['name'] == 'grpc':
       deps.append("//external:zlib")
@@ -60,7 +62,7 @@
         deps.append(':%s' % (d))
     return deps
   %>
-  
+
   % for lib in libs:
   % if lib.build in ("all", "protoc"):
   ${cc_library(lib)}
@@ -80,13 +82,19 @@
   % endfor
   
   <%def name="cc_library(lib)">
+  <%
+    lib_hdrs = lib.get("headers", [])
+    hdrs = [h for h in lib_hdrs if not h.startswith('third_party/nanopb')]
+    srcs = [s for s in lib.src if not s.startswith('third_party/nanopb')]
+    uses_nanopb = len(lib_hdrs) != len(hdrs) or len(srcs) != len(lib.src)
+  %>
   cc_library(
     name = "${lib.name}",
     srcs = [
-  % for hdr in lib.get("headers", []):
+  % for hdr in hdrs:
       "${hdr}",
   % endfor
-  % for src in lib.src:
+  % for src in srcs:
       "${src}",
   % endfor
     ],
@@ -103,6 +111,9 @@
   % for dep in get_deps(lib):
       "${dep}",
   % endfor
+  % if uses_nanopb:
+      "//external:nanopb",
+  % endif
     ],
   % if lib.name in ("grpc", "grpc_unsecure"):
     copts = [
@@ -113,10 +124,16 @@
   </%def>
   
   <%def name="objc_library(lib)">
+  <%
+    lib_hdrs = lib.get("headers", [])
+    hdrs = [h for h in lib_hdrs if not h.startswith('third_party/nanopb')]
+    srcs = [s for s in lib.src if not s.startswith('third_party/nanopb')]
+    uses_nanopb = len(lib_hdrs) != len(hdrs) or len(srcs) != len(lib.src)
+  %>
   objc_library(
     name = "${lib.name}_objc",
     srcs = [
-  % for src in lib.src:
+  % for src in srcs:
       "${src}",
   % endfor
     ],
@@ -124,7 +141,7 @@
   % for hdr in lib.get("public_headers", []):
       "${hdr}",
   % endfor
-  % for hdr in lib.get("headers", []):
+  % for hdr in hdrs:
       "${hdr}",
   % endfor
     ],
@@ -139,6 +156,9 @@
   % if lib.get('secure', False):
       "//external:libssl_objc",
   % endif
+  % if uses_nanopb:
+      "//external:nanopb",
+  % endif
     ],
   % if lib.get("baselib", false):
     sdk_dylibs = ["libz"],
diff --git a/templates/Makefile.template b/templates/Makefile.template
index c54c146..57fc146 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -1737,7 +1737,7 @@
    $(LIBDIR)/$(CONFIG)/lib${dep}.a\
   % endfor
 
-  % if tgt.language == "c++" or tgt.boringssl:
+  % if tgt.language == "c++" or tgt.boringssl or tgt.build == 'fuzzer':
   ## C++ targets specificies.
   % if tgt.build == 'protoc':
   	$(E) "[HOSTLD]  Linking $@"
@@ -1791,6 +1791,9 @@
   % elif tgt.language == 'c++' and tgt.build == 'benchmark':
    $(GTEST_LIB)\
   % endif
+  % if tgt.build == 'fuzzer':
+   -lFuzzer\
+  % endif
    -o $(BINDIR)/$(CONFIG)/${tgt.name}
   % if tgt.build == 'protoc' or tgt.language == 'c++':
 
diff --git a/templates/composer.json.template b/templates/composer.json.template
new file mode 100644
index 0000000..275b465
--- /dev/null
+++ b/templates/composer.json.template
@@ -0,0 +1,27 @@
+%YAML 1.2
+--- |
+  {
+    "name": "grpc/grpc",
+    "type": "library",
+    "description": "gRPC library for PHP",
+    "version": "${settings.php_version.php()}",
+    "keywords": ["rpc"],
+    "homepage": "http://grpc.io",
+    "license": "BSD-3-Clause",
+    "repositories": [
+      {
+        "type": "vcs",
+        "url": "https://github.com/stanley-cheung/Protobuf-PHP"
+      }
+    ],
+    "require": {
+      "php": ">=5.5.0",
+      "datto/protobuf-php": "dev-master",
+      "google/auth": "v0.7"
+    },
+    "autoload": {
+      "psr-4": {
+        "Grpc\\": "src/php/lib/Grpc/"
+      }
+    }
+  }
diff --git a/templates/package.json.template b/templates/package.json.template
index 99e8287..9085740 100644
--- a/templates/package.json.template
+++ b/templates/package.json.template
@@ -29,6 +29,7 @@
     },
     "bundledDependencies": ["node-pre-gyp"],
     "dependencies": {
+      "arguejs": "^0.2.3",
       "lodash": "^3.9.3",
       "nan": "^2.0.0",
       "protobufjs": "^4.0.0"
diff --git a/templates/package.xml.template b/templates/package.xml.template
index d309bfd..2f498c02 100644
--- a/templates/package.xml.template
+++ b/templates/package.xml.template
@@ -15,8 +15,8 @@
    <date>2016-03-01</date>
    <time>16:06:07</time>
    <version>
-    <release>0.14.0</release>
-    <api>0.14.0</api>
+    <release>${settings.php_version.php()}</release>
+    <api>${settings.php_version.php()}</api>
    </version>
    <stability>
     <release>beta</release>
@@ -29,9 +29,9 @@
    <contents>
     <dir baseinstalldir="/" name="/">
       <file baseinstalldir="/" name="config.m4" role="src" />
+      <file baseinstalldir="/" name="src/php/README.md" role="src" />
       <file baseinstalldir="/" name="src/php/ext/grpc/CREDITS" role="src" />
       <file baseinstalldir="/" name="src/php/ext/grpc/LICENSE" role="src" />
-      <file baseinstalldir="/" name="src/php/ext/grpc/README.md" role="src" />
       % for source in php_config_m4.src + php_config_m4.headers:
       <file baseinstalldir="/" name="${source}" role="src" />
       % endfor
@@ -157,8 +157,8 @@
     </release>
     <release>
      <version>
-      <release>0.14.0</release>
-      <api>0.14.0</api>
+      <release>${settings.php_version.php()}</release>
+      <api>${settings.php_version.php()}</api>
      </version>
      <stability>
       <release>beta</release>
diff --git a/templates/src/core/surface/version.c.template b/templates/src/core/lib/surface/version.c.template
similarity index 100%
rename from templates/src/core/surface/version.c.template
rename to templates/src/core/lib/surface/version.c.template
diff --git a/templates/test/core/end2end/end2end_defs.include b/templates/test/core/end2end/end2end_defs.include
index 929827e..461c8eb 100644
--- a/templates/test/core/end2end/end2end_defs.include
+++ b/templates/test/core/end2end/end2end_defs.include
@@ -36,7 +36,9 @@
 /* This file is auto-generated */
 
 #include "test/core/end2end/end2end_tests.h"
+
 #include <string.h>
+
 #include <grpc/support/log.h>
 
 % for test in tests:
@@ -64,4 +66,4 @@
     gpr_log(GPR_DEBUG, "not a test: '%s'", argv[i]);
     abort();
   }
-}</%def>
\ No newline at end of file
+}</%def>
diff --git a/templates/tools/dockerfile/apt_get_basic.include b/templates/tools/dockerfile/apt_get_basic.include
index 547ce01..9237e7d 100644
--- a/templates/tools/dockerfile/apt_get_basic.include
+++ b/templates/tools/dockerfile/apt_get_basic.include
@@ -1,4 +1,3 @@
-<%page args="skip_golang=False"/>\
 # Install Git and basic packages.
 RUN apt-get update && apt-get install -y ${'\\'}
   autoconf ${'\\'}
@@ -10,9 +9,7 @@
   gcc ${'\\'}
   gcc-multilib ${'\\'}
   git ${'\\'}
-% if not skip_golang:
   golang ${'\\'}
-% endif
   gyp ${'\\'}
   lcov ${'\\'}
   libc6 ${'\\'}
diff --git a/templates/tools/dockerfile/clang_update.include b/templates/tools/dockerfile/clang_update.include
new file mode 100644
index 0000000..4f827c8
--- /dev/null
+++ b/templates/tools/dockerfile/clang_update.include
@@ -0,0 +1,32 @@
+#=================
+# Update clang to a version with improved tsan and fuzzing capabilities
+
+RUN apt-get update && apt-get -y install python cmake && apt-get clean
+
+RUN git clone -n -b release_38 http://llvm.org/git/llvm.git && ${'\\'}
+  cd llvm && git checkout ad57503 && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/clang.git && ${'\\'}
+  cd clang && git checkout ad2c56e && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/compiler-rt.git && ${'\\'}
+  cd compiler-rt && git checkout 3176922 && cd ..
+RUN git clone -n -b release_38 ${'\\'}
+  http://llvm.org/git/clang-tools-extra.git && cd clang-tools-extra && ${'\\'}
+  git checkout c288525 && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/libcxx.git && ${'\\'}
+  cd libcxx && git checkout fda3549  && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/libcxxabi.git && ${'\\'}
+  cd libcxxabi && git checkout 8d4e51d && cd ..
+
+RUN mv clang llvm/tools
+RUN mv compiler-rt llvm/projects
+RUN mv clang-tools-extra llvm/tools/clang/tools
+RUN mv libcxx llvm/projects
+RUN mv libcxxabi llvm/projects
+
+RUN mkdir llvm-build
+RUN cd llvm-build && cmake ${'\\'}
+  -DCMAKE_BUILD_TYPE:STRING=Release ${'\\'}
+  -DCMAKE_INSTALL_PREFIX:STRING=/usr ${'\\'}
+  -DLLVM_TARGETS_TO_BUILD:STRING=X86 ${'\\'}
+  ../llvm
+RUN make -C llvm-build -j 12 && make -C llvm-build install && rm -rf llvm-build
diff --git a/templates/tools/dockerfile/gcp_api_libraries.include b/templates/tools/dockerfile/gcp_api_libraries.include
new file mode 100644
index 0000000..669b0f8
--- /dev/null
+++ b/templates/tools/dockerfile/gcp_api_libraries.include
@@ -0,0 +1,4 @@
+# Google Cloud platform API libraries
+RUN apt-get update && apt-get install -y python-pip && apt-get clean
+RUN pip install --upgrade google-api-python-client
+
diff --git a/templates/tools/dockerfile/grpc_interop_stress_cxx/Dockerfile.template b/templates/tools/dockerfile/grpc_interop_stress_cxx/Dockerfile.template
new file mode 100644
index 0000000..b1049d0
--- /dev/null
+++ b/templates/tools/dockerfile/grpc_interop_stress_cxx/Dockerfile.template
@@ -0,0 +1,40 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../apt_get_basic.include"/>
+  <%include file="../ccache_setup.include"/>
+  <%include file="../cxx_deps.include"/>
+  <%include file="../gcp_api_libraries.include"/>
+  <%include file="../clang_update.include"/>
+  # Define the default command.
+  CMD ["bash"]
diff --git a/templates/tools/dockerfile/run_tests_addons.include b/templates/tools/dockerfile/run_tests_addons.include
index 30d22be..27ac67f 100644
--- a/templates/tools/dockerfile/run_tests_addons.include
+++ b/templates/tools/dockerfile/run_tests_addons.include
@@ -1,10 +1,7 @@
-<%page args="skip_zookeeper=False"/>\
 <%include file="ccache_setup.include"/>
-% if not skip_zookeeper:
 #======================
 # Zookeeper dependencies
 # TODO(jtattermusch): is zookeeper still needed?
 RUN apt-get install -y libzookeeper-mt-dev
-% endif
 
 RUN mkdir /var/local/jenkins
diff --git a/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template
index 842c534..eb11ce3 100644
--- a/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template
@@ -33,7 +33,7 @@
   
   <%include file="../../apt_get_basic.include"/>
   <%include file="../../cxx_deps.include"/>
+  <%include file="../../clang_update.include"/>
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
   CMD ["bash"]
-  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/cxx_squeeze_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_squeeze_x64/Dockerfile.template
deleted file mode 100644
index 49371aa..0000000
--- a/templates/tools/dockerfile/test/cxx_squeeze_x64/Dockerfile.template
+++ /dev/null
@@ -1,48 +0,0 @@
-%YAML 1.2
---- |
-  # Copyright 2016, Google Inc.
-  # All rights reserved.
-  #
-  # Redistribution and use in source and binary forms, with or without
-  # modification, are permitted provided that the following conditions are
-  # met:
-  #
-  #     * Redistributions of source code must retain the above copyright
-  # notice, this list of conditions and the following disclaimer.
-  #     * Redistributions in binary form must reproduce the above
-  # copyright notice, this list of conditions and the following disclaimer
-  # in the documentation and/or other materials provided with the
-  # distribution.
-  #     * Neither the name of Google Inc. nor the names of its
-  # contributors may be used to endorse or promote products derived from
-  # this software without specific prior written permission.
-  #
-  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-  FROM debian:squeeze
-
-  <%include file="../../apt_get_basic.include" args="skip_golang=True"/>
-
-  # libgflags-dev is not available on squeezy
-  RUN apt-get update && apt-get -y install libgtest-dev libc++-dev clang && apt-get clean
-
-  RUN apt-get update && apt-get -y install python-pip && apt-get clean
-  RUN pip install argparse
-
-  RUN wget ${openssl_fallback.base_uri + openssl_fallback.tarball}
-
-  ENV POST_GIT_STEP tools/dockerfile/test/cxx_squeeze_x64/post-git-setup.sh
-
-  <%include file="../../run_tests_addons.include" args="skip_zookeeper=True"/>
-  # Define the default command.
-  CMD ["bash"]
diff --git a/templates/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile.template
new file mode 100644
index 0000000..d824220
--- /dev/null
+++ b/templates/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM ubuntu:14.04
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../cxx_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile.template
new file mode 100644
index 0000000..7956798
--- /dev/null
+++ b/templates/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile.template
@@ -0,0 +1,47 @@
+%YAML 1.2
+--- |
+  # Copyright 2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  FROM debian:wheezy
+
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../cxx_deps.include"/>
+
+  RUN apt-get update && apt-get install -y ${'\\'}
+    gcc-4.4 ${'\\'}
+    gcc-4.4-multilib
+
+  RUN wget ${openssl_fallback.base_uri + openssl_fallback.tarball}
+
+  ENV POST_GIT_STEP tools/dockerfile/test/cxx_wheezy_x64/post-git-setup.sh
+
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
diff --git a/templates/tools/dockerfile/test/cxx_squeeze_x64/post-git-setup.sh.template b/templates/tools/dockerfile/test/cxx_wheezy_x64/post-git-setup.sh.template
similarity index 100%
rename from templates/tools/dockerfile/test/cxx_squeeze_x64/post-git-setup.sh.template
rename to templates/tools/dockerfile/test/cxx_wheezy_x64/post-git-setup.sh.template
diff --git a/templates/tools/dockerfile/test/fuzzer/Dockerfile.template b/templates/tools/dockerfile/test/fuzzer/Dockerfile.template
new file mode 100644
index 0000000..479be05
--- /dev/null
+++ b/templates/tools/dockerfile/test/fuzzer/Dockerfile.template
@@ -0,0 +1,43 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  FROM debian:jessie
+
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../cxx_deps.include"/>
+  <%include file="../../clang_update.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  RUN clang++ -c -g -O2 -std=c++11 llvm/lib/Fuzzer/*.cpp -IFuzzer
+  RUN ar ruv libFuzzer.a Fuzzer*.o
+  RUN mv libFuzzer.a /usr/lib
+  RUN rm -f Fuzzer*.o
+  # Define the default command.
+  CMD ["bash"]
diff --git a/templates/tools/dockerfile/test/multilang_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/multilang_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..fdf4431
--- /dev/null
+++ b/templates/tools/dockerfile/test/multilang_jessie_x64/Dockerfile.template
@@ -0,0 +1,43 @@
+%YAML 1.2
+--- |
+  # Copyright 2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../csharp_deps.include"/>
+  <%include file="../../cxx_deps.include"/>
+  <%include file="../../node_deps.include"/>
+  <%include file="../../php_deps.include"/>
+  <%include file="../../ruby_deps.include"/>
+  <%include file="../../python_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
diff --git a/templates/tools/dockerfile/test/sanity/Dockerfile.template b/templates/tools/dockerfile/test/sanity/Dockerfile.template
index ad1d92e..8265c09 100644
--- a/templates/tools/dockerfile/test/sanity/Dockerfile.template
+++ b/templates/tools/dockerfile/test/sanity/Dockerfile.template
@@ -34,7 +34,13 @@
   <%include file="../../apt_get_basic.include"/>
   #========================
   # Sanity test dependencies
-  RUN apt-get update && apt-get install -y python-pip
+  RUN apt-get update && apt-get install -y ${"\\"}
+        python-pip ${"\\"}
+        autoconf ${"\\"}
+        automake ${"\\"}
+        libtool ${"\\"}
+        curl ${"\\"}
+        python-virtualenv
   RUN pip install simplejson mako
 
   #===================
diff --git a/templates/tools/fuzzer/runners.template b/templates/tools/fuzzer/runners.template
new file mode 100644
index 0000000..aa81a65
--- /dev/null
+++ b/templates/tools/fuzzer/runners.template
@@ -0,0 +1,44 @@
+%YAML 1.2
+---
+foreach: targets
+cond: selected.build == 'fuzzer'
+output_name: ${selected.name}.sh
+template: |
+  #!/bin/bash
+  # Copyright 2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  #
+
+  flags="-max_total_time=3600 -jobs=3 -workers=3"
+  if [ "$config" == "asan-trace-cmp" ]
+  then
+    flags="-use_traces=1 $flags"
+  fi
+
+  bins/$config/${selected.name} $flags fuzzer_output ${' '.join(selected.corpus_dirs)}
diff --git a/templates/vsprojects/buildtests_c.sln.template b/templates/vsprojects/buildtests_c.sln.template
index a985fea..21312ab 100644
--- a/templates/vsprojects/buildtests_c.sln.template
+++ b/templates/vsprojects/buildtests_c.sln.template
@@ -2,6 +2,6 @@
 --- |
   <%namespace file="sln_defs.include" import="gen_solution"/>\
   <%
-  solution_projects = [p for p in vsprojects if p.build != 'protoc' and p.language == 'c' and not p.boringssl and not p.zlib]
+  solution_projects = [p for p in vsprojects if p.build not in ['protoc', 'fuzzer'] and p.language == 'c' and not p.boringssl and not p.zlib]
   %>\
   ${gen_solution(solution_projects, use_dlls='yes')}
diff --git a/templates/vsprojects/grpc.sln.template b/templates/vsprojects/grpc.sln.template
index dbbb2c2..ded9838 100644
--- a/templates/vsprojects/grpc.sln.template
+++ b/templates/vsprojects/grpc.sln.template
@@ -2,6 +2,6 @@
 --- |
   <%namespace file="sln_defs.include" import="gen_solution"/>\
   <%
-  solution_projects = [p for p in vsprojects if p.build not in ['protoc', 'test'] and p.language in ['c', 'c++'] and p.vs_proj_dir == '.' and not (p.build == 'private' and p.language == 'c++')]
+  solution_projects = [p for p in vsprojects if p.build not in ['protoc', 'test', 'fuzzer'] and p.language in ['c', 'c++'] and p.vs_proj_dir == '.' and not (p.build == 'private' and p.language == 'c++')]
   %>\
   ${gen_solution(solution_projects, use_dlls='yes')}
diff --git a/templates/vsprojects/vcxproj.template b/templates/vsprojects/vcxproj.template
index ecf113b..0bb208f 100644
--- a/templates/vsprojects/vcxproj.template
+++ b/templates/vsprojects/vcxproj.template
@@ -2,12 +2,14 @@
 ---
 foreach: vsprojects
 output_name: ${selected.vs_proj_dir}/${selected.name}/${selected.name}.vcxproj
+cond: selected.build not in ['fuzzer']
 template: |
   <%namespace file="vcxproj_defs.include" import="gen_project"/>\
   ${gen_project(selected.name, vsprojects)}
 ---
 foreach: vsprojects
 output_name: ${selected.vs_proj_dir}/${selected.name}/${selected.name}.vcxproj.filters
+cond: selected.build not in ['fuzzer']
 template: |
   <%namespace file="vcxproj.filters_defs.include" import="gen_filters"/>\
   ${gen_filters(selected.name, vsprojects)}
diff --git a/templates/vsprojects/vcxproj_defs.include b/templates/vsprojects/vcxproj_defs.include
index e598f13..72a077f 100644
--- a/templates/vsprojects/vcxproj_defs.include
+++ b/templates/vsprojects/vcxproj_defs.include
@@ -227,7 +227,7 @@
       % endif
     % endfor
   </ItemGroup>
-  % elif configuration_type != 'StaticLibrary':
+  % else:
   <ItemGroup>
     <ClCompile Include="${repo_root}\${to_windows_path('vsprojects/dummy.c')}">
     </ClCompile>
diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index 1a2ca6f..7fd7a00 100644
--- a/test/core/bad_client/bad_client.c
+++ b/test/core/bad_client/bad_client.c
@@ -33,13 +33,13 @@
 
 #include "test/core/bad_client/bad_client.h"
 
-#include "src/core/channel/channel_stack.h"
-#include "src/core/channel/http_server_filter.h"
-#include "src/core/iomgr/endpoint_pair.h"
-#include "src/core/surface/completion_queue.h"
-#include "src/core/surface/server.h"
-#include "src/core/support/string.h"
-#include "src/core/transport/chttp2_transport.h"
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/completion_queue.h"
+#include "src/core/lib/surface/server.h"
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/sync.h>
@@ -67,11 +67,8 @@
 
 static void server_setup_transport(void *ts, grpc_transport *transport) {
   thd_args *a = ts;
-  static grpc_channel_filter const *extra_filters[] = {
-      &grpc_http_server_filter};
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_server_setup_transport(&exec_ctx, a->server, transport, extra_filters,
-                              GPR_ARRAY_SIZE(extra_filters),
+  grpc_server_setup_transport(&exec_ctx, a->server, transport,
                               grpc_server_get_channel_args(a->server));
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -105,7 +102,7 @@
   sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);
 
   /* Create server, completion events */
-  a.server = grpc_server_create_from_filters(NULL, 0, NULL);
+  a.server = grpc_server_create(NULL, NULL);
   a.cq = grpc_completion_queue_create(NULL);
   gpr_event_init(&a.done_thd);
   gpr_event_init(&a.done_write);
@@ -158,9 +155,9 @@
     grpc_exec_ctx_finish(&exec_ctx);
   }
   grpc_server_shutdown_and_notify(a.server, a.cq, NULL);
-  GPR_ASSERT(grpc_completion_queue_pluck(a.cq, NULL,
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 a.cq, NULL, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(a.server);
   grpc_completion_queue_destroy(a.cq);
   gpr_slice_buffer_destroy(&outgoing);
diff --git a/test/core/bad_client/tests/badreq.c b/test/core/bad_client/tests/badreq.c
index 6d59d25..fd3d13f 100644
--- a/test/core/bad_client/tests/badreq.c
+++ b/test/core/bad_client/tests/badreq.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,8 @@
 
 #include <string.h>
 
+#include "src/core/lib/surface/server.h"
 #include "test/core/end2end/cq_verifier.h"
-#include "src/core/surface/server.h"
 
 #define PFX_STR                      \
   "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \
@@ -45,9 +45,9 @@
 static void verifier(grpc_server *server, grpc_completion_queue *cq,
                      void *registered_method) {
   while (grpc_server_has_open_connections(server)) {
-    GPR_ASSERT(grpc_completion_queue_next(cq,
-                                          GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20),
-                                          NULL).type == GRPC_QUEUE_TIMEOUT);
+    GPR_ASSERT(grpc_completion_queue_next(
+                   cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20), NULL)
+                   .type == GRPC_QUEUE_TIMEOUT);
   }
 }
 
diff --git a/test/core/bad_client/tests/connection_prefix.c b/test/core/bad_client/tests/connection_prefix.c
index 66ff8c2..87826af 100644
--- a/test/core/bad_client/tests/connection_prefix.c
+++ b/test/core/bad_client/tests/connection_prefix.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,15 +31,15 @@
  *
  */
 
+#include "src/core/lib/surface/server.h"
 #include "test/core/bad_client/bad_client.h"
-#include "src/core/surface/server.h"
 
 static void verifier(grpc_server *server, grpc_completion_queue *cq,
                      void *registered_method) {
   while (grpc_server_has_open_connections(server)) {
-    GPR_ASSERT(grpc_completion_queue_next(cq,
-                                          GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20),
-                                          NULL).type == GRPC_QUEUE_TIMEOUT);
+    GPR_ASSERT(grpc_completion_queue_next(
+                   cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20), NULL)
+                   .type == GRPC_QUEUE_TIMEOUT);
   }
 }
 
diff --git a/test/core/bad_client/tests/headers.c b/test/core/bad_client/tests/headers.c
index 2186a4f..f66f14d 100644
--- a/test/core/bad_client/tests/headers.c
+++ b/test/core/bad_client/tests/headers.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,8 @@
  *
  */
 
+#include "src/core/lib/surface/server.h"
 #include "test/core/bad_client/bad_client.h"
-#include "src/core/surface/server.h"
 
 #define PFX_STR                      \
   "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \
@@ -41,9 +41,9 @@
 static void verifier(grpc_server *server, grpc_completion_queue *cq,
                      void *registered_method) {
   while (grpc_server_has_open_connections(server)) {
-    GPR_ASSERT(grpc_completion_queue_next(cq,
-                                          GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20),
-                                          NULL).type == GRPC_QUEUE_TIMEOUT);
+    GPR_ASSERT(grpc_completion_queue_next(
+                   cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20), NULL)
+                   .type == GRPC_QUEUE_TIMEOUT);
   }
 }
 
diff --git a/test/core/bad_client/tests/initial_settings_frame.c b/test/core/bad_client/tests/initial_settings_frame.c
index fb6149c..b303f03 100644
--- a/test/core/bad_client/tests/initial_settings_frame.c
+++ b/test/core/bad_client/tests/initial_settings_frame.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,8 @@
  *
  */
 
+#include "src/core/lib/surface/server.h"
 #include "test/core/bad_client/bad_client.h"
-#include "src/core/surface/server.h"
 
 #define PFX_STR "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
 #define ONE_SETTING_HDR "\x00\x00\x06\x04\x00\x00\x00\x00\x00"
@@ -40,9 +40,9 @@
 static void verifier(grpc_server *server, grpc_completion_queue *cq,
                      void *registered_method) {
   while (grpc_server_has_open_connections(server)) {
-    GPR_ASSERT(grpc_completion_queue_next(cq,
-                                          GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20),
-                                          NULL).type == GRPC_QUEUE_TIMEOUT);
+    GPR_ASSERT(grpc_completion_queue_next(
+                   cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20), NULL)
+                   .type == GRPC_QUEUE_TIMEOUT);
   }
 }
 
diff --git a/test/core/bad_client/tests/server_registered_method.c b/test/core/bad_client/tests/server_registered_method.c
index dc6ecc5..c35457c 100644
--- a/test/core/bad_client/tests/server_registered_method.c
+++ b/test/core/bad_client/tests/server_registered_method.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,8 @@
 
 #include <string.h>
 
+#include "src/core/lib/surface/server.h"
 #include "test/core/end2end/cq_verifier.h"
-#include "src/core/surface/server.h"
 
 #define PFX_STR                                               \
   "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"                          \
diff --git a/test/core/bad_client/tests/simple_request.c b/test/core/bad_client/tests/simple_request.c
index c04319e..6cb44ee 100644
--- a/test/core/bad_client/tests/simple_request.c
+++ b/test/core/bad_client/tests/simple_request.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,8 @@
 
 #include <string.h>
 
+#include "src/core/lib/surface/server.h"
 #include "test/core/end2end/cq_verifier.h"
-#include "src/core/surface/server.h"
 
 #define PFX_STR                                                            \
   "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"                                       \
@@ -108,9 +108,9 @@
 static void failure_verifier(grpc_server *server, grpc_completion_queue *cq,
                              void *registered_method) {
   while (grpc_server_has_open_connections(server)) {
-    GPR_ASSERT(grpc_completion_queue_next(cq,
-                                          GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20),
-                                          NULL).type == GRPC_QUEUE_TIMEOUT);
+    GPR_ASSERT(grpc_completion_queue_next(
+                   cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20), NULL)
+                   .type == GRPC_QUEUE_TIMEOUT);
   }
 }
 
diff --git a/test/core/bad_client/tests/unknown_frame.c b/test/core/bad_client/tests/unknown_frame.c
index 2ef340e..44d1e35 100644
--- a/test/core/bad_client/tests/unknown_frame.c
+++ b/test/core/bad_client/tests/unknown_frame.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,8 @@
  *
  */
 
+#include "src/core/lib/surface/server.h"
 #include "test/core/bad_client/bad_client.h"
-#include "src/core/surface/server.h"
 
 #define PFX_STR                      \
   "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \
@@ -41,9 +41,9 @@
 static void verifier(grpc_server *server, grpc_completion_queue *cq,
                      void *registered_method) {
   while (grpc_server_has_open_connections(server)) {
-    GPR_ASSERT(grpc_completion_queue_next(cq,
-                                          GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20),
-                                          NULL).type == GRPC_QUEUE_TIMEOUT);
+    GPR_ASSERT(grpc_completion_queue_next(
+                   cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20), NULL)
+                   .type == GRPC_QUEUE_TIMEOUT);
   }
 }
 
diff --git a/test/core/bad_client/tests/window_overflow.c b/test/core/bad_client/tests/window_overflow.c
index 646d5c5..b6d0101 100644
--- a/test/core/bad_client/tests/window_overflow.c
+++ b/test/core/bad_client/tests/window_overflow.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,7 +37,7 @@
 
 #include <grpc/support/alloc.h>
 
-#include "src/core/surface/server.h"
+#include "src/core/lib/surface/server.h"
 
 #define PFX_STR                                                            \
   "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"                                       \
@@ -60,9 +60,9 @@
 static void verifier(grpc_server *server, grpc_completion_queue *cq,
                      void *registered_method) {
   while (grpc_server_has_open_connections(server)) {
-    GPR_ASSERT(grpc_completion_queue_next(cq,
-                                          GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20),
-                                          NULL).type == GRPC_QUEUE_TIMEOUT);
+    GPR_ASSERT(grpc_completion_queue_next(
+                   cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(20), NULL)
+                   .type == GRPC_QUEUE_TIMEOUT);
   }
 }
 
@@ -90,8 +90,15 @@
 
   addbuf(PFX_STR, sizeof(PFX_STR) - 1);
   for (i = 0; i < NUM_FRAMES; i++) {
-    uint8_t hdr[9] = {(uint8_t)(FRAME_SIZE >> 16), (uint8_t)(FRAME_SIZE >> 8),
-                      (uint8_t)FRAME_SIZE, 0, 0, 0, 0, 0, 1};
+    uint8_t hdr[9] = {(uint8_t)(FRAME_SIZE >> 16),
+                      (uint8_t)(FRAME_SIZE >> 8),
+                      (uint8_t)FRAME_SIZE,
+                      0,
+                      0,
+                      0,
+                      0,
+                      0,
+                      1};
     addbuf(hdr, sizeof(hdr));
     for (j = 0; j < MESSAGES_PER_FRAME; j++) {
       uint8_t message[5] = {0, 0, 0, 0, 0};
diff --git a/test/core/bad_ssl/bad_ssl_test.c b/test/core/bad_ssl/bad_ssl_test.c
index a78a079..013b8ea 100644
--- a/test/core/bad_ssl/bad_ssl_test.c
+++ b/test/core/bad_ssl/bad_ssl_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,8 @@
  *
  */
 
-#include <string.h>
 #include <stdio.h>
+#include <string.h>
 
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
@@ -41,9 +41,10 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/subprocess.h>
-#include "src/core/support/string.h"
-#include "test/core/util/port.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
+#include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
 static void *tag(intptr_t t) { return (void *)t; }
@@ -144,6 +145,9 @@
   } else {
     strcpy(root, ".");
   }
+  if (argc == 2) {
+    gpr_setenv("GRPC_DEFAULT_SSL_ROOTS_FILE_PATH", argv[1]);
+  }
   /* figure out our test name */
   tmp = lunder - 1;
   while (*tmp != '_') tmp--;
diff --git a/test/core/bad_ssl/servers/alpn.c b/test/core/bad_ssl/servers/alpn.c
index c8cc83b..3225fd0 100644
--- a/test/core/bad_ssl/servers/alpn.c
+++ b/test/core/bad_ssl/servers/alpn.c
@@ -38,7 +38,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/transport/chttp2/alpn.h"
+#include "src/core/ext/transport/chttp2/transport/alpn.h"
 #include "test/core/bad_ssl/server_common.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 
diff --git a/test/core/bad_ssl/servers/cert.c b/test/core/bad_ssl/servers/cert.c
index 4edef50..7307682 100644
--- a/test/core/bad_ssl/servers/cert.c
+++ b/test/core/bad_ssl/servers/cert.c
@@ -38,7 +38,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/support/load_file.h"
+#include "src/core/lib/support/load_file.h"
 
 #include "test/core/bad_ssl/server_common.h"
 #include "test/core/end2end/data/ssl_test_data.h"
@@ -56,9 +56,11 @@
 
   grpc_init();
 
-  cert_slice = gpr_load_file("src/core/tsi/test_creds/badserver.pem", 1, &ok);
+  cert_slice =
+      gpr_load_file("src/core/lib/tsi/test_creds/badserver.pem", 1, &ok);
   GPR_ASSERT(ok);
-  key_slice = gpr_load_file("src/core/tsi/test_creds/badserver.key", 1, &ok);
+  key_slice =
+      gpr_load_file("src/core/lib/tsi/test_creds/badserver.key", 1, &ok);
   GPR_ASSERT(ok);
   pem_key_cert_pair.private_key = (const char *)GPR_SLICE_START_PTR(key_slice);
   pem_key_cert_pair.cert_chain = (const char *)GPR_SLICE_START_PTR(cert_slice);
diff --git a/test/core/census/mlog_test.c b/test/core/census/mlog_test.c
index 5b6c594..a1fadc2 100644
--- a/test/core/census/mlog_test.c
+++ b/test/core/census/mlog_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/census/mlog.h"
+#include "src/core/lib/census/mlog.h"
 #include <grpc/support/cpu.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
@@ -332,7 +332,7 @@
 
 static void setup_test(int circular_log) {
   census_log_initialize(LOG_SIZE_IN_MB, circular_log);
-  GPR_ASSERT(census_log_remaining_space() == LOG_SIZE_IN_BYTES);
+  //  GPR_ASSERT(census_log_remaining_space() == LOG_SIZE_IN_BYTES);
 }
 
 // Attempts to create a record of invalid size (size >
@@ -352,8 +352,8 @@
   // check can fail if the thread is context switched to a new CPU during the
   // start_write execution (multiple blocks get allocated), but this has not
   // been observed in practice.
-  GPR_ASSERT(LOG_SIZE_IN_BYTES - CENSUS_LOG_MAX_RECORD_SIZE ==
-             census_log_remaining_space());
+  //  GPR_ASSERT(LOG_SIZE_IN_BYTES - CENSUS_LOG_MAX_RECORD_SIZE ==
+  //             census_log_remaining_space());
   census_log_shutdown();
 }
 
diff --git a/test/core/channel/channel_args_test.c b/test/core/channel/channel_args_test.c
index 0b74dee..352dfa0 100644
--- a/test/core/channel/channel_args_test.c
+++ b/test/core/channel/channel_args_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,7 +36,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/channel/channel_args.h"
+#include "src/core/lib/channel/channel_args.h"
 
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
index e19e9a5..49e9c7e 100644
--- a/test/core/channel/channel_stack_test.c
+++ b/test/core/channel/channel_stack_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/channel/channel_stack.h"
+#include "src/core/lib/channel/channel_stack.h"
 
 #include <string.h>
 
@@ -92,10 +92,17 @@
 }
 
 static void test_create_channel_stack(void) {
-  const grpc_channel_filter filter = {
-      call_func, channel_func, sizeof(int), call_init_func,
-      grpc_call_stack_ignore_set_pollset, call_destroy_func, sizeof(int),
-      channel_init_func, channel_destroy_func, get_peer, "some_test_filter"};
+  const grpc_channel_filter filter = {call_func,
+                                      channel_func,
+                                      sizeof(int),
+                                      call_init_func,
+                                      grpc_call_stack_ignore_set_pollset,
+                                      call_destroy_func,
+                                      sizeof(int),
+                                      channel_init_func,
+                                      channel_destroy_func,
+                                      get_peer,
+                                      "some_test_filter"};
   const grpc_channel_filter *filters = &filter;
   grpc_channel_stack *channel_stack;
   grpc_call_stack *call_stack;
diff --git a/test/core/client_config/lb_policies_test.c b/test/core/client_config/lb_policies_test.c
index cb99b3d..bc7040d 100644
--- a/test/core/client_config/lb_policies_test.c
+++ b/test/core/client_config/lb_policies_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,17 +41,19 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 
-#include "src/core/channel/channel_stack.h"
-#include "src/core/channel/client_channel.h"
-#include "src/core/client_config/lb_policies/round_robin.h"
-#include "src/core/client_config/lb_policy_registry.h"
-#include "src/core/support/string.h"
-#include "src/core/surface/channel.h"
-#include "src/core/surface/server.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/client_config/lb_policies/round_robin.h"
+#include "src/core/lib/client_config/lb_policy_registry.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
+#define RETRY_TIMEOUT 300
+
 typedef struct servers_fixture {
   size_t num_servers;
   grpc_server **servers;
@@ -137,8 +139,9 @@
   gpr_log(GPR_INFO, "KILLING SERVER %d", i);
   GPR_ASSERT(f->servers[i] != NULL);
   grpc_server_shutdown_and_notify(f->servers[i], f->cq, tag(10000));
-  GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(10000), n_millis_time(5000),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(
+      grpc_completion_queue_pluck(f->cq, tag(10000), n_millis_time(5000), NULL)
+          .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->servers[i]);
   f->servers[i] = NULL;
 }
@@ -204,8 +207,8 @@
     if (f->servers[i] == NULL) continue;
     grpc_server_shutdown_and_notify(f->servers[i], f->cq, tag(10000));
     GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(10000),
-                                           n_millis_time(5000),
-                                           NULL).type == GRPC_OP_COMPLETE);
+                                           n_millis_time(5000), NULL)
+                   .type == GRPC_OP_COMPLETE);
     grpc_server_destroy(f->servers[i]);
   }
   grpc_completion_queue_shutdown(f->cq);
@@ -302,9 +305,10 @@
                grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL));
 
     s_idx = -1;
-    while ((ev = grpc_completion_queue_next(
-                f->cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), NULL)).type !=
-           GRPC_QUEUE_TIMEOUT) {
+    while (
+        (ev = grpc_completion_queue_next(
+             f->cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(10 * RETRY_TIMEOUT), NULL))
+            .type != GRPC_QUEUE_TIMEOUT) {
       GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
       read_tag = ((int)(intptr_t)ev.tag);
       gpr_log(GPR_DEBUG, "EVENT: success:%d, type:%d, tag:%d iter:%d",
@@ -376,9 +380,10 @@
       }
     }
 
-    GPR_ASSERT(grpc_completion_queue_next(f->cq,
-                                          GRPC_TIMEOUT_MILLIS_TO_DEADLINE(200),
-                                          NULL).type == GRPC_QUEUE_TIMEOUT);
+    GPR_ASSERT(
+        grpc_completion_queue_next(
+            f->cq, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(2 * RETRY_TIMEOUT), NULL)
+            .type == GRPC_QUEUE_TIMEOUT);
 
     grpc_metadata_array_destroy(&rdata->initial_metadata_recv);
     grpc_metadata_array_destroy(&rdata->trailing_metadata_recv);
@@ -506,7 +511,7 @@
 
   arg.type = GRPC_ARG_INTEGER;
   arg.key = "grpc.testing.fixed_reconnect_backoff";
-  arg.value.integer = 100;
+  arg.value.integer = RETRY_TIMEOUT;
   args.num_args = 1;
   args.args = &arg;
 
@@ -542,7 +547,7 @@
 
   arg.type = GRPC_ARG_INTEGER;
   arg.key = "grpc.testing.fixed_reconnect_backoff";
-  arg.value.integer = 100;
+  arg.value.integer = RETRY_TIMEOUT;
   args.num_args = 1;
   args.args = &arg;
 
@@ -868,6 +873,7 @@
 }
 
 int main(int argc, char **argv) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   test_spec *spec;
   size_t i;
   const size_t NUM_ITERS = 10;
@@ -877,9 +883,9 @@
   grpc_init();
   grpc_lb_round_robin_trace = 1;
 
-  GPR_ASSERT(grpc_lb_policy_create("this-lb-policy-does-not-exist", NULL) ==
-             NULL);
-  GPR_ASSERT(grpc_lb_policy_create(NULL, NULL) == NULL);
+  GPR_ASSERT(grpc_lb_policy_create(&exec_ctx, "this-lb-policy-does-not-exist",
+                                   NULL) == NULL);
+  GPR_ASSERT(grpc_lb_policy_create(&exec_ctx, NULL, NULL) == NULL);
 
   spec = test_spec_create(NUM_ITERS, NUM_SERVERS);
   /* everything is fine, all servers stay up the whole time and life's peachy */
@@ -931,6 +937,7 @@
   test_pending_calls(4);
   test_ping();
 
+  grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
   return 0;
 }
diff --git a/test/core/client_config/resolvers/dns_resolver_connectivity_test.c b/test/core/client_config/resolvers/dns_resolver_connectivity_test.c
new file mode 100644
index 0000000..dc6a614
--- /dev/null
+++ b/test/core/client_config/resolvers/dns_resolver_connectivity_test.c
@@ -0,0 +1,148 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/client_config/resolvers/dns_resolver.h"
+
+#include <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "test/core/util/test_config.h"
+
+static void subchannel_factory_ref(grpc_subchannel_factory *scv) {}
+static void subchannel_factory_unref(grpc_exec_ctx *exec_ctx,
+                                     grpc_subchannel_factory *scv) {}
+static grpc_subchannel *subchannel_factory_create_subchannel(
+    grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *factory,
+    grpc_subchannel_args *args) {
+  return NULL;
+}
+
+static const grpc_subchannel_factory_vtable sc_vtable = {
+    subchannel_factory_ref, subchannel_factory_unref,
+    subchannel_factory_create_subchannel};
+
+static grpc_subchannel_factory sc_factory = {&sc_vtable};
+
+static gpr_mu g_mu;
+static bool g_fail_resolution = true;
+
+static grpc_resolved_addresses *my_resolve_address(const char *name,
+                                                   const char *addr) {
+  gpr_mu_lock(&g_mu);
+  GPR_ASSERT(0 == strcmp("test", name));
+  if (g_fail_resolution) {
+    g_fail_resolution = false;
+    gpr_mu_unlock(&g_mu);
+    return NULL;
+  } else {
+    gpr_mu_unlock(&g_mu);
+    grpc_resolved_addresses *addrs = gpr_malloc(sizeof(*addrs));
+    addrs->naddrs = 1;
+    addrs->addrs = gpr_malloc(sizeof(*addrs->addrs));
+    addrs->addrs[0].len = 123;
+    return addrs;
+  }
+}
+
+static grpc_resolver *create_resolver(const char *name) {
+  grpc_resolver_factory *factory = grpc_dns_resolver_factory_create();
+  grpc_uri *uri = grpc_uri_parse(name, 0);
+  GPR_ASSERT(uri);
+  grpc_resolver_args args;
+  memset(&args, 0, sizeof(args));
+  args.uri = uri;
+  args.subchannel_factory = &sc_factory;
+  grpc_resolver *resolver =
+      grpc_resolver_factory_create_resolver(factory, &args);
+  grpc_resolver_factory_unref(factory);
+  grpc_uri_destroy(uri);
+  return resolver;
+}
+
+static void on_done(grpc_exec_ctx *exec_ctx, void *ev, bool success) {
+  gpr_event_set(ev, (void *)1);
+}
+
+// interleave waiting for an event with a timer check
+static bool wait_loop(int deadline_seconds, gpr_event *ev) {
+  while (deadline_seconds) {
+    gpr_log(GPR_DEBUG, "Test: waiting for %d more seconds", deadline_seconds);
+    if (gpr_event_wait(ev, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1))) return true;
+    deadline_seconds--;
+
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_timer_check(&exec_ctx, gpr_now(GPR_CLOCK_MONOTONIC), NULL);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
+  return false;
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+
+  grpc_init();
+  gpr_mu_init(&g_mu);
+  grpc_blocking_resolve_address = my_resolve_address;
+
+  grpc_resolver *resolver = create_resolver("dns:test");
+
+  grpc_client_config *config = (grpc_client_config *)1;
+
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  gpr_event ev1;
+  gpr_event_init(&ev1);
+  grpc_resolver_next(&exec_ctx, resolver, &config,
+                     grpc_closure_create(on_done, &ev1));
+  grpc_exec_ctx_flush(&exec_ctx);
+  GPR_ASSERT(wait_loop(5, &ev1));
+  GPR_ASSERT(config == NULL);
+
+  gpr_event ev2;
+  gpr_event_init(&ev2);
+  grpc_resolver_next(&exec_ctx, resolver, &config,
+                     grpc_closure_create(on_done, &ev2));
+  grpc_exec_ctx_flush(&exec_ctx);
+  GPR_ASSERT(wait_loop(30, &ev2));
+  GPR_ASSERT(config != NULL);
+
+  grpc_client_config_unref(&exec_ctx, config);
+  GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test");
+  grpc_exec_ctx_finish(&exec_ctx);
+
+  grpc_shutdown();
+  gpr_mu_destroy(&g_mu);
+}
diff --git a/test/core/client_config/resolvers/dns_resolver_test.c b/test/core/client_config/resolvers/dns_resolver_test.c
index 38e76d5..6c7a6b2 100644
--- a/test/core/client_config/resolvers/dns_resolver_test.c
+++ b/test/core/client_config/resolvers/dns_resolver_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,13 +31,13 @@
  *
  */
 
-#include "src/core/client_config/resolvers/dns_resolver.h"
+#include "src/core/lib/client_config/resolvers/dns_resolver.h"
 
 #include <string.h>
 
 #include <grpc/support/log.h>
 
-#include "src/core/client_config/resolver.h"
+#include "src/core/lib/client_config/resolver.h"
 #include "test/core/util/test_config.h"
 
 static void subchannel_factory_ref(grpc_subchannel_factory *scv) {}
diff --git a/test/core/client_config/resolvers/sockaddr_resolver_test.c b/test/core/client_config/resolvers/sockaddr_resolver_test.c
index 8856c85..fafddfd 100644
--- a/test/core/client_config/resolvers/sockaddr_resolver_test.c
+++ b/test/core/client_config/resolvers/sockaddr_resolver_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,13 +31,13 @@
  *
  */
 
-#include "src/core/client_config/resolvers/sockaddr_resolver.h"
+#include "src/core/lib/client_config/resolvers/sockaddr_resolver.h"
 
 #include <string.h>
 
 #include <grpc/support/log.h>
 
-#include "src/core/client_config/resolver.h"
+#include "src/core/lib/client_config/resolver.h"
 #include "test/core/util/test_config.h"
 
 static void subchannel_factory_ref(grpc_subchannel_factory *scv) {}
diff --git a/test/core/client_config/set_initial_connect_string_test.c b/test/core/client_config/set_initial_connect_string_test.c
index 3cf267f..7fd92a0 100644
--- a/test/core/client_config/set_initial_connect_string_test.c
+++ b/test/core/client_config/set_initial_connect_string_test.c
@@ -38,10 +38,10 @@
 #include <grpc/support/log.h>
 #include <grpc/support/slice.h>
 
-#include "src/core/client_config/initial_connect_string.h"
-#include "src/core/iomgr/sockaddr.h"
-#include "src/core/security/credentials.h"
-#include "src/core/support/string.h"
+#include "src/core/lib/client_config/initial_connect_string.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/support/string.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 #include "test/core/util/test_tcp_server.h"
diff --git a/test/core/client_config/uri_corpus/042dc4512fa3d391c5170cf3aa61e6a638f84342 b/test/core/client_config/uri_corpus/042dc4512fa3d391c5170cf3aa61e6a638f84342
new file mode 100644
index 0000000..597a6db
--- /dev/null
+++ b/test/core/client_config/uri_corpus/042dc4512fa3d391c5170cf3aa61e6a638f84342
@@ -0,0 +1 @@
+i
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/0e9bbe975f2027e8c39c89f85f667530368e7d11 b/test/core/client_config/uri_corpus/0e9bbe975f2027e8c39c89f85f667530368e7d11
new file mode 100644
index 0000000..d56b8fc
--- /dev/null
+++ b/test/core/client_config/uri_corpus/0e9bbe975f2027e8c39c89f85f667530368e7d11
@@ -0,0 +1 @@
+:iiiÐ?+n!ij
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/14b57bcbf1e17b1db1de491ef2ba3768f704b7dc b/test/core/client_config/uri_corpus/14b57bcbf1e17b1db1de491ef2ba3768f704b7dc
new file mode 100644
index 0000000..3936e89
--- /dev/null
+++ b/test/core/client_config/uri_corpus/14b57bcbf1e17b1db1de491ef2ba3768f704b7dc
@@ -0,0 +1 @@
+:‡i?=niI_!';ñ
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/1794310671a060eead6e5ee66ac978a18ec7e84f b/test/core/client_config/uri_corpus/1794310671a060eead6e5ee66ac978a18ec7e84f
new file mode 100644
index 0000000..a94c4cf
--- /dev/null
+++ b/test/core/client_config/uri_corpus/1794310671a060eead6e5ee66ac978a18ec7e84f
@@ -0,0 +1,2 @@
+~ipip~6::1
+v:Ð:1
diff --git a/test/core/client_config/uri_corpus/1d30b2a79afbaf2828ff42b9a9647e942ba1ab80 b/test/core/client_config/uri_corpus/1d30b2a79afbaf2828ff42b9a9647e942ba1ab80
new file mode 100644
index 0000000..875ac2a
--- /dev/null
+++ b/test/core/client_config/uri_corpus/1d30b2a79afbaf2828ff42b9a9647e942ba1ab80
@@ -0,0 +1 @@
+:il0P/8?n!$i:
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/1fcf5d9c333b70596cf5ba04d1f7affdf445b971 b/test/core/client_config/uri_corpus/1fcf5d9c333b70596cf5ba04d1f7affdf445b971
new file mode 100644
index 0000000..59469af
--- /dev/null
+++ b/test/core/client_config/uri_corpus/1fcf5d9c333b70596cf5ba04d1f7affdf445b971
@@ -0,0 +1,3 @@
+iiP*v:::pip~6:::0
+v:::11
+
diff --git a/test/core/client_config/uri_corpus/23162c8a8936e20b195404c21337ee734d02a6bc b/test/core/client_config/uri_corpus/23162c8a8936e20b195404c21337ee734d02a6bc
new file mode 100644
index 0000000..2f90235
--- /dev/null
+++ b/test/core/client_config/uri_corpus/23162c8a8936e20b195404c21337ee734d02a6bc
@@ -0,0 +1 @@
+:ii/i?n!%i*
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/23f3198b815ca60bdadcaae682b9f965dda387f1 b/test/core/client_config/uri_corpus/23f3198b815ca60bdadcaae682b9f965dda387f1
new file mode 100644
index 0000000..4bdc3f6
--- /dev/null
+++ b/test/core/client_config/uri_corpus/23f3198b815ca60bdadcaae682b9f965dda387f1
@@ -0,0 +1 @@
+uni::.i?n(!ipR6/
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/2ef3893b43f1f60b77b59ce06a6bce9815d78eaf b/test/core/client_config/uri_corpus/2ef3893b43f1f60b77b59ce06a6bce9815d78eaf
new file mode 100644
index 0000000..fb7665d
--- /dev/null
+++ b/test/core/client_config/uri_corpus/2ef3893b43f1f60b77b59ce06a6bce9815d78eaf
@@ -0,0 +1,2 @@
+:/i?n!ipv6:./::abc.*
+
diff --git a/test/core/client_config/uri_corpus/356c3c129e203b5c74550b4209764d74b9caefce b/test/core/client_config/uri_corpus/356c3c129e203b5c74550b4209764d74b9caefce
new file mode 100644
index 0000000..6c1e22f
--- /dev/null
+++ b/test/core/client_config/uri_corpus/356c3c129e203b5c74550b4209764d74b9caefce
@@ -0,0 +1 @@
+unix://ii:#v6i?n!
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/3b58860f3451d3e7aad99690a8d39782ca5116fc b/test/core/client_config/uri_corpus/3b58860f3451d3e7aad99690a8d39782ca5116fc
new file mode 100644
index 0000000..725b208
--- /dev/null
+++ b/test/core/client_config/uri_corpus/3b58860f3451d3e7aad99690a8d39782ca5116fc
@@ -0,0 +1,4 @@
+i:i?nip~&2./:::abipip~6c.*
+
+::1
+v:Ð:1
diff --git a/test/core/client_config/uri_corpus/47b5228404451fc9d4071fa69192514bb4ce33c1 b/test/core/client_config/uri_corpus/47b5228404451fc9d4071fa69192514bb4ce33c1
new file mode 100644
index 0000000..23d52e1
--- /dev/null
+++ b/test/core/client_config/uri_corpus/47b5228404451fc9d4071fa69192514bb4ce33c1
@@ -0,0 +1 @@
+:iiP/i?n!'i*
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/636c5606fc23713a1bae88c8899c0541cfad4fd8 b/test/core/client_config/uri_corpus/636c5606fc23713a1bae88c8899c0541cfad4fd8
new file mode 100644
index 0000000..1dc4931
--- /dev/null
+++ b/test/core/client_config/uri_corpus/636c5606fc23713a1bae88c8899c0541cfad4fd8
@@ -0,0 +1,4 @@
+:i?n!ip~f2:./::abipip~6c.*
+
+::1
+v:Ð:1
diff --git a/test/core/client_config/uri_corpus/63fe493b270b17426d77a27cbf3abac5b2c2794a b/test/core/client_config/uri_corpus/63fe493b270b17426d77a27cbf3abac5b2c2794a
new file mode 100644
index 0000000..7b95329
--- /dev/null
+++ b/test/core/client_config/uri_corpus/63fe493b270b17426d77a27cbf3abac5b2c2794a
@@ -0,0 +1 @@
+:‡i?=niI!';ñ
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/655300a902b62662296a8e46bfb04fbcb07182cb b/test/core/client_config/uri_corpus/655300a902b62662296a8e46bfb04fbcb07182cb
new file mode 100644
index 0000000..4eaca39
--- /dev/null
+++ b/test/core/client_config/uri_corpus/655300a902b62662296a8e46bfb04fbcb07182cb
@@ -0,0 +1 @@
+unix://ii:pv6i?n!
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/6b70979a70a038ff6607d6cf85485ee95baf58e6 b/test/core/client_config/uri_corpus/6b70979a70a038ff6607d6cf85485ee95baf58e6
new file mode 100644
index 0000000..57cbd72
--- /dev/null
+++ b/test/core/client_config/uri_corpus/6b70979a70a038ff6607d6cf85485ee95baf58e6
@@ -0,0 +1 @@
+uni::/i?n!ipR6/
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/7314ab3545a7535a26e0e8aad67caea5534d68b1 b/test/core/client_config/uri_corpus/7314ab3545a7535a26e0e8aad67caea5534d68b1
new file mode 100644
index 0000000..e13cf5a
--- /dev/null
+++ b/test/core/client_config/uri_corpus/7314ab3545a7535a26e0e8aad67caea5534d68b1
@@ -0,0 +1,2 @@
+ipip~6:::1
+v:::1
diff --git a/test/core/client_config/uri_corpus/884dcaee2908ffe5f12b65b8eba81016099c4266 b/test/core/client_config/uri_corpus/884dcaee2908ffe5f12b65b8eba81016099c4266
new file mode 100644
index 0000000..58ecc7e
--- /dev/null
+++ b/test/core/client_config/uri_corpus/884dcaee2908ffe5f12b65b8eba81016099c4266
@@ -0,0 +1 @@
+ip*v:::1
diff --git a/test/core/client_config/uri_corpus/96c8d266b7dc037288ef305c996608270f72e7fb b/test/core/client_config/uri_corpus/96c8d266b7dc037288ef305c996608270f72e7fb
new file mode 100644
index 0000000..efb392b
--- /dev/null
+++ b/test/core/client_config/uri_corpus/96c8d266b7dc037288ef305c996608270f72e7fb
@@ -0,0 +1,2 @@
+:/i/n!ipv6:::/a.b.c1
+
diff --git a/test/core/client_config/uri_corpus/975536c71ade4800415a7e9c2f1b45c35a6d5ea8 b/test/core/client_config/uri_corpus/975536c71ade4800415a7e9c2f1b45c35a6d5ea8
new file mode 100644
index 0000000..7155222
--- /dev/null
+++ b/test/core/client_config/uri_corpus/975536c71ade4800415a7e9c2f1b45c35a6d5ea8
@@ -0,0 +1 @@
+ilP.i;?n!#i!;
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/99750aa67d30beaea8af565c829d4999aa8cb91b b/test/core/client_config/uri_corpus/99750aa67d30beaea8af565c829d4999aa8cb91b
new file mode 100644
index 0000000..4061e02
--- /dev/null
+++ b/test/core/client_config/uri_corpus/99750aa67d30beaea8af565c829d4999aa8cb91b
@@ -0,0 +1 @@
+unix::/i?n!ipv6/
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/a1f0f9b75bb354eb063d7cba4fcfa2d0b88d63de b/test/core/client_config/uri_corpus/a1f0f9b75bb354eb063d7cba4fcfa2d0b88d63de
new file mode 100644
index 0000000..736e63e
--- /dev/null
+++ b/test/core/client_config/uri_corpus/a1f0f9b75bb354eb063d7cba4fcfa2d0b88d63de
@@ -0,0 +1 @@
+:¢ilP/i;n!#i:
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/a296eb3d1d436ed7df7195b10aa3c4de3896f98d b/test/core/client_config/uri_corpus/a296eb3d1d436ed7df7195b10aa3c4de3896f98d
new file mode 100644
index 0000000..dff2f89
--- /dev/null
+++ b/test/core/client_config/uri_corpus/a296eb3d1d436ed7df7195b10aa3c4de3896f98d
@@ -0,0 +1 @@
+u+ni::/i?n!ipR3/
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/a8b8e66050b424f1b8c07d46f868199fb7f60e38 b/test/core/client_config/uri_corpus/a8b8e66050b424f1b8c07d46f868199fb7f60e38
new file mode 100644
index 0000000..13a1154
--- /dev/null
+++ b/test/core/client_config/uri_corpus/a8b8e66050b424f1b8c07d46f868199fb7f60e38
@@ -0,0 +1 @@
+uni::pi:miP/?ni.!(Ri?)8/n!'i*
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/af55baf8c8855e563befdf1eefbcbd46c5ddb8d2 b/test/core/client_config/uri_corpus/af55baf8c8855e563befdf1eefbcbd46c5ddb8d2
new file mode 100644
index 0000000..fe019fc
--- /dev/null
+++ b/test/core/client_config/uri_corpus/af55baf8c8855e563befdf1eefbcbd46c5ddb8d2
@@ -0,0 +1 @@
+uni::.i!in:/i/n!ipv6ž:?(pR;::/a.2b
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/b3c0bf66c2bf5d24ef1daf4cc5a9d6d5bd0e8bfd b/test/core/client_config/uri_corpus/b3c0bf66c2bf5d24ef1daf4cc5a9d6d5bd0e8bfd
new file mode 100644
index 0000000..6e12167
--- /dev/null
+++ b/test/core/client_config/uri_corpus/b3c0bf66c2bf5d24ef1daf4cc5a9d6d5bd0e8bfd
@@ -0,0 +1 @@
+:ii/iilP.i;?n?n!#i!;!%*
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/ceb4e2264ba7a8d5be47d276b37ec09489e00245 b/test/core/client_config/uri_corpus/ceb4e2264ba7a8d5be47d276b37ec09489e00245
new file mode 100644
index 0000000..b565522
--- /dev/null
+++ b/test/core/client_config/uri_corpus/ceb4e2264ba7a8d5be47d276b37ec09489e00245
@@ -0,0 +1 @@
+:‡i?P-niI!'iñ
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/cf4395958f5bfb46fd6f535a39657d016c75114c b/test/core/client_config/uri_corpus/cf4395958f5bfb46fd6f535a39657d016c75114c
new file mode 100644
index 0000000..a765672
--- /dev/null
+++ b/test/core/client_config/uri_corpus/cf4395958f5bfb46fd6f535a39657d016c75114c
@@ -0,0 +1 @@
+unix://ipv6:::
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/d46668372b7e20154a89409a7430a28e642afdca b/test/core/client_config/uri_corpus/d46668372b7e20154a89409a7430a28e642afdca
new file mode 100644
index 0000000..d658fb8
--- /dev/null
+++ b/test/core/client_config/uri_corpus/d46668372b7e20154a89409a7430a28e642afdca
@@ -0,0 +1 @@
+:ilP/i?n!#i:
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/d6fe7412a0a1d1c733160246f3fa425f4f97682a b/test/core/client_config/uri_corpus/d6fe7412a0a1d1c733160246f3fa425f4f97682a
new file mode 100644
index 0000000..6d37b5f
--- /dev/null
+++ b/test/core/client_config/uri_corpus/d6fe7412a0a1d1c733160246f3fa425f4f97682a
@@ -0,0 +1 @@
+:ilP/i?n,!#i:
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/dns.txt b/test/core/client_config/uri_corpus/dns.txt
new file mode 100644
index 0000000..577e105
--- /dev/null
+++ b/test/core/client_config/uri_corpus/dns.txt
@@ -0,0 +1 @@
+dns:10.2.1.1
diff --git a/test/core/client_config/uri_corpus/ea02d9fea9bad5b89cf353a0169238f584177e71 b/test/core/client_config/uri_corpus/ea02d9fea9bad5b89cf353a0169238f584177e71
new file mode 100644
index 0000000..52f5a23
--- /dev/null
+++ b/test/core/client_config/uri_corpus/ea02d9fea9bad5b89cf353a0169238f584177e71
@@ -0,0 +1,4 @@
+i:i?n!ip~f2.:/::abipip~6c.*
+
+::1
+v:Ð:1
diff --git a/test/core/client_config/uri_corpus/ec4731dddf94ed3ea92ae4d5a71f145ab6e3f6ee b/test/core/client_config/uri_corpus/ec4731dddf94ed3ea92ae4d5a71f145ab6e3f6ee
new file mode 100644
index 0000000..c3c93fe
--- /dev/null
+++ b/test/core/client_config/uri_corpus/ec4731dddf94ed3ea92ae4d5a71f145ab6e3f6ee
@@ -0,0 +1 @@
+ii-i?n!%*
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/ed2f78646f19fc47dd85ff0877c232b71913ece2 b/test/core/client_config/uri_corpus/ed2f78646f19fc47dd85ff0877c232b71913ece2
new file mode 100644
index 0000000..45065e2
--- /dev/null
+++ b/test/core/client_config/uri_corpus/ed2f78646f19fc47dd85ff0877c232b71913ece2
@@ -0,0 +1 @@
+:ii/i?n!%*
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/f6889f4a6350fea1596a3adea5cdac02bd5d1ff3 b/test/core/client_config/uri_corpus/f6889f4a6350fea1596a3adea5cdac02bd5d1ff3
new file mode 100644
index 0000000..02151c8
--- /dev/null
+++ b/test/core/client_config/uri_corpus/f6889f4a6350fea1596a3adea5cdac02bd5d1ff3
@@ -0,0 +1,2 @@
+:ipip~6:::1
+vii/:::iunix:?n/1/ipv6!%
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/f6f3bd030f0d321efe7c51ca3f057de23509af67 b/test/core/client_config/uri_corpus/f6f3bd030f0d321efe7c51ca3f057de23509af67
new file mode 100644
index 0000000..8034e13
--- /dev/null
+++ b/test/core/client_config/uri_corpus/f6f3bd030f0d321efe7c51ca3f057de23509af67
@@ -0,0 +1 @@
+:iiP/i?n!i*
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/f97598cff03306af3c70400608fec47268b5075d b/test/core/client_config/uri_corpus/f97598cff03306af3c70400608fec47268b5075d
new file mode 100644
index 0000000..240946d
--- /dev/null
+++ b/test/core/client_config/uri_corpus/f97598cff03306af3c70400608fec47268b5075d
@@ -0,0 +1,2 @@
+unix://ipv6:::/a.b.c1
+
diff --git a/test/core/client_config/uri_corpus/f9e1ec1fc642b575bc9955618b7065747f56b101 b/test/core/client_config/uri_corpus/f9e1ec1fc642b575bc9955618b7065747f56b101
new file mode 100644
index 0000000..d089a59
--- /dev/null
+++ b/test/core/client_config/uri_corpus/f9e1ec1fc642b575bc9955618b7065747f56b101
@@ -0,0 +1 @@
+:ilP.i;?n!#i;
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/fe0630a3aeed2ec6f474f362e4c839478290d5c4 b/test/core/client_config/uri_corpus/fe0630a3aeed2ec6f474f362e4c839478290d5c4
new file mode 100644
index 0000000..66eefbc
--- /dev/null
+++ b/test/core/client_config/uri_corpus/fe0630a3aeed2ec6f474f362e4c839478290d5c4
@@ -0,0 +1 @@
+:miP/i?)n!'i*
\ No newline at end of file
diff --git a/test/core/client_config/uri_corpus/ipv4.txt b/test/core/client_config/uri_corpus/ipv4.txt
new file mode 100644
index 0000000..fe29486
--- /dev/null
+++ b/test/core/client_config/uri_corpus/ipv4.txt
@@ -0,0 +1 @@
+ipv4:10.2.1.1
diff --git a/test/core/client_config/uri_corpus/ipv6.txt b/test/core/client_config/uri_corpus/ipv6.txt
new file mode 100644
index 0000000..7b6932b
--- /dev/null
+++ b/test/core/client_config/uri_corpus/ipv6.txt
@@ -0,0 +1 @@
+ipv6:::1
diff --git a/test/core/client_config/uri_corpus/unix.txt b/test/core/client_config/uri_corpus/unix.txt
new file mode 100644
index 0000000..7a0997e
--- /dev/null
+++ b/test/core/client_config/uri_corpus/unix.txt
@@ -0,0 +1 @@
+unix:///a.b.c
diff --git a/test/core/client_config/uri_fuzzer_test.c b/test/core/client_config/uri_fuzzer_test.c
new file mode 100644
index 0000000..cd746c1
--- /dev/null
+++ b/test/core/client_config/uri_fuzzer_test.c
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+#include "src/core/lib/client_config/uri_parser.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  char *s = gpr_malloc(size + 1);
+  memcpy(s, data, size);
+  s[size] = 0;
+
+  grpc_uri *x;
+  if ((x = grpc_uri_parse(s, 1))) {
+    grpc_uri_destroy(x);
+  }
+  gpr_free(s);
+  return 0;
+}
diff --git a/test/core/client_config/uri_parser_test.c b/test/core/client_config/uri_parser_test.c
index df12d6b..c7f7726 100644
--- a/test/core/client_config/uri_parser_test.c
+++ b/test/core/client_config/uri_parser_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/client_config/uri_parser.h"
+#include "src/core/lib/client_config/uri_parser.h"
 
 #include <string.h>
 
diff --git a/test/core/compression/algorithm_test.c b/test/core/compression/algorithm_test.c
index 7de7e11..937eb66 100644
--- a/test/core/compression/algorithm_test.c
+++ b/test/core/compression/algorithm_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/compression/algorithm_metadata.h"
+#include "src/core/lib/compression/algorithm_metadata.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -40,7 +40,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/transport/static_metadata.h"
+#include "src/core/lib/transport/static_metadata.h"
 #include "test/core/util/test_config.h"
 
 static void test_algorithm_mesh(void) {
diff --git a/test/core/compression/compression_test.c b/test/core/compression/compression_test.c
index 26d7b2b..5d8231f 100644
--- a/test/core/compression/compression_test.c
+++ b/test/core/compression/compression_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -93,18 +93,98 @@
 }
 
 static void test_compression_algorithm_for_level(void) {
-  size_t i;
-  grpc_compression_level levels[] = {
-      GRPC_COMPRESS_LEVEL_NONE, GRPC_COMPRESS_LEVEL_LOW,
-      GRPC_COMPRESS_LEVEL_MED, GRPC_COMPRESS_LEVEL_HIGH};
-  grpc_compression_algorithm algorithms[] = {
-      GRPC_COMPRESS_NONE, GRPC_COMPRESS_DEFLATE, GRPC_COMPRESS_DEFLATE,
-      GRPC_COMPRESS_DEFLATE};
   gpr_log(GPR_DEBUG, "test_compression_algorithm_for_level");
 
-  for (i = 0; i < GPR_ARRAY_SIZE(levels); i++) {
-    GPR_ASSERT(algorithms[i] ==
-               grpc_compression_algorithm_for_level(levels[i]));
+  {
+    /* accept only identity (aka none) */
+    uint32_t accepted_encodings = 0;
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_NONE); /* always */
+
+    GPR_ASSERT(GRPC_COMPRESS_NONE ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_NONE,
+                                                    accepted_encodings));
+
+    GPR_ASSERT(GRPC_COMPRESS_NONE ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_LOW,
+                                                    accepted_encodings));
+
+    GPR_ASSERT(GRPC_COMPRESS_NONE ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_MED,
+                                                    accepted_encodings));
+
+    GPR_ASSERT(GRPC_COMPRESS_NONE ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_HIGH,
+                                                    accepted_encodings));
+  }
+
+  {
+    /* accept only gzip */
+    uint32_t accepted_encodings = 0;
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_NONE); /* always */
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_GZIP);
+
+    GPR_ASSERT(GRPC_COMPRESS_NONE ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_NONE,
+                                                    accepted_encodings));
+
+    GPR_ASSERT(GRPC_COMPRESS_GZIP ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_LOW,
+                                                    accepted_encodings));
+
+    GPR_ASSERT(GRPC_COMPRESS_GZIP ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_MED,
+                                                    accepted_encodings));
+
+    GPR_ASSERT(GRPC_COMPRESS_GZIP ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_HIGH,
+                                                    accepted_encodings));
+  }
+
+  {
+    /* accept only deflate */
+    uint32_t accepted_encodings = 0;
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_NONE); /* always */
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_DEFLATE);
+
+    GPR_ASSERT(GRPC_COMPRESS_NONE ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_NONE,
+                                                    accepted_encodings));
+
+    GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_LOW,
+                                                    accepted_encodings));
+
+    GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_MED,
+                                                    accepted_encodings));
+
+    GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_HIGH,
+                                                    accepted_encodings));
+  }
+
+  {
+    /* accept gzip and deflate */
+    uint32_t accepted_encodings = 0;
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_NONE); /* always */
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_GZIP);
+    GPR_BITSET(&accepted_encodings, GRPC_COMPRESS_DEFLATE);
+
+    GPR_ASSERT(GRPC_COMPRESS_NONE ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_NONE,
+                                                    accepted_encodings));
+
+    GPR_ASSERT(GRPC_COMPRESS_GZIP ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_LOW,
+                                                    accepted_encodings));
+
+    GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_MED,
+                                                    accepted_encodings));
+
+    GPR_ASSERT(GRPC_COMPRESS_DEFLATE ==
+               grpc_compression_algorithm_for_level(GRPC_COMPRESS_LEVEL_HIGH,
+                                                    accepted_encodings));
   }
 }
 
diff --git a/test/core/compression/message_compress_test.c b/test/core/compression/message_compress_test.c
index 6d3d161..378badc 100644
--- a/test/core/compression/message_compress_test.c
+++ b/test/core/compression/message_compress_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/compression/message_compress.h"
+#include "src/core/lib/compression/message_compress.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -40,7 +40,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/support/murmur_hash.h"
+#include "src/core/lib/support/murmur_hash.h"
 #include "test/core/util/slice_splitter.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/end2end/cq_verifier.c b/test/core/end2end/cq_verifier.c
index 724d419..baf8e8e 100644
--- a/test/core/end2end/cq_verifier.c
+++ b/test/core/end2end/cq_verifier.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,6 @@
 #include <stdio.h>
 #include <string.h>
 
-#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>
@@ -46,6 +44,8 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/event_string.h"
 
 #define ROOT_EXPECTATION 1000
 
diff --git a/test/core/end2end/dualstack_socket_test.c b/test/core/end2end/dualstack_socket_test.c
index 58e13a4..7501df9 100644
--- a/test/core/end2end/dualstack_socket_test.c
+++ b/test/core/end2end/dualstack_socket_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,9 +39,9 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/support/string.h"
-#include "src/core/iomgr/resolve_address.h"
-#include "src/core/iomgr/socket_utils_posix.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+#include "src/core/lib/support/string.h"
 
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/util/port.h"
@@ -249,9 +249,9 @@
 
   /* Destroy server. */
   grpc_server_shutdown_and_notify(server, cq, tag(1000));
-  GPR_ASSERT(grpc_completion_queue_pluck(cq, tag(1000),
-                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(server);
   grpc_completion_queue_shutdown(cq);
   drain_cq(cq);
diff --git a/test/core/end2end/end2end_nosec_tests.c b/test/core/end2end/end2end_nosec_tests.c
index 17dc190..b893451 100644
--- a/test/core/end2end/end2end_nosec_tests.c
+++ b/test/core/end2end/end2end_nosec_tests.c
@@ -35,7 +35,9 @@
 /* This file is auto-generated */
 
 #include "test/core/end2end/end2end_tests.h"
+
 #include <string.h>
+
 #include <grpc/support/log.h>
 
 extern void bad_hostname(grpc_end2end_test_config config);
diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c
index 6f2f5af..f096979 100644
--- a/test/core/end2end/end2end_tests.c
+++ b/test/core/end2end/end2end_tests.c
@@ -35,7 +35,9 @@
 /* This file is auto-generated */
 
 #include "test/core/end2end/end2end_tests.h"
+
 #include <string.h>
+
 #include <grpc/support/log.h>
 
 extern void bad_hostname(grpc_end2end_test_config config);
diff --git a/test/core/end2end/fixtures/h2_census.c b/test/core/end2end/fixtures/h2_census.c
index e74c9ae..9d091d5 100644
--- a/test/core/end2end/fixtures/h2_census.c
+++ b/test/core/end2end/fixtures/h2_census.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,19 +35,19 @@
 
 #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 "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/end2end/fixtures/h2_compress.c b/test/core/end2end/fixtures/h2_compress.c
index fea8a4f..8d8d5e7 100644
--- a/test/core/end2end/fixtures/h2_compress.c
+++ b/test/core/end2end/fixtures/h2_compress.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,19 +35,19 @@
 
 #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 "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/end2end/fixtures/h2_fakesec.c b/test/core/end2end/fixtures/h2_fakesec.c
index 2767f1d..7386691 100644
--- a/test/core/end2end/fixtures/h2_fakesec.c
+++ b/test/core/end2end/fixtures/h2_fakesec.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,14 +36,14 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/channel/channel_args.h"
-#include "src/core/security/credentials.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
-#include "test/core/util/test_config.h"
-#include "test/core/util/port.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/security/credentials.h"
 #include "test/core/end2end/data/ssl_test_data.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
 
 typedef struct fullstack_secure_fixture_data {
   char *localaddr;
diff --git a/test/core/end2end/fixtures/h2_full+pipe.c b/test/core/end2end/fixtures/h2_full+pipe.c
index 4b93581..e238023 100644
--- a/test/core/end2end/fixtures/h2_full+pipe.c
+++ b/test/core/end2end/fixtures/h2_full+pipe.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,21 +35,21 @@
 
 #include <string.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 "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
-#include "src/core/iomgr/wakeup_fd_posix.h"
 
 typedef struct fullstack_fixture_data {
   char *localaddr;
diff --git a/test/core/end2end/fixtures/h2_full+poll+pipe.c b/test/core/end2end/fixtures/h2_full+poll+pipe.c
index 682598f..688686e 100644
--- a/test/core/end2end/fixtures/h2_full+poll+pipe.c
+++ b/test/core/end2end/fixtures/h2_full+poll+pipe.c
@@ -42,14 +42,14 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.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/iomgr/pollset_posix.h"
-#include "src/core/iomgr/wakeup_fd_posix.h"
-#include "src/core/surface/channel.h"
-#include "src/core/surface/server.h"
-#include "src/core/transport/chttp2_transport.h"
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
+#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/end2end/fixtures/h2_full+poll.c b/test/core/end2end/fixtures/h2_full+poll.c
index 5a0b2ef..4bb1f80 100644
--- a/test/core/end2end/fixtures/h2_full+poll.c
+++ b/test/core/end2end/fixtures/h2_full+poll.c
@@ -42,13 +42,13 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.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/iomgr/pollset_posix.h"
-#include "src/core/surface/channel.h"
-#include "src/core/surface/server.h"
-#include "src/core/transport/chttp2_transport.h"
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/end2end/fixtures/h2_full+trace.c b/test/core/end2end/fixtures/h2_full+trace.c
new file mode 100644
index 0000000..f1b4c5d
--- /dev/null
+++ b/test/core/end2end/fixtures/h2_full+trace.c
@@ -0,0 +1,132 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <string.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 "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+typedef struct fullstack_fixture_data {
+  char *localaddr;
+} fullstack_fixture_data;
+
+static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
+    grpc_channel_args *client_args, grpc_channel_args *server_args) {
+  grpc_end2end_test_fixture f;
+  int port = grpc_pick_unused_port_or_die();
+  fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data));
+  memset(&f, 0, sizeof(f));
+
+  gpr_join_host_port(&ffd->localaddr, "localhost", port);
+
+  f.fixture_data = ffd;
+  f.cq = grpc_completion_queue_create(NULL);
+
+  return f;
+}
+
+void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
+                                  grpc_channel_args *client_args) {
+  fullstack_fixture_data *ffd = f->fixture_data;
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
+  GPR_ASSERT(f->client);
+}
+
+void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
+                                  grpc_channel_args *server_args) {
+  fullstack_fixture_data *ffd = f->fixture_data;
+  if (f->server) {
+    grpc_server_destroy(f->server);
+  }
+  f->server = grpc_server_create(server_args, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
+  GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr));
+  grpc_server_start(f->server);
+}
+
+void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
+  fullstack_fixture_data *ffd = f->fixture_data;
+  gpr_free(ffd->localaddr);
+  gpr_free(ffd);
+}
+
+/* All test configurations */
+static grpc_end2end_test_config configs[] = {
+    {"chttp2/fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
+     chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
+     chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
+};
+
+int main(int argc, char **argv) {
+  size_t i;
+
+  /* force tracing on, with a value to force many
+     code paths in trace.c to be taken */
+  gpr_setenv("GRPC_TRACE", "doesnt-exist,http,all");
+
+#ifdef GPR_POSIX_SOCKET
+  g_fixture_slowdown_factor = isatty(STDOUT_FILENO) ? 10.0 : 1.0;
+#else
+  g_fixture_slowdown_factor = 10.0;
+#endif
+
+  grpc_test_init(argc, argv);
+  grpc_init();
+
+  GPR_ASSERT(0 == grpc_tracer_set_enabled("also-doesnt-exist", 0));
+  GPR_ASSERT(1 == grpc_tracer_set_enabled("http", 1));
+  GPR_ASSERT(1 == grpc_tracer_set_enabled("all", 1));
+
+  for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
+    grpc_end2end_tests(argc, argv, configs[i]);
+  }
+
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/end2end/fixtures/h2_full.c b/test/core/end2end/fixtures/h2_full.c
index ebaa1c6..cd88ed2 100644
--- a/test/core/end2end/fixtures/h2_full.c
+++ b/test/core/end2end/fixtures/h2_full.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,18 +35,18 @@
 
 #include <string.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 "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/end2end/fixtures/h2_oauth2.c b/test/core/end2end/fixtures/h2_oauth2.c
index e2c8291..ee188cc 100644
--- a/test/core/end2end/fixtures/h2_oauth2.c
+++ b/test/core/end2end/fixtures/h2_oauth2.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,15 +36,15 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/channel/channel_args.h"
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/security/credentials.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
-#include "test/core/util/test_config.h"
-#include "test/core/util/port.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/security/credentials.h"
 #include "test/core/end2end/data/ssl_test_data.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
 
 static const char oauth2_md[] = "Bearer aaslkfjs424535asdf";
 static const char *client_identity_property_name = "smurf_name";
diff --git a/test/core/end2end/fixtures/h2_proxy.c b/test/core/end2end/fixtures/h2_proxy.c
index 8bcc1b6..299e44e 100644
--- a/test/core/end2end/fixtures/h2_proxy.c
+++ b/test/core/end2end/fixtures/h2_proxy.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,18 +35,18 @@
 
 #include <string.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 "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/end2end/fixtures/proxy.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.c b/test/core/end2end/fixtures/h2_sockpair+trace.c
index 511c8b1..5fc8b32 100644
--- a/test/core/end2end/fixtures/h2_sockpair+trace.c
+++ b/test/core/end2end/fixtures/h2_sockpair+trace.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,22 +35,22 @@
 
 #include <string.h>
 
-#include "src/core/channel/client_channel.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/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/server.h"
-#include "src/core/transport/chttp2_transport.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/compress_filter.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_client_filter.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
@@ -59,11 +59,8 @@
 
 static void server_setup_transport(void *ts, grpc_transport *transport) {
   grpc_end2end_test_fixture *f = ts;
-  static grpc_channel_filter const *extra_filters[] = {
-      &grpc_http_server_filter};
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_server_setup_transport(&exec_ctx, f->server, transport, extra_filters,
-                              GPR_ARRAY_SIZE(extra_filters),
+  grpc_server_setup_transport(&exec_ctx, f->server, transport,
                               grpc_server_get_channel_args(f->server));
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -77,17 +74,9 @@
                                    grpc_transport *transport) {
   sp_client_setup *cs = ts;
 
-  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(
-      exec_ctx, "socketpair-target", filters, nfilters, cs->client_args, 1);
-
-  cs->f->client = channel;
-
-  grpc_connected_channel_bind_transport(grpc_channel_get_channel_stack(channel),
-                                        transport);
+  cs->f->client =
+      grpc_channel_create(exec_ctx, "socketpair-target", cs->client_args,
+                          GRPC_CLIENT_DIRECT_CHANNEL, transport);
 }
 
 static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
@@ -126,7 +115,7 @@
   grpc_endpoint_pair *sfd = f->fixture_data;
   grpc_transport *transport;
   GPR_ASSERT(!f->server);
-  f->server = grpc_server_create_from_filters(NULL, 0, server_args);
+  f->server = grpc_server_create(server_args, NULL);
   grpc_server_register_completion_queue(f->server, f->cq, NULL);
   grpc_server_start(f->server);
   transport =
diff --git a/test/core/end2end/fixtures/h2_sockpair.c b/test/core/end2end/fixtures/h2_sockpair.c
index 6b4787b..739e553 100644
--- a/test/core/end2end/fixtures/h2_sockpair.c
+++ b/test/core/end2end/fixtures/h2_sockpair.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,21 +35,21 @@
 
 #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/server.h"
-#include "src/core/transport/chttp2_transport.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/compress_filter.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_client_filter.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
@@ -58,11 +58,8 @@
 
 static void server_setup_transport(void *ts, grpc_transport *transport) {
   grpc_end2end_test_fixture *f = ts;
-  static grpc_channel_filter const *extra_filters[] = {
-      &grpc_http_server_filter};
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_server_setup_transport(&exec_ctx, f->server, transport, extra_filters,
-                              GPR_ARRAY_SIZE(extra_filters),
+  grpc_server_setup_transport(&exec_ctx, f->server, transport,
                               grpc_server_get_channel_args(f->server));
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -76,17 +73,9 @@
                                    grpc_transport *transport) {
   sp_client_setup *cs = ts;
 
-  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(
-      exec_ctx, "socketpair-target", filters, nfilters, cs->client_args, 1);
-
-  cs->f->client = channel;
-
-  grpc_connected_channel_bind_transport(grpc_channel_get_channel_stack(channel),
-                                        transport);
+  cs->f->client =
+      grpc_channel_create(exec_ctx, "socketpair-target", cs->client_args,
+                          GRPC_CLIENT_DIRECT_CHANNEL, transport);
 }
 
 static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
@@ -125,7 +114,7 @@
   grpc_endpoint_pair *sfd = f->fixture_data;
   grpc_transport *transport;
   GPR_ASSERT(!f->server);
-  f->server = grpc_server_create_from_filters(NULL, 0, server_args);
+  f->server = grpc_server_create(server_args, NULL);
   grpc_server_register_completion_queue(f->server, f->cq, NULL);
   grpc_server_start(f->server);
   transport =
diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.c b/test/core/end2end/fixtures/h2_sockpair_1byte.c
index 3ae8e96..f5312ca 100644
--- a/test/core/end2end/fixtures/h2_sockpair_1byte.c
+++ b/test/core/end2end/fixtures/h2_sockpair_1byte.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,21 +35,21 @@
 
 #include <string.h>
 
-#include "src/core/channel/client_channel.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/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/server.h"
-#include "src/core/transport/chttp2_transport.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/compress_filter.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_client_filter.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
@@ -58,11 +58,8 @@
 
 static void server_setup_transport(void *ts, grpc_transport *transport) {
   grpc_end2end_test_fixture *f = ts;
-  static grpc_channel_filter const *extra_filters[] = {
-      &grpc_http_server_filter};
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_server_setup_transport(&exec_ctx, f->server, transport, extra_filters,
-                              GPR_ARRAY_SIZE(extra_filters),
+  grpc_server_setup_transport(&exec_ctx, f->server, transport,
                               grpc_server_get_channel_args(f->server));
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -76,17 +73,9 @@
                                    grpc_transport *transport) {
   sp_client_setup *cs = ts;
 
-  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(
-      exec_ctx, "socketpair-target", filters, nfilters, cs->client_args, 1);
-
-  cs->f->client = channel;
-
-  grpc_connected_channel_bind_transport(grpc_channel_get_channel_stack(channel),
-                                        transport);
+  cs->f->client =
+      grpc_channel_create(exec_ctx, "socketpair-target", cs->client_args,
+                          GRPC_CLIENT_DIRECT_CHANNEL, transport);
 }
 
 static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
@@ -125,7 +114,7 @@
   grpc_endpoint_pair *sfd = f->fixture_data;
   grpc_transport *transport;
   GPR_ASSERT(!f->server);
-  f->server = grpc_server_create_from_filters(NULL, 0, server_args);
+  f->server = grpc_server_create(server_args, NULL);
   grpc_server_register_completion_queue(f->server, f->cq, NULL);
   grpc_server_start(f->server);
   transport =
diff --git a/test/core/end2end/fixtures/h2_ssl+poll.c b/test/core/end2end/fixtures/h2_ssl+poll.c
index 66268c7..e93b436 100644
--- a/test/core/end2end/fixtures/h2_ssl+poll.c
+++ b/test/core/end2end/fixtures/h2_ssl+poll.c
@@ -40,12 +40,12 @@
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 
-#include "src/core/channel/channel_args.h"
-#include "src/core/iomgr/pollset_posix.h"
-#include "src/core/security/credentials.h"
-#include "src/core/support/env.h"
-#include "src/core/support/tmpfile.h"
-#include "src/core/support/string.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/support/tmpfile.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
diff --git a/test/core/end2end/fixtures/h2_ssl.c b/test/core/end2end/fixtures/h2_ssl.c
index e21a347..fecd03f 100644
--- a/test/core/end2end/fixtures/h2_ssl.c
+++ b/test/core/end2end/fixtures/h2_ssl.c
@@ -40,11 +40,11 @@
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 
-#include "src/core/channel/channel_args.h"
-#include "src/core/security/credentials.h"
-#include "src/core/support/env.h"
-#include "src/core/support/tmpfile.h"
-#include "src/core/support/string.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/support/tmpfile.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
diff --git a/test/core/end2end/fixtures/h2_ssl_proxy.c b/test/core/end2end/fixtures/h2_ssl_proxy.c
index 6340d3f..bfbc735 100644
--- a/test/core/end2end/fixtures/h2_ssl_proxy.c
+++ b/test/core/end2end/fixtures/h2_ssl_proxy.c
@@ -40,11 +40,11 @@
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 
-#include "src/core/channel/channel_args.h"
-#include "src/core/security/credentials.h"
-#include "src/core/support/env.h"
-#include "src/core/support/tmpfile.h"
-#include "src/core/support/string.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/support/tmpfile.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 #include "test/core/end2end/fixtures/proxy.h"
 #include "test/core/util/port.h"
diff --git a/test/core/end2end/fixtures/h2_uchannel.c b/test/core/end2end/fixtures/h2_uchannel.c
deleted file mode 100644
index 87bbd64..0000000
--- a/test/core/end2end/fixtures/h2_uchannel.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "test/core/end2end/end2end_tests.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/client_channel.h"
-#include "src/core/channel/client_uchannel.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/client_config/resolver_registry.h"
-#include "src/core/iomgr/tcp_client.h"
-#include "src/core/surface/channel.h"
-#include "src/core/surface/server.h"
-#include "src/core/transport/chttp2_transport.h"
-#include "test/core/util/port.h"
-#include "test/core/util/test_config.h"
-
-typedef struct {
-  grpc_connector base;
-  gpr_refcount refs;
-
-  grpc_closure *notify;
-  grpc_connect_in_args args;
-  grpc_connect_out_args *result;
-
-  grpc_endpoint *tcp;
-
-  grpc_closure connected;
-} connector;
-
-static void connector_ref(grpc_connector *con) {
-  connector *c = (connector *)con;
-  gpr_ref(&c->refs);
-}
-
-static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
-  connector *c = (connector *)con;
-  if (gpr_unref(&c->refs)) {
-    gpr_free(c);
-  }
-}
-
-static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  connector *c = arg;
-  grpc_closure *notify;
-  grpc_endpoint *tcp = c->tcp;
-  if (tcp != NULL) {
-    c->result->transport =
-        grpc_create_chttp2_transport(exec_ctx, c->args.channel_args, tcp, 1);
-    grpc_chttp2_transport_start_reading(exec_ctx, 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 {
-    memset(c->result, 0, sizeof(*c->result));
-  }
-  notify = c->notify;
-  c->notify = NULL;
-  notify->cb(exec_ctx, notify->cb_arg, 1);
-}
-
-static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {}
-
-static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
-                              const grpc_connect_in_args *args,
-                              grpc_connect_out_args *result,
-                              grpc_closure *notify) {
-  connector *c = (connector *)con;
-  GPR_ASSERT(c->notify == NULL);
-  GPR_ASSERT(notify->cb);
-  c->notify = notify;
-  c->args = *args;
-  c->result = result;
-  c->tcp = NULL;
-  grpc_closure_init(&c->connected, connected, c);
-  grpc_tcp_client_connect(exec_ctx, &c->connected, &c->tcp,
-                          args->interested_parties, args->addr, args->addr_len,
-                          args->deadline);
-}
-
-static const grpc_connector_vtable connector_vtable = {
-    connector_ref, connector_unref, connector_shutdown, connector_connect};
-
-typedef struct {
-  grpc_subchannel_factory base;
-  gpr_refcount refs;
-  grpc_channel_args *merge_args;
-  grpc_channel *master;
-  grpc_subchannel **sniffed_subchannel;
-} 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_exec_ctx *exec_ctx,
-                                     grpc_subchannel_factory *scf) {
-  subchannel_factory *f = (subchannel_factory *)scf;
-  if (gpr_unref(&f->refs)) {
-    GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master, "subchannel_factory");
-    grpc_channel_args_destroy(f->merge_args);
-    gpr_free(f);
-  }
-}
-
-static grpc_subchannel *subchannel_factory_create_subchannel(
-    grpc_exec_ctx *exec_ctx, 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->args = final_args;
-  s = grpc_subchannel_create(exec_ctx, &c->base, args);
-  grpc_connector_unref(exec_ctx, &c->base);
-  grpc_channel_args_destroy(final_args);
-  if (*f->sniffed_subchannel) {
-    GRPC_SUBCHANNEL_UNREF(exec_ctx, *f->sniffed_subchannel, "sniffed");
-  }
-  *f->sniffed_subchannel = s;
-  GRPC_SUBCHANNEL_REF(s, "sniffed");
-  return s;
-}
-
-static const grpc_subchannel_factory_vtable test_subchannel_factory_vtable = {
-    subchannel_factory_ref, subchannel_factory_unref,
-    subchannel_factory_create_subchannel};
-
-/* The evil twin of grpc_insecure_channel_create. It allows the test to use the
- * custom-built sniffing subchannel_factory */
-grpc_channel *channel_create(const char *target, const grpc_channel_args *args,
-                             grpc_subchannel **sniffed_subchannel) {
-  grpc_channel *channel = NULL;
-#define MAX_FILTERS 1
-  const grpc_channel_filter *filters[MAX_FILTERS];
-  grpc_resolver *resolver;
-  subchannel_factory *f;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  size_t n = 0;
-
-  filters[n++] = &grpc_client_channel_filter;
-  GPR_ASSERT(n <= MAX_FILTERS);
-
-  channel =
-      grpc_channel_create_from_filters(&exec_ctx, target, filters, n, args, 1);
-
-  f = gpr_malloc(sizeof(*f));
-  f->sniffed_subchannel = sniffed_subchannel;
-  f->base.vtable = &test_subchannel_factory_vtable;
-  gpr_ref_init(&f->refs, 1);
-  f->merge_args = grpc_channel_args_copy(args);
-  f->master = channel;
-  GRPC_CHANNEL_INTERNAL_REF(f->master, "test_subchannel_factory");
-  resolver = grpc_resolver_create(target, &f->base);
-  if (!resolver) {
-    return NULL;
-  }
-
-  grpc_client_channel_set_resolver(
-      &exec_ctx, grpc_channel_get_channel_stack(channel), resolver);
-  GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_create");
-  grpc_subchannel_factory_unref(&exec_ctx, &f->base);
-
-  grpc_exec_ctx_finish(&exec_ctx);
-
-  return channel;
-}
-
-typedef struct micro_fullstack_fixture_data {
-  char *localaddr;
-  grpc_channel *master_channel;
-  grpc_subchannel *sniffed_subchannel;
-} micro_fullstack_fixture_data;
-
-static grpc_end2end_test_fixture chttp2_create_fixture_micro_fullstack(
-    grpc_channel_args *client_args, grpc_channel_args *server_args) {
-  grpc_end2end_test_fixture f;
-  int port = grpc_pick_unused_port_or_die();
-  micro_fullstack_fixture_data *ffd =
-      gpr_malloc(sizeof(micro_fullstack_fixture_data));
-  memset(&f, 0, sizeof(f));
-  memset(ffd, 0, sizeof(*ffd));
-
-  gpr_join_host_port(&ffd->localaddr, "127.0.0.1", port);
-
-  f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
-
-  return f;
-}
-
-grpc_connectivity_state g_state = GRPC_CHANNEL_IDLE;
-grpc_pollset_set *g_interested_parties;
-
-static void state_changed(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  if (g_state != GRPC_CHANNEL_READY) {
-    grpc_subchannel_notify_on_state_change(
-        exec_ctx, arg, g_interested_parties, &g_state,
-        grpc_closure_create(state_changed, arg));
-  }
-}
-
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  grpc_pollset_destroy(arg);
-}
-
-static grpc_connected_subchannel *connect_subchannel(grpc_subchannel *c) {
-  gpr_mu *mu;
-  grpc_pollset *pollset = gpr_malloc(grpc_pollset_size());
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_pollset_init(pollset, &mu);
-  g_interested_parties = grpc_pollset_set_create();
-  grpc_pollset_set_add_pollset(&exec_ctx, g_interested_parties, pollset);
-  grpc_subchannel_notify_on_state_change(&exec_ctx, c, g_interested_parties,
-                                         &g_state,
-                                         grpc_closure_create(state_changed, c));
-  grpc_exec_ctx_flush(&exec_ctx);
-  gpr_mu_lock(mu);
-  while (g_state != GRPC_CHANNEL_READY) {
-    grpc_pollset_worker *worker = NULL;
-    grpc_pollset_work(&exec_ctx, pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1));
-    gpr_mu_unlock(mu);
-    grpc_exec_ctx_flush(&exec_ctx);
-    gpr_mu_lock(mu);
-  }
-  grpc_pollset_shutdown(&exec_ctx, pollset,
-                        grpc_closure_create(destroy_pollset, pollset));
-  grpc_pollset_set_destroy(g_interested_parties);
-  gpr_mu_unlock(mu);
-  grpc_exec_ctx_finish(&exec_ctx);
-  gpr_free(pollset);
-  return grpc_subchannel_get_connected_subchannel(c);
-}
-
-static void chttp2_init_client_micro_fullstack(grpc_end2end_test_fixture *f,
-                                               grpc_channel_args *client_args) {
-  micro_fullstack_fixture_data *ffd = f->fixture_data;
-  grpc_connectivity_state conn_state;
-  grpc_connected_subchannel *connected;
-  char *ipv4_localaddr;
-
-  gpr_asprintf(&ipv4_localaddr, "ipv4:%s", ffd->localaddr);
-  ffd->master_channel =
-      channel_create(ipv4_localaddr, client_args, &ffd->sniffed_subchannel);
-  gpr_free(ipv4_localaddr);
-  gpr_log(GPR_INFO, "MASTER CHANNEL %p ", ffd->master_channel);
-  /* the following will block. That's ok for this test */
-  conn_state = grpc_channel_check_connectivity_state(ffd->master_channel,
-                                                     1 /* try to connect */);
-  GPR_ASSERT(conn_state == GRPC_CHANNEL_IDLE);
-
-  /* here sniffed_subchannel should be ready to use */
-  GPR_ASSERT(conn_state == GRPC_CHANNEL_IDLE);
-  GPR_ASSERT(ffd->sniffed_subchannel != NULL);
-
-  connected = connect_subchannel(ffd->sniffed_subchannel);
-  f->client = grpc_client_uchannel_create(ffd->sniffed_subchannel, client_args);
-  grpc_client_uchannel_set_connected_subchannel(f->client, connected);
-  gpr_log(GPR_INFO, "CHANNEL WRAPPING SUBCHANNEL: %p(%p)", f->client,
-          ffd->sniffed_subchannel);
-
-  GPR_ASSERT(f->client);
-}
-
-static void chttp2_init_server_micro_fullstack(grpc_end2end_test_fixture *f,
-                                               grpc_channel_args *server_args) {
-  micro_fullstack_fixture_data *ffd = f->fixture_data;
-  if (f->server) {
-    grpc_server_destroy(f->server);
-  }
-  f->server = grpc_server_create(server_args, NULL);
-  grpc_server_register_completion_queue(f->server, f->cq, NULL);
-  GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr));
-  grpc_server_start(f->server);
-}
-
-static void chttp2_tear_down_micro_fullstack(grpc_end2end_test_fixture *f) {
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  micro_fullstack_fixture_data *ffd = f->fixture_data;
-  grpc_channel_destroy(ffd->master_channel);
-  if (ffd->sniffed_subchannel) {
-    GRPC_SUBCHANNEL_UNREF(&exec_ctx, ffd->sniffed_subchannel, "sniffed");
-  }
-  gpr_free(ffd->localaddr);
-  gpr_free(ffd);
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-/* All test configurations */
-static grpc_end2end_test_config configs[] = {
-    {"chttp2/micro_fullstack", 0, chttp2_create_fixture_micro_fullstack,
-     chttp2_init_client_micro_fullstack, chttp2_init_server_micro_fullstack,
-     chttp2_tear_down_micro_fullstack},
-};
-
-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(argc, argv, configs[i]);
-  }
-
-  grpc_shutdown();
-
-  return 0;
-}
diff --git a/test/core/end2end/fixtures/h2_uds+poll.c b/test/core/end2end/fixtures/h2_uds+poll.c
index c3a855f..39ae34a 100644
--- a/test/core/end2end/fixtures/h2_uds+poll.c
+++ b/test/core/end2end/fixtures/h2_uds+poll.c
@@ -45,14 +45,14 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.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/iomgr/pollset_posix.h"
-#include "src/core/support/string.h"
-#include "src/core/surface/channel.h"
-#include "src/core/surface/server.h"
-#include "src/core/transport/chttp2_transport.h"
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/end2end/fixtures/h2_uds.c b/test/core/end2end/fixtures/h2_uds.c
index 3092827..cc0d6bf 100644
--- a/test/core/end2end/fixtures/h2_uds.c
+++ b/test/core/end2end/fixtures/h2_uds.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,13 +37,6 @@
 #include <string.h>
 #include <unistd.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/support/string.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>
@@ -51,6 +44,13 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/useful.h>
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/client_channel.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index 4dfafce..93b48c3 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -59,6 +59,7 @@
         platforms=['linux']),
     'h2_full+poll+pipe': default_unsecure_fixture_options._replace(
         platforms=['linux']),
+    'h2_full+trace': default_unsecure_fixture_options._replace(tracing=True),
     'h2_oauth2': default_secure_fixture_options._replace(ci_mac=False),
     'h2_proxy': default_unsecure_fixture_options._replace(includes_proxy=True,
                                                           ci_mac=False),
@@ -66,12 +67,11 @@
         ci_mac=False),
     'h2_sockpair': socketpair_unsecure_fixture_options._replace(ci_mac=False),
     'h2_sockpair+trace': socketpair_unsecure_fixture_options._replace(
-        tracing=True),
+        ci_mac=False, tracing=True),
     'h2_ssl': default_secure_fixture_options,
     'h2_ssl+poll': default_secure_fixture_options._replace(platforms=['linux']),
     'h2_ssl_proxy': default_secure_fixture_options._replace(includes_proxy=True,
                                                             ci_mac=False),
-    'h2_uchannel': default_unsecure_fixture_options._replace(fullstack=False),
     'h2_uds+poll': uds_fixture_options._replace(platforms=['linux']),
     'h2_uds': uds_fixture_options,
 }
@@ -150,7 +150,6 @@
 
 def main():
   sec_deps = [
-    'end2end_certs',
     'grpc_test_util',
     'grpc',
     'gpr_test_util',
@@ -193,18 +192,6 @@
               'deps': unsec_deps,
               'vs_proj_dir': 'test/end2end/tests',
           }
-      ] + [
-          {
-              'name': 'end2end_certs',
-              'build': 'private',
-              'language': 'c',
-              'src': [
-                  "test/core/end2end/data/test_root_cert.c",
-                  "test/core/end2end/data/server1_cert.c",
-                  "test/core/end2end/data/server1_key.c"
-              ],
-              'vs_proj_dir': 'test/end2end',
-          }
       ],
       'targets': [
           {
diff --git a/test/core/end2end/invalid_call_argument_test.c b/test/core/end2end/invalid_call_argument_test.c
index 4029e96..642b044 100644
--- a/test/core/end2end/invalid_call_argument_test.c
+++ b/test/core/end2end/invalid_call_argument_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -63,7 +63,7 @@
 static struct test_state g_state;
 
 static void prepare_test(int is_client) {
-  int port;
+  int port = grpc_pick_unused_port_or_die();
   char *server_hostport;
   grpc_op *op;
   g_state.is_client = is_client;
@@ -85,7 +85,6 @@
   } else {
     g_state.server = grpc_server_create(NULL, NULL);
     grpc_server_register_completion_queue(g_state.server, g_state.cq, NULL);
-    port = grpc_pick_unused_port_or_die();
     gpr_join_host_port(&server_hostport, "0.0.0.0", port);
     grpc_server_add_insecure_http2_port(g_state.server, server_hostport);
     grpc_server_start(g_state.server);
@@ -131,20 +130,23 @@
     grpc_server_shutdown_and_notify(g_state.server, g_state.cq, tag(1000));
     GPR_ASSERT(grpc_completion_queue_pluck(g_state.cq, tag(1000),
                                            GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
-                                           NULL).type == GRPC_OP_COMPLETE);
+                                           NULL)
+                   .type == GRPC_OP_COMPLETE);
     grpc_server_destroy(g_state.server);
     grpc_call_details_destroy(&g_state.call_details);
     grpc_metadata_array_destroy(&g_state.server_initial_metadata_recv);
   }
   grpc_completion_queue_shutdown(g_state.cq);
   while (grpc_completion_queue_next(g_state.cq,
-                                    gpr_inf_future(GPR_CLOCK_REALTIME),
-                                    NULL).type != GRPC_QUEUE_SHUTDOWN)
+                                    gpr_inf_future(GPR_CLOCK_REALTIME), NULL)
+             .type != GRPC_QUEUE_SHUTDOWN)
     ;
   grpc_completion_queue_destroy(g_state.cq);
 }
 
 static void test_non_null_reserved_on_start_batch() {
+  gpr_log(GPR_INFO, "test_non_null_reserved_on_start_batch");
+
   prepare_test(1);
   GPR_ASSERT(GRPC_CALL_ERROR ==
              grpc_call_start_batch(g_state.call, NULL, 0, NULL, tag(1)));
@@ -152,6 +154,8 @@
 }
 
 static void test_non_null_reserved_on_op() {
+  gpr_log(GPR_INFO, "test_non_null_reserved_on_op");
+
   grpc_op *op;
   prepare_test(1);
 
@@ -168,6 +172,8 @@
 }
 
 static void test_send_initial_metadata_more_than_once() {
+  gpr_log(GPR_INFO, "test_send_initial_metadata_more_than_once");
+
   grpc_op *op;
   prepare_test(1);
 
@@ -196,6 +202,8 @@
 }
 
 static void test_too_many_metadata() {
+  gpr_log(GPR_INFO, "test_too_many_metadata");
+
   grpc_op *op;
   prepare_test(1);
 
@@ -212,6 +220,8 @@
 }
 
 static void test_send_null_message() {
+  gpr_log(GPR_INFO, "test_send_null_message");
+
   grpc_op *op;
   prepare_test(1);
 
@@ -233,6 +243,8 @@
 }
 
 static void test_send_messages_at_the_same_time() {
+  gpr_log(GPR_INFO, "test_send_messages_at_the_same_time");
+
   grpc_op *op;
   gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
   grpc_byte_buffer *request_payload =
@@ -262,6 +274,8 @@
 }
 
 static void test_send_server_status_from_client() {
+  gpr_log(GPR_INFO, "test_send_server_status_from_client");
+
   grpc_op *op;
   prepare_test(1);
 
@@ -280,6 +294,8 @@
 }
 
 static void test_receive_initial_metadata_twice_at_client() {
+  gpr_log(GPR_INFO, "test_receive_initial_metadata_twice_at_client");
+
   grpc_op *op;
   prepare_test(1);
   op = g_state.ops;
@@ -306,6 +322,8 @@
 }
 
 static void test_receive_message_with_invalid_flags() {
+  gpr_log(GPR_INFO, "test_receive_message_with_invalid_flags");
+
   grpc_op *op;
   grpc_byte_buffer *payload = NULL;
   prepare_test(1);
@@ -322,6 +340,8 @@
 }
 
 static void test_receive_two_messages_at_the_same_time() {
+  gpr_log(GPR_INFO, "test_receive_two_messages_at_the_same_time");
+
   grpc_op *op;
   grpc_byte_buffer *payload = NULL;
   prepare_test(1);
@@ -343,6 +363,8 @@
 }
 
 static void test_recv_close_on_server_from_client() {
+  gpr_log(GPR_INFO, "test_recv_close_on_server_from_client");
+
   grpc_op *op;
   prepare_test(1);
 
@@ -359,6 +381,8 @@
 }
 
 static void test_recv_status_on_client_twice() {
+  gpr_log(GPR_INFO, "test_recv_status_on_client_twice");
+
   grpc_op *op;
   prepare_test(1);
 
@@ -395,6 +419,8 @@
 }
 
 static void test_send_close_from_client_on_server() {
+  gpr_log(GPR_INFO, "test_send_close_from_client_on_server");
+
   grpc_op *op;
   prepare_test(0);
 
@@ -410,6 +436,8 @@
 }
 
 static void test_recv_status_on_client_from_server() {
+  gpr_log(GPR_INFO, "test_recv_status_on_client_from_server");
+
   grpc_op *op;
   prepare_test(0);
 
@@ -431,6 +459,8 @@
 }
 
 static void test_send_status_from_server_with_invalid_flags() {
+  gpr_log(GPR_INFO, "test_send_status_from_server_with_invalid_flags");
+
   grpc_op *op;
   prepare_test(0);
 
@@ -449,6 +479,8 @@
 }
 
 static void test_too_many_trailing_metadata() {
+  gpr_log(GPR_INFO, "test_too_many_trailing_metadata");
+
   grpc_op *op;
   prepare_test(0);
 
@@ -468,6 +500,8 @@
 }
 
 static void test_send_server_status_twice() {
+  gpr_log(GPR_INFO, "test_send_server_status_twice");
+
   grpc_op *op;
   prepare_test(0);
 
@@ -493,6 +527,8 @@
 }
 
 static void test_recv_close_on_server_with_invalid_flags() {
+  gpr_log(GPR_INFO, "test_recv_close_on_server_with_invalid_flags");
+
   grpc_op *op;
   prepare_test(0);
 
@@ -509,6 +545,8 @@
 }
 
 static void test_recv_close_on_server_twice() {
+  gpr_log(GPR_INFO, "test_recv_close_on_server_twice");
+
   grpc_op *op;
   prepare_test(0);
 
diff --git a/test/core/end2end/no_server_test.c b/test/core/end2end/no_server_test.c
index 5c971ea..c1be55d 100644
--- a/test/core/end2end/no_server_test.c
+++ b/test/core/end2end/no_server_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -88,8 +88,9 @@
   GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED);
 
   grpc_completion_queue_shutdown(cq);
-  while (grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME),
-                                    NULL).type != GRPC_QUEUE_SHUTDOWN)
+  while (
+      grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL)
+          .type != GRPC_QUEUE_SHUTDOWN)
     ;
   grpc_completion_queue_destroy(cq);
   grpc_call_destroy(call);
diff --git a/test/core/end2end/tests/bad_hostname.c b/test/core/end2end/tests/bad_hostname.c
index 1458738..e8c07ac 100644
--- a/test/core/end2end/tests/bad_hostname.c
+++ b/test/core/end2end/tests/bad_hostname.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,13 +36,13 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/support/string.h"
 #include <grpc/byte_buffer.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
 enum { TIMEOUT = 200000 };
@@ -77,9 +77,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
@@ -152,7 +152,7 @@
   cq_expect_completion(cqv, tag(1), 1);
   cq_verify(cqv);
 
-  GPR_ASSERT(status == GRPC_STATUS_INVALID_ARGUMENT);
+  GPR_ASSERT(status == GRPC_STATUS_INTERNAL);
 
   gpr_free(details);
   grpc_metadata_array_destroy(&initial_metadata_recv);
diff --git a/test/core/end2end/tests/binary_metadata.c b/test/core/end2end/tests/binary_metadata.c
index 4eccd16..a4f4afa 100644
--- a/test/core/end2end/tests/binary_metadata.c
+++ b/test/core/end2end/tests/binary_metadata.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,9 +75,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/call_creds.c b/test/core/end2end/tests/call_creds.c
index c9d4251..f749a60 100644
--- a/test/core/end2end/tests/call_creds.c
+++ b/test/core/end2end/tests/call_creds.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,15 +36,15 @@
 #include <stdio.h>
 #include <string.h>
 
-#include <grpc/grpc_security.h>
 #include <grpc/byte_buffer.h>
+#include <grpc/grpc_security.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
-#include "src/core/security/credentials.h"
-#include "src/core/support/string.h"
 
 static const char iam_token[] = "token";
 static const char iam_selector[] = "selector";
@@ -93,9 +93,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c
index 4646bf7..2025f11 100644
--- a/test/core/end2end/tests/cancel_after_accept.c
+++ b/test/core/end2end/tests/cancel_after_accept.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -76,9 +76,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/cancel_after_client_done.c b/test/core/end2end/tests/cancel_after_client_done.c
index 364598a..bc958a6 100644
--- a/test/core/end2end/tests/cancel_after_client_done.c
+++ b/test/core/end2end/tests/cancel_after_client_done.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -76,9 +76,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/cancel_after_invoke.c b/test/core/end2end/tests/cancel_after_invoke.c
index ec0b0de..5bab10e 100644
--- a/test/core/end2end/tests/cancel_after_invoke.c
+++ b/test/core/end2end/tests/cancel_after_invoke.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -77,9 +77,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/cancel_before_invoke.c b/test/core/end2end/tests/cancel_before_invoke.c
index 7b432fe..8c0becd 100644
--- a/test/core/end2end/tests/cancel_before_invoke.c
+++ b/test/core/end2end/tests/cancel_before_invoke.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,9 +75,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/cancel_in_a_vacuum.c b/test/core/end2end/tests/cancel_in_a_vacuum.c
index 214ab2b..7bea7d7 100644
--- a/test/core/end2end/tests/cancel_in_a_vacuum.c
+++ b/test/core/end2end/tests/cancel_in_a_vacuum.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -76,9 +76,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/cancel_with_status.c b/test/core/end2end/tests/cancel_with_status.c
index 1541ca0..e5a1556 100644
--- a/test/core/end2end/tests/cancel_with_status.c
+++ b/test/core/end2end/tests/cancel_with_status.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,13 +36,13 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/support/string.h"
 #include <grpc/byte_buffer.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
 enum { TIMEOUT = 200000 };
@@ -77,9 +77,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/compressed_payload.c b/test/core/end2end/tests/compressed_payload.c
index 33b1d8f..9c25885 100644
--- a/test/core/end2end/tests/compressed_payload.c
+++ b/test/core/end2end/tests/compressed_payload.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,10 +43,10 @@
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
 
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/compress_filter.h"
+#include "src/core/lib/surface/call_test_only.h"
 #include "test/core/end2end/cq_verifier.h"
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/compress_filter.h"
-#include "src/core/surface/call_test_only.h"
 
 enum { TIMEOUT = 200000 };
 
@@ -80,9 +80,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/default_host.c b/test/core/end2end/tests/default_host.c
index dc33034..576d81e 100644
--- a/test/core/end2end/tests/default_host.c
+++ b/test/core/end2end/tests/default_host.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,13 +36,13 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/support/string.h"
 #include <grpc/byte_buffer.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
 enum { TIMEOUT = 200000 };
@@ -77,9 +77,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/empty_batch.c b/test/core/end2end/tests/empty_batch.c
index 24320c0..7f56313 100644
--- a/test/core/end2end/tests/empty_batch.c
+++ b/test/core/end2end/tests/empty_batch.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,13 +36,13 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/support/string.h"
 #include <grpc/byte_buffer.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
 enum { TIMEOUT = 200000 };
@@ -77,9 +77,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/high_initial_seqno.c b/test/core/end2end/tests/high_initial_seqno.c
index 8d16ef5..2196fbd 100644
--- a/test/core/end2end/tests/high_initial_seqno.c
+++ b/test/core/end2end/tests/high_initial_seqno.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,7 @@
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/support/string.h"
+#include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
 enum { TIMEOUT = 200000 };
@@ -79,9 +79,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/hpack_size.c b/test/core/end2end/tests/hpack_size.c
index fd4fe34..2774e50 100644
--- a/test/core/end2end/tests/hpack_size.c
+++ b/test/core/end2end/tests/hpack_size.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,7 @@
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/support/string.h"
+#include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
 static void *tag(intptr_t t) { return (void *)t; }
@@ -262,9 +262,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/invoke_large_request.c b/test/core/end2end/tests/invoke_large_request.c
index f0b0198..7f03ebb 100644
--- a/test/core/end2end/tests/invoke_large_request.c
+++ b/test/core/end2end/tests/invoke_large_request.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -73,9 +73,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/large_metadata.c b/test/core/end2end/tests/large_metadata.c
index 1b41e89..4b77974 100644
--- a/test/core/end2end/tests/large_metadata.c
+++ b/test/core/end2end/tests/large_metadata.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,9 +75,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/max_concurrent_streams.c b/test/core/end2end/tests/max_concurrent_streams.c
index d6b2a06..05472bf 100644
--- a/test/core/end2end/tests/max_concurrent_streams.c
+++ b/test/core/end2end/tests/max_concurrent_streams.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,9 +75,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c
index 59ab7f4..2202306 100644
--- a/test/core/end2end/tests/max_message_length.c
+++ b/test/core/end2end/tests/max_message_length.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,9 +75,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/negative_deadline.c b/test/core/end2end/tests/negative_deadline.c
index 2109310..e5031af 100644
--- a/test/core/end2end/tests/negative_deadline.c
+++ b/test/core/end2end/tests/negative_deadline.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,13 +36,13 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/support/string.h"
 #include <grpc/byte_buffer.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
 enum { TIMEOUT = 200000 };
@@ -77,9 +77,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/no_op.c b/test/core/end2end/tests/no_op.c
index 4bc1d63..efcd496 100644
--- a/test/core/end2end/tests/no_op.c
+++ b/test/core/end2end/tests/no_op.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,9 +75,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/payload.c b/test/core/end2end/tests/payload.c
index bc220cb..74af28d 100644
--- a/test/core/end2end/tests/payload.c
+++ b/test/core/end2end/tests/payload.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,9 +75,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/ping_pong_streaming.c b/test/core/end2end/tests/ping_pong_streaming.c
index 8351f50..7af0149 100644
--- a/test/core/end2end/tests/ping_pong_streaming.c
+++ b/test/core/end2end/tests/ping_pong_streaming.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,9 +75,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/registered_call.c b/test/core/end2end/tests/registered_call.c
index d9d2b19..09f452f 100644
--- a/test/core/end2end/tests/registered_call.c
+++ b/test/core/end2end/tests/registered_call.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,13 +36,13 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/support/string.h"
 #include <grpc/byte_buffer.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
 enum { TIMEOUT = 200000 };
@@ -77,9 +77,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/request_with_flags.c b/test/core/end2end/tests/request_with_flags.c
index 340aba6..433622e 100644
--- a/test/core/end2end/tests/request_with_flags.c
+++ b/test/core/end2end/tests/request_with_flags.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,7 +41,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
-#include "src/core/transport/byte_stream.h"
+#include "src/core/lib/transport/byte_stream.h"
 #include "test/core/end2end/cq_verifier.h"
 
 enum { TIMEOUT = 200000 };
@@ -76,9 +76,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/request_with_payload.c b/test/core/end2end/tests/request_with_payload.c
index 1aced6a..07f9993 100644
--- a/test/core/end2end/tests/request_with_payload.c
+++ b/test/core/end2end/tests/request_with_payload.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,9 +75,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/server_finishes_request.c b/test/core/end2end/tests/server_finishes_request.c
index 6bca8d4..d3ac2d5 100644
--- a/test/core/end2end/tests/server_finishes_request.c
+++ b/test/core/end2end/tests/server_finishes_request.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,13 +36,13 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/support/string.h"
 #include <grpc/byte_buffer.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
 enum { TIMEOUT = 200000 };
@@ -77,9 +77,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/simple_delayed_request.c b/test/core/end2end/tests/simple_delayed_request.c
index 0afef75..e9f5a38 100644
--- a/test/core/end2end/tests/simple_delayed_request.c
+++ b/test/core/end2end/tests/simple_delayed_request.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -63,9 +63,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/simple_metadata.c b/test/core/end2end/tests/simple_metadata.c
index c5084a5..0e214e3 100644
--- a/test/core/end2end/tests/simple_metadata.c
+++ b/test/core/end2end/tests/simple_metadata.c
@@ -75,9 +75,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c
index 3720cd1..bc634ef 100644
--- a/test/core/end2end/tests/simple_request.c
+++ b/test/core/end2end/tests/simple_request.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,13 +36,13 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/support/string.h"
 #include <grpc/byte_buffer.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
 enum { TIMEOUT = 200000 };
@@ -77,9 +77,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/end2end/tests/trailing_metadata.c b/test/core/end2end/tests/trailing_metadata.c
index 78525e9..03f4f3e 100644
--- a/test/core/end2end/tests/trailing_metadata.c
+++ b/test/core/end2end/tests/trailing_metadata.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,9 +75,9 @@
 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),
-                                         NULL).type == GRPC_OP_COMPLETE);
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(f->server);
   f->server = NULL;
 }
diff --git a/test/core/fling/client.c b/test/core/fling/client.c
index b36aef3..6a4eb1c 100644
--- a/test/core/fling/client.c
+++ b/test/core/fling/client.c
@@ -41,7 +41,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
-#include "src/core/profiling/timers.h"
+#include "src/core/lib/profiling/timers.h"
 #include "test/core/util/grpc_profiler.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/fling/fling_stream_test.c b/test/core/fling/fling_stream_test.c
index 78a7337..2807504 100644
--- a/test/core/fling/fling_stream_test.c
+++ b/test/core/fling/fling_stream_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,19 +35,19 @@
 #define _POSIX_SOURCE
 #endif
 
-#include <unistd.h>
 #include <assert.h>
-#include <stdio.h>
-#include <string.h>
 #include <signal.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <unistd.h>
 
-#include "src/core/support/string.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/string_util.h>
+#include "src/core/lib/support/string.h"
 #include "test/core/util/port.h"
 
 int main(int argc, char **argv) {
diff --git a/test/core/fling/fling_test.c b/test/core/fling/fling_test.c
index cf43ecf..46456a2 100644
--- a/test/core/fling/fling_test.c
+++ b/test/core/fling/fling_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,14 +31,14 @@
  *
  */
 
-#include <string.h>
 #include <stdio.h>
+#include <string.h>
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/subprocess.h>
-#include "src/core/support/string.h"
+#include "src/core/lib/support/string.h"
 #include "test/core/util/port.h"
 
 int main(int argc, char **argv) {
diff --git a/test/core/fling/server.c b/test/core/fling/server.c
index 42be20e..4fef21f 100644
--- a/test/core/fling/server.c
+++ b/test/core/fling/server.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -49,7 +49,7 @@
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include "src/core/profiling/timers.h"
+#include "src/core/lib/profiling/timers.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 #include "test/core/util/grpc_profiler.h"
 #include "test/core/util/port.h"
diff --git a/test/core/http/corpus/0299ca2580e4398d170c4a336e0c33eb2cd9d427 b/test/core/http/corpus/0299ca2580e4398d170c4a336e0c33eb2cd9d427
new file mode 100644
index 0000000..3d6face
--- /dev/null
+++ b/test/core/http/corpus/0299ca2580e4398d170c4a336e0c33eb2cd9d427
@@ -0,0 +1,2 @@
+HTTP/1.1 …200 OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/05e613853d64a9669ea3cf41b0de777dc24931ba b/test/core/http/corpus/05e613853d64a9669ea3cf41b0de777dc24931ba
new file mode 100644
index 0000000..5cbaf2e
--- /dev/null
+++ b/test/core/http/corpus/05e613853d64a9669ea3cf41b0de777dc24931ba
@@ -0,0 +1,2 @@
+HTTP/1.1 8) pMKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/069352518a1d1baa05f317c677d275cefda2ac97 b/test/core/http/corpus/069352518a1d1baa05f317c677d275cefda2ac97
new file mode 100644
index 0000000..8831f07
--- /dev/null
+++ b/test/core/http/corpus/069352518a1d1baa05f317c677d275cefda2ac97
@@ -0,0 +1,2 @@
+HTTP/1.1 80) OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/0925527c9358b1e10ec0f0387cd99f35204d9a34 b/test/core/http/corpus/0925527c9358b1e10ec0f0387cd99f35204d9a34
new file mode 100644
index 0000000..10967d9
--- /dev/null
+++ b/test/core/http/corpus/0925527c9358b1e10ec0f0387cd99f35204d9a34
@@ -0,0 +1,2 @@
+„HTT/21. 200 HT!TP/1OKH.1HTTP 200 OKH

+tHT//1T0P.1y 2001.
\ No newline at end of file
diff --git a/test/core/http/corpus/0c5b7c2569410b526605e308309a7f36574e530d b/test/core/http/corpus/0c5b7c2569410b526605e308309a7f36574e530d
new file mode 100644
index 0000000..c79e456
--- /dev/null
+++ b/test/core/http/corpus/0c5b7c2569410b526605e308309a7f36574e530d
Binary files differ
diff --git a/test/core/http/corpus/0ef3d0a84360bb5ad66274f1226f5cb273ecdbcf b/test/core/http/corpus/0ef3d0a84360bb5ad66274f1226f5cb273ecdbcf
new file mode 100644
index 0000000..7b979b5
--- /dev/null
+++ b/test/core/http/corpus/0ef3d0a84360bb5ad66274f1226f5cb273ecdbcf
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OKH

+tHTTP/01.021  Oes,H

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/1e1273f90187fdf5df3625764245610f86af6aa4 b/test/core/http/corpus/1e1273f90187fdf5df3625764245610f86af6aa4
new file mode 100644
index 0000000..67382b4
--- /dev/null
+++ b/test/core/http/corpus/1e1273f90187fdf5df3625764245610f86af6aa4
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OKHHTTP‰/1.200 OKH

+

+tHTHTTP/0 20T:tes/01.
\ No newline at end of file
diff --git a/test/core/http/corpus/1fbc57d118f3733287e9a9d808bb8947b3260e55 b/test/core/http/corpus/1fbc57d118f3733287e9a9d808bb8947b3260e55
new file mode 100644
index 0000000..deb8265
--- /dev/null
+++ b/test/core/http/corpus/1fbc57d118f3733287e9a9d808bb8947b3260e55
@@ -0,0 +1,3 @@
+JHTT/21. 2è0 HTTP/1.1 200 OKHHTTP‰/1.200 OKH

+

+tHTHTHTJHTTPT
\ No newline at end of file
diff --git a/test/core/http/corpus/24756c396bc72894fd720092bb6f9c03e66b469f b/test/core/http/corpus/24756c396bc72894fd720092bb6f9c03e66b469f
new file mode 100644
index 0000000..9f2e0e4
--- /dev/null
+++ b/test/core/http/corpus/24756c396bc72894fd720092bb6f9c03e66b469f
@@ -0,0 +1,2 @@
+JHTT/21. 200œHTT/0OKH.1 HTTP/200 OKH

+tH1.T
\ No newline at end of file
diff --git a/test/core/http/corpus/276def41311933421ae7a9ee42e906c85b6a4d3f b/test/core/http/corpus/276def41311933421ae7a9ee42e906c85b6a4d3f
new file mode 100644
index 0000000..4db04b2
--- /dev/null
+++ b/test/core/http/corpus/276def41311933421ae7a9ee42e906c85b6a4d3f
Binary files differ
diff --git a/test/core/http/corpus/29daa75432381937fd005cb25e314e328de6e9f9 b/test/core/http/corpus/29daa75432381937fd005cb25e314e328de6e9f9
new file mode 100644
index 0000000..cee70bf
--- /dev/null
+++ b/test/core/http/corpus/29daa75432381937fd005cb25e314e328de6e9f9
@@ -0,0 +1,2 @@
+JHTT¹21. 200HTT/0OKH1 HTTP/100 OKH

+tH1.T
\ No newline at end of file
diff --git a/test/core/http/corpus/2a75204bc492084ad853682f8de3fb137d5907bc b/test/core/http/corpus/2a75204bc492084ad853682f8de3fb137d5907bc
new file mode 100644
index 0000000..e76b00e
--- /dev/null
+++ b/test/core/http/corpus/2a75204bc492084ad853682f8de3fb137d5907bc
@@ -0,0 +1,2 @@
+GET / HTTHTTP/1.1 200 OKH

+t10H
\ No newline at end of file
diff --git a/test/core/http/corpus/2d34ba249b755a880525cf53c665633a5e359305 b/test/core/http/corpus/2d34ba249b755a880525cf53c665633a5e359305
new file mode 100644
index 0000000..7435f52
--- /dev/null
+++ b/test/core/http/corpus/2d34ba249b755a880525cf53c665633a5e359305
Binary files differ
diff --git a/test/core/http/corpus/33f4ea0c7ea27c37d8f95cfa64d282370efdafd2 b/test/core/http/corpus/33f4ea0c7ea27c37d8f95cfa64d282370efdafd2
new file mode 100644
index 0000000..cce8ded
--- /dev/null
+++ b/test/core/http/corpus/33f4ea0c7ea27c37d8f95cfa64d282370efdafd2
@@ -0,0 +1,2 @@
+HTTP/1*9y 200 OKm

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/35554617ea6418bd43161fe9a2c337ed82d7ec5b b/test/core/http/corpus/35554617ea6418bd43161fe9a2c337ed82d7ec5b
new file mode 100644
index 0000000..57efa3c
--- /dev/null
+++ b/test/core/http/corpus/35554617ea6418bd43161fe9a2c337ed82d7ec5b
@@ -0,0 +1,4 @@
+JHTT/21. 200 HTTP/0OKH.1 200 OKH

+tHTTP/01.021  Oes,H

+t

+t
\ No newline at end of file
diff --git a/test/core/http/corpus/35f0c561297cfc840ddaeebb9fc61091f4eadece b/test/core/http/corpus/35f0c561297cfc840ddaeebb9fc61091f4eadece
new file mode 100644
index 0000000..8df43e4
--- /dev/null
+++ b/test/core/http/corpus/35f0c561297cfc840ddaeebb9fc61091f4eadece
@@ -0,0 +1,2 @@
+HTTP/1.9y 200 OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/3953688866ccb3b4f371f1a858570d6afdb6452d b/test/core/http/corpus/3953688866ccb3b4f371f1a858570d6afdb6452d
new file mode 100644
index 0000000..f85f1df
--- /dev/null
+++ b/test/core/http/corpus/3953688866ccb3b4f371f1a858570d6afdb6452d
Binary files differ
diff --git a/test/core/http/corpus/39b19c41ba537f37511eff7727733715db432e76 b/test/core/http/corpus/39b19c41ba537f37511eff7727733715db432e76
new file mode 100644
index 0000000..fefa451
--- /dev/null
+++ b/test/core/http/corpus/39b19c41ba537f37511eff7727733715db432e76
@@ -0,0 +1,2 @@
+HTTP/1.1 000 OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/3e3c4756d5e40b5aa250954cbac86b826e70a7ac b/test/core/http/corpus/3e3c4756d5e40b5aa250954cbac86b826e70a7ac
new file mode 100644
index 0000000..b967b57
--- /dev/null
+++ b/test/core/http/corpus/3e3c4756d5e40b5aa250954cbac86b826e70a7ac
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OKH

+tHTTP/01.021 : Oes,H

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/3f03265921120c6ffa61b944e213e062a5538d4b b/test/core/http/corpus/3f03265921120c6ffa61b944e213e062a5538d4b
new file mode 100644
index 0000000..8af9007
--- /dev/null
+++ b/test/core/http/corpus/3f03265921120c6ffa61b944e213e062a5538d4b
@@ -0,0 +1,2 @@
+@TTP/1.1y 002ÿOKH

+ves
\ No newline at end of file
diff --git a/test/core/http/corpus/3fb034e66ee5494a67acae1b4e6ff64ba92a2046 b/test/core/http/corpus/3fb034e66ee5494a67acae1b4e6ff64ba92a2046
new file mode 100644
index 0000000..7d20266
--- /dev/null
+++ b/test/core/http/corpus/3fb034e66ee5494a67acae1b4e6ff64ba92a2046
@@ -0,0 +1,2 @@
+HTTP/1.1y 200 OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/466059ed07a0d55d6ad5e522c7d367cbf278eaf9 b/test/core/http/corpus/466059ed07a0d55d6ad5e522c7d367cbf278eaf9
new file mode 100644
index 0000000..5996b9a
--- /dev/null
+++ b/test/core/http/corpus/466059ed07a0d55d6ad5e522c7d367cbf278eaf9
Binary files differ
diff --git a/test/core/http/corpus/487725eb38511c79a9340bf4560a1411061fa6fa b/test/core/http/corpus/487725eb38511c79a9340bf4560a1411061fa6fa
new file mode 100644
index 0000000..c59c4d2
--- /dev/null
+++ b/test/core/http/corpus/487725eb38511c79a9340bf4560a1411061fa6fa
@@ -0,0 +1,2 @@
+HTTP/01.021  O,H

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/48b9b205cae8ac21512a3f26f49fd53e21ee13c5 b/test/core/http/corpus/48b9b205cae8ac21512a3f26f49fd53e21ee13c5
new file mode 100644
index 0000000..8ac7ceb
--- /dev/null
+++ b/test/core/http/corpus/48b9b205cae8ac21512a3f26f49fd53e21ee13c5
@@ -0,0 +1,2 @@
+ITTP/11 …20O HK

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/4b1f1f79a0bfa3f942479dd5f8edb59a7c257c55 b/test/core/http/corpus/4b1f1f79a0bfa3f942479dd5f8edb59a7c257c55
new file mode 100644
index 0000000..49d1c8f
--- /dev/null
+++ b/test/core/http/corpus/4b1f1f79a0bfa3f942479dd5f8edb59a7c257c55
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/5028c56a5116a186b7343ff59567b47347a0796d b/test/core/http/corpus/5028c56a5116a186b7343ff59567b47347a0796d
new file mode 100644
index 0000000..5f2c4df
--- /dev/null
+++ b/test/core/http/corpus/5028c56a5116a186b7343ff59567b47347a0796d
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OKH

+	 HTDP/01.021 : Oes,H

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/533f62b3f495ce704babf3ee8d840f196a714dff b/test/core/http/corpus/533f62b3f495ce704babf3ee8d840f196a714dff
new file mode 100644
index 0000000..6313cd9
--- /dev/null
+++ b/test/core/http/corpus/533f62b3f495ce704babf3ee8d840f196a714dff
@@ -0,0 +1,4 @@
+JHTT/21. 200 HTTP/1OKH.1 200 OKH

+tHTTP/01.021  Oes,H

+t

+t
\ No newline at end of file
diff --git a/test/core/http/corpus/5892cbb284771fc9761caae37b19cd6e27dbc104 b/test/core/http/corpus/5892cbb284771fc9761caae37b19cd6e27dbc104
new file mode 100644
index 0000000..fee5512
--- /dev/null
+++ b/test/core/http/corpus/5892cbb284771fc9761caae37b19cd6e27dbc104
@@ -0,0 +1,2 @@
+JÏHTTP‰/1.200:OKHHTã/21. 2è0 HTTP/

+1.1 200 OKHHTtTP‰
\ No newline at end of file
diff --git a/test/core/http/corpus/5aeab6e4f7c2a1c09d4ac0dbdb3beac4893607ee b/test/core/http/corpus/5aeab6e4f7c2a1c09d4ac0dbdb3beac4893607ee
new file mode 100644
index 0000000..bd7e239
--- /dev/null
+++ b/test/core/http/corpus/5aeab6e4f7c2a1c09d4ac0dbdb3beac4893607ee
Binary files differ
diff --git a/test/core/http/corpus/5b6292bdf009b0daecbc90b85cca30a88c36eec5 b/test/core/http/corpus/5b6292bdf009b0daecbc90b85cca30a88c36eec5
new file mode 100644
index 0000000..9a15ab0
--- /dev/null
+++ b/test/core/http/corpus/5b6292bdf009b0daecbc90b85cca30a88c36eec5
@@ -0,0 +1,2 @@
+HTTP/1. 200 OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/5c1659b77678b41faa4fa13df7772dae3238d1c0 b/test/core/http/corpus/5c1659b77678b41faa4fa13df7772dae3238d1c0
new file mode 100644
index 0000000..480708e
--- /dev/null
+++ b/test/core/http/corpus/5c1659b77678b41faa4fa13df7772dae3238d1c0
@@ -0,0 +1,2 @@
+@TTP/1.1y 00'JHTTP/1.1 +00ÿOïH HTTP/

+ve1.1 200s
\ No newline at end of file
diff --git a/test/core/http/corpus/5c81f61621e29ec9c6a64ac3af9b3b216141618e b/test/core/http/corpus/5c81f61621e29ec9c6a64ac3af9b3b216141618e
new file mode 100644
index 0000000..0ed0dfa
--- /dev/null
+++ b/test/core/http/corpus/5c81f61621e29ec9c6a64ac3af9b3b216141618e
Binary files differ
diff --git a/test/core/http/corpus/657368df512ca6294b9df16adf935a3f374a8be2 b/test/core/http/corpus/657368df512ca6294b9df16adf935a3f374a8be2
new file mode 100644
index 0000000..1f14f69
--- /dev/null
+++ b/test/core/http/corpus/657368df512ca6294b9df16adf935a3f374a8be2
@@ -0,0 +1,3 @@
+HTT
+/1.1 201 OKH

+des
\ No newline at end of file
diff --git a/test/core/http/corpus/7fc4520094902ce2c760d70eaad5b674d2817337 b/test/core/http/corpus/7fc4520094902ce2c760d70eaad5b674d2817337
new file mode 100644
index 0000000..8fc481d
--- /dev/null
+++ b/test/core/http/corpus/7fc4520094902ce2c760d70eaad5b674d2817337
@@ -0,0 +1,5 @@
+JHTTP/1.GET / HTTP/1.0
+1 200 OKH

+
+
+t
\ No newline at end of file
diff --git a/test/core/http/corpus/81f59a12b458ec3604035cb962165c604d1355e6 b/test/core/http/corpus/81f59a12b458ec3604035cb962165c604d1355e6
new file mode 100644
index 0000000..d4223cc
--- /dev/null
+++ b/test/core/http/corpus/81f59a12b458ec3604035cb962165c604d1355e6
@@ -0,0 +1,2 @@
+HTTP/1.1 8p) )MKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/8f41c50e88ee8c17ecad3d41d63d38fb12aca0b9 b/test/core/http/corpus/8f41c50e88ee8c17ecad3d41d63d38fb12aca0b9
new file mode 100644
index 0000000..99e2c48
--- /dev/null
+++ b/test/core/http/corpus/8f41c50e88ee8c17ecad3d41d63d38fb12aca0b9
@@ -0,0 +1,4 @@
+HTTP/1.1 200 OKH

+tHTHTTP/1. 20TP/01.020(: Oes,H0 OKH

+

+tteses
\ No newline at end of file
diff --git a/test/core/http/corpus/97c16de7fe3c390a2e6c09ff5c28f17d5c67542c b/test/core/http/corpus/97c16de7fe3c390a2e6c09ff5c28f17d5c67542c
new file mode 100644
index 0000000..776253d
--- /dev/null
+++ b/test/core/http/corpus/97c16de7fe3c390a2e6c09ff5c28f17d5c67542c
Binary files differ
diff --git a/test/core/http/corpus/97e4499d450c95660de86747f527e670f2012548 b/test/core/http/corpus/97e4499d450c95660de86747f527e670f2012548
new file mode 100644
index 0000000..b1927fb
--- /dev/null
+++ b/test/core/http/corpus/97e4499d450c95660de86747f527e670f2012548
@@ -0,0 +1,3 @@
+HTHHTT`TT
+/1.1 201 P*/OKH

+des1.1 2T
\ No newline at end of file
diff --git a/test/core/http/corpus/9a996857196e0998a1278994a9bab3d35526e7f1 b/test/core/http/corpus/9a996857196e0998a1278994a9bab3d35526e7f1
new file mode 100644
index 0000000..0eb2c0d
--- /dev/null
+++ b/test/core/http/corpus/9a996857196e0998a1278994a9bab3d35526e7f1
@@ -0,0 +1,2 @@
+@TTP/1.1y 002ÿOKH

+ves
\ No newline at end of file
diff --git a/test/core/http/corpus/9b7e00049ec356ecd84b1747e4e1941140139ae8 b/test/core/http/corpus/9b7e00049ec356ecd84b1747e4e1941140139ae8
new file mode 100644
index 0000000..f93b9a0
--- /dev/null
+++ b/test/core/http/corpus/9b7e00049ec356ecd84b1747e4e1941140139ae8
@@ -0,0 +1,3 @@
+„HTT/21. 200 HTTP/1.1 HT!TP/1OKH.1HTTP 200 OKH

+tHT/:/80 OKH

+1
\ No newline at end of file
diff --git a/test/core/http/corpus/9f0c38ec455cc363369b3674a2d32bc21c206de1 b/test/core/http/corpus/9f0c38ec455cc363369b3674a2d32bc21c206de1
new file mode 100644
index 0000000..4ea07dc
--- /dev/null
+++ b/test/core/http/corpus/9f0c38ec455cc363369b3674a2d32bc21c206de1
@@ -0,0 +1,5 @@
+JHTTP/1>GET / HTTP/2.0
+1 200 OKH

+
+
+t
\ No newline at end of file
diff --git a/test/core/http/corpus/a1dc7bc235e46eb21d91084d7b52d5ff9f45df85 b/test/core/http/corpus/a1dc7bc235e46eb21d91084d7b52d5ff9f45df85
new file mode 100644
index 0000000..2e95bac
--- /dev/null
+++ b/test/core/http/corpus/a1dc7bc235e46eb21d91084d7b52d5ff9f45df85
@@ -0,0 +1,3 @@
+„HTT/21. 200 HTTP/1.1 HT!TP/1OKH.1HTTP 200 OKH

+tHT//80) OKH

+1
\ No newline at end of file
diff --git a/test/core/http/corpus/aa3bbb876eafa8ad8ca4ff2eabc6dd94341d2441 b/test/core/http/corpus/aa3bbb876eafa8ad8ca4ff2eabc6dd94341d2441
new file mode 100644
index 0000000..837449d
--- /dev/null
+++ b/test/core/http/corpus/aa3bbb876eafa8ad8ca4ff2eabc6dd94341d2441
@@ -0,0 +1,2 @@
+HTTP/1.1 80î OH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/b04fea5c041c707db0ad9c09a81672557b52cc47 b/test/core/http/corpus/b04fea5c041c707db0ad9c09a81672557b52cc47
new file mode 100644
index 0000000..10905be
--- /dev/null
+++ b/test/core/http/corpus/b04fea5c041c707db0ad9c09a81672557b52cc47
@@ -0,0 +1,2 @@
+JHTTP/1.1 200 OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/c4acff8aa2ff886f35439f72625d05002990c940 b/test/core/http/corpus/c4acff8aa2ff886f35439f72625d05002990c940
new file mode 100644
index 0000000..4539d9f
--- /dev/null
+++ b/test/core/http/corpus/c4acff8aa2ff886f35439f72625d05002990c940
@@ -0,0 +1,4 @@
+JHTT/21. 200 HTTP/2OKH.1 200 OKH

+tHTTP/01.021  Oes,H

+t

+t
\ No newline at end of file
diff --git a/test/core/http/corpus/c55ce9995b002e88a102ae2891a71e8bacb346c8 b/test/core/http/corpus/c55ce9995b002e88a102ae2891a71e8bacb346c8
new file mode 100644
index 0000000..2704e4f
--- /dev/null
+++ b/test/core/http/corpus/c55ce9995b002e88a102ae2891a71e8bacb346c8
@@ -0,0 +1,2 @@
+HTTP/1.1 767) OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/ca5a0c00b8969310acb73d15ad0d0c602f1bd0c2 b/test/core/http/corpus/ca5a0c00b8969310acb73d15ad0d0c602f1bd0c2
new file mode 100644
index 0000000..f5cbbc6
--- /dev/null
+++ b/test/core/http/corpus/ca5a0c00b8969310acb73d15ad0d0c602f1bd0c2
@@ -0,0 +1,3 @@
+HJHTHHTT`TT
+/1.1 201 P*HHTT/T1/OKH

+des1.1 2.1T 20T1
\ No newline at end of file
diff --git a/test/core/http/corpus/cce734f1b263de6994f7950e0df7bf0c81449f70 b/test/core/http/corpus/cce734f1b263de6994f7950e0df7bf0c81449f70
new file mode 100644
index 0000000..f6ea09c
--- /dev/null
+++ b/test/core/http/corpus/cce734f1b263de6994f7950e0df7bf0c81449f70
@@ -0,0 +1,3 @@
+JHTT/21. 200 HTTPHTTP/1.1 80î OH/1OKH.0 200 OKH

+tHTTP/0

+te
\ No newline at end of file
diff --git a/test/core/http/corpus/d4c3e4cf5d035596433c30eaabbd2b2925f4b453 b/test/core/http/corpus/d4c3e4cf5d035596433c30eaabbd2b2925f4b453
new file mode 100644
index 0000000..be33d81
--- /dev/null
+++ b/test/core/http/corpus/d4c3e4cf5d035596433c30eaabbd2b2925f4b453
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OKH

+ HTTP/01.021 : Oes,H

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/d51f7fcc089f269c7afecaaca51966bab5fde629 b/test/core/http/corpus/d51f7fcc089f269c7afecaaca51966bab5fde629
new file mode 100644
index 0000000..e81a59f
--- /dev/null
+++ b/test/core/http/corpus/d51f7fcc089f269c7afecaaca51966bab5fde629
@@ -0,0 +1,2 @@
+ÏHTTP‰/1.200:OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/d936dad71c129cf659097dc3db64550c4dd467f4 b/test/core/http/corpus/d936dad71c129cf659097dc3db64550c4dd467f4
new file mode 100644
index 0000000..ccf9187
--- /dev/null
+++ b/test/core/http/corpus/d936dad71c129cf659097dc3db64550c4dd467f4
@@ -0,0 +1,2 @@
+HTTP‰/1.200 OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/e275b0466a8fb8d9e0e15856e343ddc7112ae66b b/test/core/http/corpus/e275b0466a8fb8d9e0e15856e343ddc7112ae66b
new file mode 100644
index 0000000..b6fc095
--- /dev/null
+++ b/test/core/http/corpus/e275b0466a8fb8d9e0e15856e343ddc7112ae66b
@@ -0,0 +1,3 @@
+JHTT/21. 200 HTTRHTTP/1.1 0î OL/1OKH.0 200 OKH

+tHTTP/0

+te
\ No newline at end of file
diff --git a/test/core/http/corpus/e5c364b205855a2991ce07482aebb2a3a6147089 b/test/core/http/corpus/e5c364b205855a2991ce07482aebb2a3a6147089
new file mode 100644
index 0000000..98b5f62
--- /dev/null
+++ b/test/core/http/corpus/e5c364b205855a2991ce07482aebb2a3a6147089
@@ -0,0 +1,2 @@
+TTHP‰/1.200 OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/ee2077e08c3cfccd9bd82adb574ac4fc7d429afb b/test/core/http/corpus/ee2077e08c3cfccd9bd82adb574ac4fc7d429afb
new file mode 100644
index 0000000..78b36c9
--- /dev/null
+++ b/test/core/http/corpus/ee2077e08c3cfccd9bd82adb574ac4fc7d429afb
@@ -0,0 +1,2 @@
+ITHTTTPHT/12 …2S HTKP/1.1 767) OKH

+tes
\ No newline at end of file
diff --git a/test/core/http/corpus/fc5d4b9117ba9e87388174aee4f4970bdfe8d066 b/test/core/http/corpus/fc5d4b9117ba9e87388174aee4f4970bdfe8d066
new file mode 100644
index 0000000..06f1a3b
--- /dev/null
+++ b/test/core/http/corpus/fc5d4b9117ba9e87388174aee4f4970bdfe8d066
@@ -0,0 +1 @@
+HH
\ No newline at end of file
diff --git a/test/core/http/corpus/fdeb2c7daa9e7704f67e141106384e6dd0042c0b b/test/core/http/corpus/fdeb2c7daa9e7704f67e141106384e6dd0042c0b
new file mode 100644
index 0000000..eb63d31
--- /dev/null
+++ b/test/core/http/corpus/fdeb2c7daa9e7704f67e141106384e6dd0042c0b
Binary files differ
diff --git a/test/core/http/corpus/request1.txt b/test/core/http/corpus/request1.txt
new file mode 100644
index 0000000..16a750f
--- /dev/null
+++ b/test/core/http/corpus/request1.txt
@@ -0,0 +1,3 @@
+GET / HTTP/1.0
+
+
diff --git a/test/core/http/corpus/request2.txt b/test/core/http/corpus/request2.txt
new file mode 100644
index 0000000..897a284
--- /dev/null
+++ b/test/core/http/corpus/request2.txt
@@ -0,0 +1,3 @@
+GET / HTTP/1.0
+Content-Length: 128
+
diff --git a/test/core/http/corpus/request3.txt b/test/core/http/corpus/request3.txt
new file mode 100644
index 0000000..aaa75bb
--- /dev/null
+++ b/test/core/http/corpus/request3.txt
@@ -0,0 +1,3 @@
+GET / HTTP/1.1
+Content-Length: 128
+
diff --git a/test/core/http/corpus/request4.txt b/test/core/http/corpus/request4.txt
new file mode 100644
index 0000000..593f6fa
--- /dev/null
+++ b/test/core/http/corpus/request4.txt
@@ -0,0 +1,3 @@
+GET /foo.bar HTTP/1.1
+Content-Length: 128
+
diff --git a/test/core/http/corpus/request5.txt b/test/core/http/corpus/request5.txt
new file mode 100644
index 0000000..19fb244
--- /dev/null
+++ b/test/core/http/corpus/request5.txt
@@ -0,0 +1,3 @@
+POST / HTTP/1.0
+
+asdlfkjadsfl;akdjsfasdf
diff --git a/test/core/http/corpus/response1.txt b/test/core/http/corpus/response1.txt
new file mode 100644
index 0000000..a171399
--- /dev/null
+++ b/test/core/http/corpus/response1.txt
@@ -0,0 +1,4 @@
+HTTP/1.1 200 OK
+test: hello
+
+abcd
diff --git a/test/core/http/corpus/response2.txt b/test/core/http/corpus/response2.txt
new file mode 100644
index 0000000..1b86449
--- /dev/null
+++ b/test/core/http/corpus/response2.txt
@@ -0,0 +1,4 @@
+HTTP/0.9 200 OK
+test: hello
+
+abcd
diff --git a/test/core/http/corpus/response3.txt b/test/core/http/corpus/response3.txt
new file mode 100644
index 0000000..9e5b046
--- /dev/null
+++ b/test/core/http/corpus/response3.txt
@@ -0,0 +1,5 @@
+HTTP/0.9 200 OK
+test: hello
+content-length: 102384398
+
+abcd
diff --git a/test/core/http/corpus/response4.txt b/test/core/http/corpus/response4.txt
new file mode 100644
index 0000000..b237b01
--- /dev/null
+++ b/test/core/http/corpus/response4.txt
@@ -0,0 +1,2 @@
+HTTP/1.1 404 Not Found
+
diff --git a/test/core/http/corpus/response5.txt b/test/core/http/corpus/response5.txt
new file mode 100644
index 0000000..2630595
--- /dev/null
+++ b/test/core/http/corpus/response5.txt
@@ -0,0 +1,5 @@
+HTTP/0.9 200 OK
+test: hello
+content-length: 4
+
+abcd
diff --git a/test/core/http/corpus/response6.txt b/test/core/http/corpus/response6.txt
new file mode 100644
index 0000000..797b6ee
--- /dev/null
+++ b/test/core/http/corpus/response6.txt
@@ -0,0 +1,5 @@
+HTTP/0.9 200 OK
+test: hello
+content-length: 6
+
+abcd
diff --git a/test/core/http/corpus/toolong.txt b/test/core/http/corpus/toolong.txt
new file mode 100644
index 0000000..9a9d5e2
--- /dev/null
+++ b/test/core/http/corpus/toolong.txt
@@ -0,0 +1,2 @@
+GET / HTTP/1.1
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
diff --git a/test/core/http/format_request_test.c b/test/core/http/format_request_test.c
new file mode 100644
index 0000000..a676420
--- /dev/null
+++ b/test/core/http/format_request_test.c
@@ -0,0 +1,164 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/http/format_request.h"
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+#include "test/core/util/test_config.h"
+
+static void test_format_get_request(void) {
+  grpc_http_header hdr = {"x-yz", "abc"};
+  grpc_httpcli_request req;
+  gpr_slice slice;
+
+  memset(&req, 0, sizeof(req));
+  req.host = "example.com";
+  req.http.path = "/index.html";
+  req.http.hdr_count = 1;
+  req.http.hdrs = &hdr;
+
+  slice = grpc_httpcli_format_get_request(&req);
+
+  GPR_ASSERT(0 == gpr_slice_str_cmp(slice,
+                                    "GET /index.html HTTP/1.0\r\n"
+                                    "Host: example.com\r\n"
+                                    "Connection: close\r\n"
+                                    "User-Agent: " GRPC_HTTPCLI_USER_AGENT
+                                    "\r\n"
+                                    "x-yz: abc\r\n"
+                                    "\r\n"));
+
+  gpr_slice_unref(slice);
+}
+
+static void test_format_post_request(void) {
+  grpc_http_header hdr = {"x-yz", "abc"};
+  grpc_httpcli_request req;
+  gpr_slice slice;
+  char body_bytes[] = "fake body";
+  size_t body_len = 9;
+
+  memset(&req, 0, sizeof(req));
+  req.host = "example.com";
+  req.http.path = "/index.html";
+  req.http.hdr_count = 1;
+  req.http.hdrs = &hdr;
+
+  slice = grpc_httpcli_format_post_request(&req, body_bytes, body_len);
+
+  GPR_ASSERT(0 == gpr_slice_str_cmp(slice,
+                                    "POST /index.html HTTP/1.0\r\n"
+                                    "Host: example.com\r\n"
+                                    "Connection: close\r\n"
+                                    "User-Agent: " GRPC_HTTPCLI_USER_AGENT
+                                    "\r\n"
+                                    "x-yz: abc\r\n"
+                                    "Content-Type: text/plain\r\n"
+                                    "Content-Length: 9\r\n"
+                                    "\r\n"
+                                    "fake body"));
+
+  gpr_slice_unref(slice);
+}
+
+static void test_format_post_request_no_body(void) {
+  grpc_http_header hdr = {"x-yz", "abc"};
+  grpc_httpcli_request req;
+  gpr_slice slice;
+
+  memset(&req, 0, sizeof(req));
+  req.host = "example.com";
+  req.http.path = "/index.html";
+  req.http.hdr_count = 1;
+  req.http.hdrs = &hdr;
+
+  slice = grpc_httpcli_format_post_request(&req, NULL, 0);
+
+  GPR_ASSERT(0 == gpr_slice_str_cmp(slice,
+                                    "POST /index.html HTTP/1.0\r\n"
+                                    "Host: example.com\r\n"
+                                    "Connection: close\r\n"
+                                    "User-Agent: " GRPC_HTTPCLI_USER_AGENT
+                                    "\r\n"
+                                    "x-yz: abc\r\n"
+                                    "\r\n"));
+
+  gpr_slice_unref(slice);
+}
+
+static void test_format_post_request_content_type_override(void) {
+  grpc_http_header hdrs[2];
+  grpc_httpcli_request req;
+  gpr_slice slice;
+  char body_bytes[] = "fake%20body";
+  size_t body_len = 11;
+
+  hdrs[0].key = "x-yz";
+  hdrs[0].value = "abc";
+  hdrs[1].key = "Content-Type";
+  hdrs[1].value = "application/x-www-form-urlencoded";
+  memset(&req, 0, sizeof(req));
+  req.host = "example.com";
+  req.http.path = "/index.html";
+  req.http.hdr_count = 2;
+  req.http.hdrs = hdrs;
+
+  slice = grpc_httpcli_format_post_request(&req, body_bytes, body_len);
+
+  GPR_ASSERT(0 == gpr_slice_str_cmp(
+                      slice,
+                      "POST /index.html HTTP/1.0\r\n"
+                      "Host: example.com\r\n"
+                      "Connection: close\r\n"
+                      "User-Agent: " GRPC_HTTPCLI_USER_AGENT "\r\n"
+                      "x-yz: abc\r\n"
+                      "Content-Type: application/x-www-form-urlencoded\r\n"
+                      "Content-Length: 11\r\n"
+                      "\r\n"
+                      "fake%20body"));
+
+  gpr_slice_unref(slice);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+
+  test_format_get_request();
+  test_format_post_request();
+  test_format_post_request_no_body();
+  test_format_post_request_content_type_override();
+
+  return 0;
+}
diff --git a/test/core/http/fuzzer.c b/test/core/http/fuzzer.c
new file mode 100644
index 0000000..bab846d
--- /dev/null
+++ b/test/core/http/fuzzer.c
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+#include "src/core/lib/http/parser.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  grpc_http_parser parser;
+  grpc_http_parser_init(&parser);
+  gpr_slice slice = gpr_slice_from_copied_buffer((const char *)data, size);
+  grpc_http_parser_parse(&parser, slice);
+  grpc_http_parser_eof(&parser);
+  gpr_slice_unref(slice);
+  grpc_http_parser_destroy(&parser);
+  return 0;
+}
diff --git a/test/core/http/httpcli_test.c b/test/core/http/httpcli_test.c
new file mode 100644
index 0000000..1fdbcd0
--- /dev/null
+++ b/test/core/http/httpcli_test.c
@@ -0,0 +1,200 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/http/httpcli.h"
+
+#include <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/subprocess.h>
+#include <grpc/support/sync.h>
+#include "src/core/lib/iomgr/iomgr.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+static int g_done = 0;
+static grpc_httpcli_context g_context;
+static gpr_mu *g_mu;
+static grpc_pollset *g_pollset;
+
+static gpr_timespec n_seconds_time(int seconds) {
+  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(seconds);
+}
+
+static void on_finish(grpc_exec_ctx *exec_ctx, void *arg,
+                      const grpc_httpcli_response *response) {
+  const char *expect =
+      "<html><head><title>Hello world!</title></head>"
+      "<body><p>This is a test</p></body></html>";
+  GPR_ASSERT(arg == (void *)42);
+  GPR_ASSERT(response);
+  GPR_ASSERT(response->status == 200);
+  GPR_ASSERT(response->body_length == strlen(expect));
+  GPR_ASSERT(0 == memcmp(expect, response->body, response->body_length));
+  gpr_mu_lock(g_mu);
+  g_done = 1;
+  grpc_pollset_kick(g_pollset, NULL);
+  gpr_mu_unlock(g_mu);
+}
+
+static void test_get(int port) {
+  grpc_httpcli_request req;
+  char *host;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  g_done = 0;
+  gpr_log(GPR_INFO, "test_get");
+
+  gpr_asprintf(&host, "localhost:%d", port);
+  gpr_log(GPR_INFO, "requesting from %s", host);
+
+  memset(&req, 0, sizeof(req));
+  req.host = host;
+  req.http.path = "/get";
+  req.handshaker = &grpc_httpcli_plaintext;
+
+  grpc_httpcli_get(&exec_ctx, &g_context, g_pollset, &req, n_seconds_time(15),
+                   on_finish, (void *)42);
+  gpr_mu_lock(g_mu);
+  while (!g_done) {
+    grpc_pollset_worker *worker = NULL;
+    grpc_pollset_work(&exec_ctx, g_pollset, &worker,
+                      gpr_now(GPR_CLOCK_MONOTONIC), n_seconds_time(20));
+    gpr_mu_unlock(g_mu);
+    grpc_exec_ctx_finish(&exec_ctx);
+    gpr_mu_lock(g_mu);
+  }
+  gpr_mu_unlock(g_mu);
+  gpr_free(host);
+}
+
+static void test_post(int port) {
+  grpc_httpcli_request req;
+  char *host;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  g_done = 0;
+  gpr_log(GPR_INFO, "test_post");
+
+  gpr_asprintf(&host, "localhost:%d", port);
+  gpr_log(GPR_INFO, "posting to %s", host);
+
+  memset(&req, 0, sizeof(req));
+  req.host = host;
+  req.http.path = "/post";
+  req.handshaker = &grpc_httpcli_plaintext;
+
+  grpc_httpcli_post(&exec_ctx, &g_context, g_pollset, &req, "hello", 5,
+                    n_seconds_time(15), on_finish, (void *)42);
+  gpr_mu_lock(g_mu);
+  while (!g_done) {
+    grpc_pollset_worker *worker = NULL;
+    grpc_pollset_work(&exec_ctx, g_pollset, &worker,
+                      gpr_now(GPR_CLOCK_MONOTONIC), n_seconds_time(20));
+    gpr_mu_unlock(g_mu);
+    grpc_exec_ctx_finish(&exec_ctx);
+    gpr_mu_lock(g_mu);
+  }
+  gpr_mu_unlock(g_mu);
+  gpr_free(host);
+}
+
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
+  grpc_pollset_destroy(p);
+}
+
+int main(int argc, char **argv) {
+  grpc_closure destroyed;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  gpr_subprocess *server;
+  char *me = argv[0];
+  char *lslash = strrchr(me, '/');
+  char *args[4];
+  int port = grpc_pick_unused_port_or_die();
+  int arg_shift = 0;
+  /* figure out where we are */
+  char *root;
+  if (lslash) {
+    root = gpr_malloc((size_t)(lslash - me + 1));
+    memcpy(root, me, (size_t)(lslash - me));
+    root[lslash - me] = 0;
+  } else {
+    root = gpr_strdup(".");
+  }
+
+  GPR_ASSERT(argc <= 2);
+  if (argc == 2) {
+    args[0] = gpr_strdup(argv[1]);
+  } else {
+    arg_shift = 1;
+    gpr_asprintf(&args[0], "%s/../../tools/distrib/python_wrapper.sh", root);
+    gpr_asprintf(&args[1], "%s/../../test/core/http/test_server.py", root);
+  }
+
+  /* start the server */
+  args[1 + arg_shift] = "--port";
+  gpr_asprintf(&args[2 + arg_shift], "%d", port);
+  server = gpr_subprocess_create(3 + arg_shift, (const char **)args);
+  GPR_ASSERT(server);
+  gpr_free(args[0]);
+  if (arg_shift) gpr_free(args[1]);
+  gpr_free(args[2 + arg_shift]);
+  gpr_free(root);
+
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                               gpr_time_from_seconds(5, GPR_TIMESPAN)));
+
+  grpc_test_init(argc, argv);
+  grpc_init();
+  grpc_httpcli_context_init(&g_context);
+  g_pollset = gpr_malloc(grpc_pollset_size());
+  grpc_pollset_init(g_pollset, &g_mu);
+
+  test_get(port);
+  test_post(port);
+
+  grpc_httpcli_context_destroy(&g_context);
+  grpc_closure_init(&destroyed, destroy_pollset, g_pollset);
+  grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
+  grpc_exec_ctx_finish(&exec_ctx);
+  grpc_shutdown();
+
+  gpr_free(g_pollset);
+
+  gpr_subprocess_destroy(server);
+
+  return 0;
+}
diff --git a/test/core/http/httpscli_test.c b/test/core/http/httpscli_test.c
new file mode 100644
index 0000000..71db3e7
--- /dev/null
+++ b/test/core/http/httpscli_test.c
@@ -0,0 +1,203 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/http/httpcli.h"
+
+#include <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/subprocess.h>
+#include <grpc/support/sync.h>
+#include "src/core/lib/iomgr/iomgr.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+static int g_done = 0;
+static grpc_httpcli_context g_context;
+static gpr_mu *g_mu;
+static grpc_pollset *g_pollset;
+
+static gpr_timespec n_seconds_time(int seconds) {
+  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(seconds);
+}
+
+static void on_finish(grpc_exec_ctx *exec_ctx, void *arg,
+                      const grpc_httpcli_response *response) {
+  const char *expect =
+      "<html><head><title>Hello world!</title></head>"
+      "<body><p>This is a test</p></body></html>";
+  GPR_ASSERT(arg == (void *)42);
+  GPR_ASSERT(response);
+  GPR_ASSERT(response->status == 200);
+  GPR_ASSERT(response->body_length == strlen(expect));
+  GPR_ASSERT(0 == memcmp(expect, response->body, response->body_length));
+  gpr_mu_lock(g_mu);
+  g_done = 1;
+  grpc_pollset_kick(g_pollset, NULL);
+  gpr_mu_unlock(g_mu);
+}
+
+static void test_get(int port) {
+  grpc_httpcli_request req;
+  char *host;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  g_done = 0;
+  gpr_log(GPR_INFO, "test_get");
+
+  gpr_asprintf(&host, "localhost:%d", port);
+  gpr_log(GPR_INFO, "requesting from %s", host);
+
+  memset(&req, 0, sizeof(req));
+  req.host = host;
+  req.ssl_host_override = "foo.test.google.fr";
+  req.http.path = "/get";
+  req.handshaker = &grpc_httpcli_ssl;
+
+  grpc_httpcli_get(&exec_ctx, &g_context, g_pollset, &req, n_seconds_time(15),
+                   on_finish, (void *)42);
+  gpr_mu_lock(g_mu);
+  while (!g_done) {
+    grpc_pollset_worker *worker = NULL;
+    grpc_pollset_work(&exec_ctx, g_pollset, &worker,
+                      gpr_now(GPR_CLOCK_MONOTONIC), n_seconds_time(20));
+    gpr_mu_unlock(g_mu);
+    grpc_exec_ctx_finish(&exec_ctx);
+    gpr_mu_lock(g_mu);
+  }
+  gpr_mu_unlock(g_mu);
+  gpr_free(host);
+}
+
+static void test_post(int port) {
+  grpc_httpcli_request req;
+  char *host;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  g_done = 0;
+  gpr_log(GPR_INFO, "test_post");
+
+  gpr_asprintf(&host, "localhost:%d", port);
+  gpr_log(GPR_INFO, "posting to %s", host);
+
+  memset(&req, 0, sizeof(req));
+  req.host = host;
+  req.ssl_host_override = "foo.test.google.fr";
+  req.http.path = "/post";
+  req.handshaker = &grpc_httpcli_ssl;
+
+  grpc_httpcli_post(&exec_ctx, &g_context, g_pollset, &req, "hello", 5,
+                    n_seconds_time(15), on_finish, (void *)42);
+  gpr_mu_lock(g_mu);
+  while (!g_done) {
+    grpc_pollset_worker *worker = NULL;
+    grpc_pollset_work(&exec_ctx, g_pollset, &worker,
+                      gpr_now(GPR_CLOCK_MONOTONIC), n_seconds_time(20));
+    gpr_mu_unlock(g_mu);
+    grpc_exec_ctx_finish(&exec_ctx);
+    gpr_mu_lock(g_mu);
+  }
+  gpr_mu_unlock(g_mu);
+  gpr_free(host);
+}
+
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
+  grpc_pollset_destroy(p);
+}
+
+int main(int argc, char **argv) {
+  grpc_closure destroyed;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  gpr_subprocess *server;
+  char *me = argv[0];
+  char *lslash = strrchr(me, '/');
+  char *args[5];
+  int port = grpc_pick_unused_port_or_die();
+  int arg_shift = 0;
+  /* figure out where we are */
+  char *root;
+  if (lslash) {
+    root = gpr_malloc((size_t)(lslash - me + 1));
+    memcpy(root, me, (size_t)(lslash - me));
+    root[lslash - me] = 0;
+  } else {
+    root = gpr_strdup(".");
+  }
+
+  GPR_ASSERT(argc <= 2);
+  if (argc == 2) {
+    args[0] = gpr_strdup(argv[1]);
+  } else {
+    arg_shift = 1;
+    gpr_asprintf(&args[0], "%s/../../tools/distrib/python_wrapper.sh", root);
+    gpr_asprintf(&args[1], "%s/../../test/core/http/test_server.py", root);
+  }
+
+  /* start the server */
+  args[1 + arg_shift] = "--port";
+  gpr_asprintf(&args[2 + arg_shift], "%d", port);
+  args[3 + arg_shift] = "--ssl";
+  server = gpr_subprocess_create(4 + arg_shift, (const char **)args);
+  GPR_ASSERT(server);
+  gpr_free(args[0]);
+  if (arg_shift) gpr_free(args[1]);
+  gpr_free(args[2 + arg_shift]);
+  gpr_free(root);
+
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                               gpr_time_from_seconds(5, GPR_TIMESPAN)));
+
+  grpc_test_init(argc, argv);
+  grpc_init();
+  grpc_httpcli_context_init(&g_context);
+  g_pollset = gpr_malloc(grpc_pollset_size());
+  grpc_pollset_init(g_pollset, &g_mu);
+
+  test_get(port);
+  test_post(port);
+
+  grpc_httpcli_context_destroy(&g_context);
+  grpc_closure_init(&destroyed, destroy_pollset, g_pollset);
+  grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
+  grpc_exec_ctx_finish(&exec_ctx);
+  grpc_shutdown();
+
+  gpr_free(g_pollset);
+
+  gpr_subprocess_destroy(server);
+
+  return 0;
+}
diff --git a/test/core/http/parser_test.c b/test/core/http/parser_test.c
new file mode 100644
index 0000000..149919d
--- /dev/null
+++ b/test/core/http/parser_test.c
@@ -0,0 +1,295 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/http/parser.h"
+
+#include <stdarg.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 "test/core/util/slice_splitter.h"
+#include "test/core/util/test_config.h"
+
+static void test_request_succeeds(grpc_slice_split_mode split_mode,
+                                  char *request, char *expect_method,
+                                  grpc_http_version expect_version,
+                                  char *expect_path, char *expect_body, ...) {
+  grpc_http_parser parser;
+  gpr_slice input_slice = gpr_slice_from_copied_string(request);
+  size_t num_slices;
+  size_t i;
+  gpr_slice *slices;
+  va_list args;
+
+  grpc_split_slices(split_mode, &input_slice, 1, &slices, &num_slices);
+  gpr_slice_unref(input_slice);
+
+  grpc_http_parser_init(&parser);
+
+  for (i = 0; i < num_slices; i++) {
+    GPR_ASSERT(grpc_http_parser_parse(&parser, slices[i]));
+    gpr_slice_unref(slices[i]);
+  }
+  GPR_ASSERT(grpc_http_parser_eof(&parser));
+
+  GPR_ASSERT(GRPC_HTTP_REQUEST == parser.type);
+  GPR_ASSERT(0 == strcmp(expect_method, parser.http.request.method));
+  GPR_ASSERT(0 == strcmp(expect_path, parser.http.request.path));
+  GPR_ASSERT(expect_version == parser.http.request.version);
+
+  if (expect_body != NULL) {
+    GPR_ASSERT(strlen(expect_body) == parser.http.request.body_length);
+    GPR_ASSERT(0 == memcmp(expect_body, parser.http.request.body,
+                           parser.http.request.body_length));
+  } else {
+    GPR_ASSERT(parser.http.request.body_length == 0);
+  }
+
+  va_start(args, expect_body);
+  i = 0;
+  for (;;) {
+    char *expect_key;
+    char *expect_value;
+    expect_key = va_arg(args, char *);
+    if (!expect_key) break;
+    GPR_ASSERT(i < parser.http.request.hdr_count);
+    expect_value = va_arg(args, char *);
+    GPR_ASSERT(expect_value);
+    GPR_ASSERT(0 == strcmp(expect_key, parser.http.request.hdrs[i].key));
+    GPR_ASSERT(0 == strcmp(expect_value, parser.http.request.hdrs[i].value));
+    i++;
+  }
+  va_end(args);
+  GPR_ASSERT(i == parser.http.request.hdr_count);
+
+  grpc_http_parser_destroy(&parser);
+  gpr_free(slices);
+}
+
+static void test_succeeds(grpc_slice_split_mode split_mode, char *response,
+                          int expect_status, char *expect_body, ...) {
+  grpc_http_parser parser;
+  gpr_slice input_slice = gpr_slice_from_copied_string(response);
+  size_t num_slices;
+  size_t i;
+  gpr_slice *slices;
+  va_list args;
+
+  grpc_split_slices(split_mode, &input_slice, 1, &slices, &num_slices);
+  gpr_slice_unref(input_slice);
+
+  grpc_http_parser_init(&parser);
+
+  for (i = 0; i < num_slices; i++) {
+    GPR_ASSERT(grpc_http_parser_parse(&parser, slices[i]));
+    gpr_slice_unref(slices[i]);
+  }
+  GPR_ASSERT(grpc_http_parser_eof(&parser));
+
+  GPR_ASSERT(GRPC_HTTP_RESPONSE == parser.type);
+  GPR_ASSERT(expect_status == parser.http.response.status);
+  if (expect_body != NULL) {
+    GPR_ASSERT(strlen(expect_body) == parser.http.response.body_length);
+    GPR_ASSERT(0 == memcmp(expect_body, parser.http.response.body,
+                           parser.http.response.body_length));
+  } else {
+    GPR_ASSERT(parser.http.response.body_length == 0);
+  }
+
+  va_start(args, expect_body);
+  i = 0;
+  for (;;) {
+    char *expect_key;
+    char *expect_value;
+    expect_key = va_arg(args, char *);
+    if (!expect_key) break;
+    GPR_ASSERT(i < parser.http.response.hdr_count);
+    expect_value = va_arg(args, char *);
+    GPR_ASSERT(expect_value);
+    GPR_ASSERT(0 == strcmp(expect_key, parser.http.response.hdrs[i].key));
+    GPR_ASSERT(0 == strcmp(expect_value, parser.http.response.hdrs[i].value));
+    i++;
+  }
+  va_end(args);
+  GPR_ASSERT(i == parser.http.response.hdr_count);
+
+  grpc_http_parser_destroy(&parser);
+  gpr_free(slices);
+}
+
+static void test_fails(grpc_slice_split_mode split_mode, char *response) {
+  grpc_http_parser parser;
+  gpr_slice input_slice = gpr_slice_from_copied_string(response);
+  size_t num_slices;
+  size_t i;
+  gpr_slice *slices;
+  int done = 0;
+
+  grpc_split_slices(split_mode, &input_slice, 1, &slices, &num_slices);
+  gpr_slice_unref(input_slice);
+
+  grpc_http_parser_init(&parser);
+
+  for (i = 0; i < num_slices; i++) {
+    if (!done && !grpc_http_parser_parse(&parser, slices[i])) {
+      done = 1;
+    }
+    gpr_slice_unref(slices[i]);
+  }
+  if (!done && !grpc_http_parser_eof(&parser)) {
+    done = 1;
+  }
+  GPR_ASSERT(done);
+
+  grpc_http_parser_destroy(&parser);
+  gpr_free(slices);
+}
+
+static const uint8_t failed_test1[] = {
+    0x9e, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x4a,
+    0x48, 0x54, 0x54, 0x30, 0x32, 0x16, 0xa,  0x2f, 0x48, 0x20,
+    0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x31, 0x54, 0x54, 0xb9,
+    0x32, 0x31, 0x2e, 0x20, 0x32, 0x30, 0x20,
+};
+
+typedef struct {
+  const char *name;
+  const uint8_t *data;
+  size_t length;
+} failed_test;
+
+#define FAILED_TEST(name) \
+  { #name, name, sizeof(name) }
+
+failed_test failed_tests[] = {
+    FAILED_TEST(failed_test1),
+};
+
+static void test_doesnt_crash(failed_test t) {
+  gpr_log(GPR_DEBUG, "Run previously failed test: %s", t.name);
+  grpc_http_parser p;
+  grpc_http_parser_init(&p);
+  gpr_slice slice =
+      gpr_slice_from_copied_buffer((const char *)t.data, t.length);
+  grpc_http_parser_parse(&p, slice);
+  gpr_slice_unref(slice);
+  grpc_http_parser_destroy(&p);
+}
+
+int main(int argc, char **argv) {
+  size_t i;
+  const grpc_slice_split_mode split_modes[] = {GRPC_SLICE_SPLIT_IDENTITY,
+                                               GRPC_SLICE_SPLIT_ONE_BYTE};
+  char *tmp1, *tmp2;
+
+  grpc_test_init(argc, argv);
+
+  for (i = 0; i < GPR_ARRAY_SIZE(failed_tests); i++) {
+    test_doesnt_crash(failed_tests[i]);
+  }
+
+  for (i = 0; i < GPR_ARRAY_SIZE(split_modes); i++) {
+    test_succeeds(split_modes[i],
+                  "HTTP/1.0 200 OK\r\n"
+                  "xyz: abc\r\n"
+                  "\r\n"
+                  "hello world!",
+                  200, "hello world!", "xyz", "abc", NULL);
+    test_succeeds(split_modes[i],
+                  "HTTP/1.0 404 Not Found\r\n"
+                  "\r\n",
+                  404, NULL, NULL);
+    test_succeeds(split_modes[i],
+                  "HTTP/1.1 200 OK\r\n"
+                  "xyz: abc\r\n"
+                  "\r\n"
+                  "hello world!",
+                  200, "hello world!", "xyz", "abc", NULL);
+    test_request_succeeds(split_modes[i],
+                          "GET / HTTP/1.0\r\n"
+                          "\r\n",
+                          "GET", GRPC_HTTP_HTTP10, "/", NULL, NULL);
+    test_request_succeeds(split_modes[i],
+                          "GET / HTTP/1.0\r\n"
+                          "\r\n"
+                          "xyz",
+                          "GET", GRPC_HTTP_HTTP10, "/", "xyz", NULL);
+    test_request_succeeds(split_modes[i],
+                          "GET / HTTP/1.1\r\n"
+                          "\r\n"
+                          "xyz",
+                          "GET", GRPC_HTTP_HTTP11, "/", "xyz", NULL);
+    test_request_succeeds(split_modes[i],
+                          "GET / HTTP/2.0\r\n"
+                          "\r\n"
+                          "xyz",
+                          "GET", GRPC_HTTP_HTTP20, "/", "xyz", NULL);
+    test_request_succeeds(split_modes[i],
+                          "GET / HTTP/1.0\r\n"
+                          "xyz: abc\r\n"
+                          "\r\n"
+                          "xyz",
+                          "GET", GRPC_HTTP_HTTP10, "/", "xyz", "xyz", "abc",
+                          NULL);
+    test_fails(split_modes[i], "HTTP/1.0\r\n");
+    test_fails(split_modes[i], "HTTP/1.2\r\n");
+    test_fails(split_modes[i], "HTTP/1.0 000 XYX\r\n");
+    test_fails(split_modes[i], "HTTP/1.0 200 OK\n");
+    test_fails(split_modes[i], "HTTP/1.0 200 OK\r\n");
+    test_fails(split_modes[i], "HTTP/1.0 200 OK\r\nFoo x\r\n");
+    test_fails(split_modes[i],
+               "HTTP/1.0 200 OK\r\n"
+               "xyz: abc\r\n"
+               "  def\r\n"
+               "\r\n"
+               "hello world!");
+    test_fails(split_modes[i], "GET\r\n");
+    test_fails(split_modes[i], "GET /\r\n");
+    test_fails(split_modes[i], "GET / HTTP/0.0\r\n");
+    test_fails(split_modes[i], "GET / ____/1.0\r\n");
+    test_fails(split_modes[i], "GET / HTTP/1.2\r\n");
+
+    tmp1 = gpr_malloc(2 * GRPC_HTTP_PARSER_MAX_HEADER_LENGTH);
+    memset(tmp1, 'a', 2 * GRPC_HTTP_PARSER_MAX_HEADER_LENGTH - 1);
+    tmp1[2 * GRPC_HTTP_PARSER_MAX_HEADER_LENGTH - 1] = 0;
+    gpr_asprintf(&tmp2, "HTTP/1.0 200 OK\r\nxyz: %s\r\n\r\n", tmp1);
+    test_fails(split_modes[i], tmp2);
+    gpr_free(tmp1);
+    gpr_free(tmp2);
+  }
+
+  return 0;
+}
diff --git a/test/core/http/test_server.py b/test/core/http/test_server.py
new file mode 100755
index 0000000..9f8d052
--- /dev/null
+++ b/test/core/http/test_server.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python2.7
+# Copyright 2015-2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Server for httpcli_test"""
+
+import argparse
+import BaseHTTPServer
+import os
+import ssl
+import sys
+
+_PEM = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../../..', 'src/core/lib/tsi/test_creds/server1.pem'))
+_KEY = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../../..', 'src/core/lib/tsi/test_creds/server1.key'))
+print _PEM
+open(_PEM).close()
+
+argp = argparse.ArgumentParser(description='Server for httpcli_test')
+argp.add_argument('-p', '--port', default=10080, type=int)
+argp.add_argument('-s', '--ssl', default=False, action='store_true')
+args = argp.parse_args()
+
+print 'server running on port %d' % args.port
+
+class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
+	def good(self):
+		self.send_response(200)
+		self.send_header('Content-Type', 'text/html')
+		self.end_headers()
+		self.wfile.write('<html><head><title>Hello world!</title></head>')
+		self.wfile.write('<body><p>This is a test</p></body></html>')
+
+	def do_GET(self):
+		if self.path == '/get':
+			self.good()
+
+	def do_POST(self):
+		content = self.rfile.read(int(self.headers.getheader('content-length')))
+		if self.path == '/post' and content == 'hello':
+			self.good()
+
+httpd = BaseHTTPServer.HTTPServer(('localhost', args.port), Handler)
+if args.ssl:
+	httpd.socket = ssl.wrap_socket(httpd.socket, certfile=_PEM, keyfile=_KEY, server_side=True)
+httpd.serve_forever()
diff --git a/test/core/httpcli/format_request_test.c b/test/core/httpcli/format_request_test.c
deleted file mode 100644
index da85004..0000000
--- a/test/core/httpcli/format_request_test.c
+++ /dev/null
@@ -1,165 +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/httpcli/format_request.h"
-
-#include <string.h>
-
-#include <grpc/support/log.h>
-#include "test/core/util/test_config.h"
-
-static void test_format_get_request(void) {
-  grpc_httpcli_header hdr = {"x-yz", "abc"};
-  grpc_httpcli_request req;
-  gpr_slice slice;
-
-  memset(&req, 0, sizeof(req));
-  req.host = "example.com";
-  req.path = "/index.html";
-  req.hdr_count = 1;
-  req.hdrs = &hdr;
-
-  slice = grpc_httpcli_format_get_request(&req);
-
-  GPR_ASSERT(0 == gpr_slice_str_cmp(slice,
-                                    "GET /index.html HTTP/1.0\r\n"
-                                    "Host: example.com\r\n"
-                                    "Connection: close\r\n"
-                                    "User-Agent: " GRPC_HTTPCLI_USER_AGENT
-                                    "\r\n"
-                                    "x-yz: abc\r\n"
-                                    "\r\n"));
-
-  gpr_slice_unref(slice);
-}
-
-static void test_format_post_request(void) {
-  grpc_httpcli_header hdr = {"x-yz", "abc"};
-  grpc_httpcli_request req;
-  gpr_slice slice;
-  char body_bytes[] = "fake body";
-  size_t body_len = 9;
-
-  memset(&req, 0, sizeof(req));
-  req.host = "example.com";
-  req.path = "/index.html";
-  req.hdr_count = 1;
-  req.hdrs = &hdr;
-
-  slice = grpc_httpcli_format_post_request(&req, body_bytes, body_len);
-
-  GPR_ASSERT(0 == gpr_slice_str_cmp(slice,
-                                    "POST /index.html HTTP/1.0\r\n"
-                                    "Host: example.com\r\n"
-                                    "Connection: close\r\n"
-                                    "User-Agent: " GRPC_HTTPCLI_USER_AGENT
-                                    "\r\n"
-                                    "x-yz: abc\r\n"
-                                    "Content-Type: text/plain\r\n"
-                                    "Content-Length: 9\r\n"
-                                    "\r\n"
-                                    "fake body"));
-
-  gpr_slice_unref(slice);
-}
-
-static void test_format_post_request_no_body(void) {
-  grpc_httpcli_header hdr = {"x-yz", "abc"};
-  grpc_httpcli_request req;
-  gpr_slice slice;
-
-  memset(&req, 0, sizeof(req));
-  req.host = "example.com";
-  req.path = "/index.html";
-  req.hdr_count = 1;
-  req.hdrs = &hdr;
-
-  slice = grpc_httpcli_format_post_request(&req, NULL, 0);
-
-  GPR_ASSERT(0 == gpr_slice_str_cmp(slice,
-                                    "POST /index.html HTTP/1.0\r\n"
-                                    "Host: example.com\r\n"
-                                    "Connection: close\r\n"
-                                    "User-Agent: " GRPC_HTTPCLI_USER_AGENT
-                                    "\r\n"
-                                    "x-yz: abc\r\n"
-                                    "\r\n"));
-
-  gpr_slice_unref(slice);
-}
-
-static void test_format_post_request_content_type_override(void) {
-  grpc_httpcli_header hdrs[2];
-  grpc_httpcli_request req;
-  gpr_slice slice;
-  char body_bytes[] = "fake%20body";
-  size_t body_len = 11;
-
-  hdrs[0].key = "x-yz";
-  hdrs[0].value = "abc";
-  hdrs[1].key = "Content-Type";
-  hdrs[1].value = "application/x-www-form-urlencoded";
-  memset(&req, 0, sizeof(req));
-  req.host = "example.com";
-  req.path = "/index.html";
-  req.hdr_count = 2;
-  req.hdrs = hdrs;
-
-  slice = grpc_httpcli_format_post_request(&req, body_bytes, body_len);
-
-  GPR_ASSERT(0 == gpr_slice_str_cmp(
-                      slice,
-                      "POST /index.html HTTP/1.0\r\n"
-                      "Host: example.com\r\n"
-                      "Connection: close\r\n"
-                      "User-Agent: " GRPC_HTTPCLI_USER_AGENT
-                      "\r\n"
-                      "x-yz: abc\r\n"
-                      "Content-Type: application/x-www-form-urlencoded\r\n"
-                      "Content-Length: 11\r\n"
-                      "\r\n"
-                      "fake%20body"));
-
-  gpr_slice_unref(slice);
-}
-
-int main(int argc, char **argv) {
-  grpc_test_init(argc, argv);
-
-  test_format_get_request();
-  test_format_post_request();
-  test_format_post_request_no_body();
-  test_format_post_request_content_type_override();
-
-  return 0;
-}
diff --git a/test/core/httpcli/httpcli_test.c b/test/core/httpcli/httpcli_test.c
deleted file mode 100644
index da14633..0000000
--- a/test/core/httpcli/httpcli_test.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/httpcli/httpcli.h"
-
-#include <string.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/subprocess.h>
-#include <grpc/support/sync.h>
-#include "src/core/iomgr/iomgr.h"
-#include "test/core/util/port.h"
-#include "test/core/util/test_config.h"
-
-static int g_done = 0;
-static grpc_httpcli_context g_context;
-static gpr_mu *g_mu;
-static grpc_pollset *g_pollset;
-
-static gpr_timespec n_seconds_time(int seconds) {
-  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(seconds);
-}
-
-static void on_finish(grpc_exec_ctx *exec_ctx, void *arg,
-                      const grpc_httpcli_response *response) {
-  const char *expect =
-      "<html><head><title>Hello world!</title></head>"
-      "<body><p>This is a test</p></body></html>";
-  GPR_ASSERT(arg == (void *)42);
-  GPR_ASSERT(response);
-  GPR_ASSERT(response->status == 200);
-  GPR_ASSERT(response->body_length == strlen(expect));
-  GPR_ASSERT(0 == memcmp(expect, response->body, response->body_length));
-  gpr_mu_lock(g_mu);
-  g_done = 1;
-  grpc_pollset_kick(g_pollset, NULL);
-  gpr_mu_unlock(g_mu);
-}
-
-static void test_get(int port) {
-  grpc_httpcli_request req;
-  char *host;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  g_done = 0;
-  gpr_log(GPR_INFO, "test_get");
-
-  gpr_asprintf(&host, "localhost:%d", port);
-  gpr_log(GPR_INFO, "requesting from %s", host);
-
-  memset(&req, 0, sizeof(req));
-  req.host = host;
-  req.path = "/get";
-  req.handshaker = &grpc_httpcli_plaintext;
-
-  grpc_httpcli_get(&exec_ctx, &g_context, g_pollset, &req, n_seconds_time(15),
-                   on_finish, (void *)42);
-  gpr_mu_lock(g_mu);
-  while (!g_done) {
-    grpc_pollset_worker *worker = NULL;
-    grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                      gpr_now(GPR_CLOCK_MONOTONIC), n_seconds_time(20));
-    gpr_mu_unlock(g_mu);
-    grpc_exec_ctx_finish(&exec_ctx);
-    gpr_mu_lock(g_mu);
-  }
-  gpr_mu_unlock(g_mu);
-  gpr_free(host);
-}
-
-static void test_post(int port) {
-  grpc_httpcli_request req;
-  char *host;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  g_done = 0;
-  gpr_log(GPR_INFO, "test_post");
-
-  gpr_asprintf(&host, "localhost:%d", port);
-  gpr_log(GPR_INFO, "posting to %s", host);
-
-  memset(&req, 0, sizeof(req));
-  req.host = host;
-  req.path = "/post";
-  req.handshaker = &grpc_httpcli_plaintext;
-
-  grpc_httpcli_post(&exec_ctx, &g_context, g_pollset, &req, "hello", 5,
-                    n_seconds_time(15), on_finish, (void *)42);
-  gpr_mu_lock(g_mu);
-  while (!g_done) {
-    grpc_pollset_worker *worker = NULL;
-    grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                      gpr_now(GPR_CLOCK_MONOTONIC), n_seconds_time(20));
-    gpr_mu_unlock(g_mu);
-    grpc_exec_ctx_finish(&exec_ctx);
-    gpr_mu_lock(g_mu);
-  }
-  gpr_mu_unlock(g_mu);
-  gpr_free(host);
-}
-
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
-  grpc_pollset_destroy(p);
-}
-
-int main(int argc, char **argv) {
-  grpc_closure destroyed;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  gpr_subprocess *server;
-  char *me = argv[0];
-  char *lslash = strrchr(me, '/');
-  char *args[4];
-  int port = grpc_pick_unused_port_or_die();
-
-  GPR_ASSERT(argc <= 2);
-  if (argc == 2) {
-    args[0] = gpr_strdup(argv[1]);
-  } else {
-    /* figure out where we are */
-    char *root;
-    if (lslash) {
-      root = gpr_malloc((size_t)(lslash - me + 1));
-      memcpy(root, me, (size_t)(lslash - me));
-      root[lslash - me] = 0;
-    } else {
-      root = gpr_strdup(".");
-    }
-    gpr_asprintf(&args[0], "%s/../../test/core/httpcli/test_server.py", root);
-    gpr_free(root);
-  }
-
-  /* start the server */
-  args[1] = "--port";
-  gpr_asprintf(&args[2], "%d", port);
-  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_CLOCK_REALTIME),
-                               gpr_time_from_seconds(5, GPR_TIMESPAN)));
-
-  grpc_test_init(argc, argv);
-  grpc_init();
-  grpc_httpcli_context_init(&g_context);
-  g_pollset = gpr_malloc(grpc_pollset_size());
-  grpc_pollset_init(g_pollset, &g_mu);
-
-  test_get(port);
-  test_post(port);
-
-  grpc_httpcli_context_destroy(&g_context);
-  grpc_closure_init(&destroyed, destroy_pollset, g_pollset);
-  grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
-  grpc_exec_ctx_finish(&exec_ctx);
-  grpc_shutdown();
-
-  gpr_free(g_pollset);
-
-  gpr_subprocess_destroy(server);
-
-  return 0;
-}
diff --git a/test/core/httpcli/httpscli_test.c b/test/core/httpcli/httpscli_test.c
deleted file mode 100644
index 7f765bc..0000000
--- a/test/core/httpcli/httpscli_test.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/httpcli/httpcli.h"
-
-#include <string.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/subprocess.h>
-#include <grpc/support/sync.h>
-#include "src/core/iomgr/iomgr.h"
-#include "test/core/util/port.h"
-#include "test/core/util/test_config.h"
-
-static int g_done = 0;
-static grpc_httpcli_context g_context;
-static gpr_mu *g_mu;
-static grpc_pollset *g_pollset;
-
-static gpr_timespec n_seconds_time(int seconds) {
-  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(seconds);
-}
-
-static void on_finish(grpc_exec_ctx *exec_ctx, void *arg,
-                      const grpc_httpcli_response *response) {
-  const char *expect =
-      "<html><head><title>Hello world!</title></head>"
-      "<body><p>This is a test</p></body></html>";
-  GPR_ASSERT(arg == (void *)42);
-  GPR_ASSERT(response);
-  GPR_ASSERT(response->status == 200);
-  GPR_ASSERT(response->body_length == strlen(expect));
-  GPR_ASSERT(0 == memcmp(expect, response->body, response->body_length));
-  gpr_mu_lock(g_mu);
-  g_done = 1;
-  grpc_pollset_kick(g_pollset, NULL);
-  gpr_mu_unlock(g_mu);
-}
-
-static void test_get(int port) {
-  grpc_httpcli_request req;
-  char *host;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  g_done = 0;
-  gpr_log(GPR_INFO, "test_get");
-
-  gpr_asprintf(&host, "localhost:%d", port);
-  gpr_log(GPR_INFO, "requesting from %s", host);
-
-  memset(&req, 0, sizeof(req));
-  req.host = host;
-  req.ssl_host_override = "foo.test.google.fr";
-  req.path = "/get";
-  req.handshaker = &grpc_httpcli_ssl;
-
-  grpc_httpcli_get(&exec_ctx, &g_context, g_pollset, &req, n_seconds_time(15),
-                   on_finish, (void *)42);
-  gpr_mu_lock(g_mu);
-  while (!g_done) {
-    grpc_pollset_worker *worker = NULL;
-    grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                      gpr_now(GPR_CLOCK_MONOTONIC), n_seconds_time(20));
-    gpr_mu_unlock(g_mu);
-    grpc_exec_ctx_finish(&exec_ctx);
-    gpr_mu_lock(g_mu);
-  }
-  gpr_mu_unlock(g_mu);
-  gpr_free(host);
-}
-
-static void test_post(int port) {
-  grpc_httpcli_request req;
-  char *host;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
-  g_done = 0;
-  gpr_log(GPR_INFO, "test_post");
-
-  gpr_asprintf(&host, "localhost:%d", port);
-  gpr_log(GPR_INFO, "posting to %s", host);
-
-  memset(&req, 0, sizeof(req));
-  req.host = host;
-  req.ssl_host_override = "foo.test.google.fr";
-  req.path = "/post";
-  req.handshaker = &grpc_httpcli_ssl;
-
-  grpc_httpcli_post(&exec_ctx, &g_context, g_pollset, &req, "hello", 5,
-                    n_seconds_time(15), on_finish, (void *)42);
-  gpr_mu_lock(g_mu);
-  while (!g_done) {
-    grpc_pollset_worker *worker = NULL;
-    grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                      gpr_now(GPR_CLOCK_MONOTONIC), n_seconds_time(20));
-    gpr_mu_unlock(g_mu);
-    grpc_exec_ctx_finish(&exec_ctx);
-    gpr_mu_lock(g_mu);
-  }
-  gpr_mu_unlock(g_mu);
-  gpr_free(host);
-}
-
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
-  grpc_pollset_destroy(p);
-}
-
-int main(int argc, char **argv) {
-  grpc_closure destroyed;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  gpr_subprocess *server;
-  char *me = argv[0];
-  char *lslash = strrchr(me, '/');
-  char *args[5];
-  int port = grpc_pick_unused_port_or_die();
-
-  GPR_ASSERT(argc <= 2);
-  if (argc == 2) {
-    args[0] = gpr_strdup(argv[1]);
-  } else {
-    /* figure out where we are */
-    char *root;
-    if (lslash) {
-      root = gpr_malloc((size_t)(lslash - me + 1));
-      memcpy(root, me, (size_t)(lslash - me));
-      root[lslash - me] = 0;
-    } else {
-      root = gpr_strdup(".");
-    }
-    gpr_asprintf(&args[0], "%s/../../test/core/httpcli/test_server.py", root);
-    gpr_free(root);
-  }
-
-  /* start the server */
-  args[1] = "--port";
-  gpr_asprintf(&args[2], "%d", port);
-  args[3] = "--ssl";
-  server = gpr_subprocess_create(4, (const char **)args);
-  GPR_ASSERT(server);
-  gpr_free(args[0]);
-  gpr_free(args[2]);
-
-  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                               gpr_time_from_seconds(5, GPR_TIMESPAN)));
-
-  grpc_test_init(argc, argv);
-  grpc_init();
-  grpc_httpcli_context_init(&g_context);
-  g_pollset = gpr_malloc(grpc_pollset_size());
-  grpc_pollset_init(g_pollset, &g_mu);
-
-  test_get(port);
-  test_post(port);
-
-  grpc_httpcli_context_destroy(&g_context);
-  grpc_closure_init(&destroyed, destroy_pollset, g_pollset);
-  grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
-  grpc_exec_ctx_finish(&exec_ctx);
-  grpc_shutdown();
-
-  gpr_free(g_pollset);
-
-  gpr_subprocess_destroy(server);
-
-  return 0;
-}
diff --git a/test/core/httpcli/parser_test.c b/test/core/httpcli/parser_test.c
deleted file mode 100644
index a26ddd2..0000000
--- a/test/core/httpcli/parser_test.c
+++ /dev/null
@@ -1,171 +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/httpcli/parser.h"
-
-#include <stdarg.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 "test/core/util/slice_splitter.h"
-#include "test/core/util/test_config.h"
-
-static void test_succeeds(grpc_slice_split_mode split_mode, char *response,
-                          int expect_status, char *expect_body, ...) {
-  grpc_httpcli_parser parser;
-  gpr_slice input_slice = gpr_slice_from_copied_string(response);
-  size_t num_slices;
-  size_t i;
-  gpr_slice *slices;
-  va_list args;
-
-  grpc_split_slices(split_mode, &input_slice, 1, &slices, &num_slices);
-  gpr_slice_unref(input_slice);
-
-  grpc_httpcli_parser_init(&parser);
-
-  for (i = 0; i < num_slices; i++) {
-    GPR_ASSERT(grpc_httpcli_parser_parse(&parser, slices[i]));
-    gpr_slice_unref(slices[i]);
-  }
-  GPR_ASSERT(grpc_httpcli_parser_eof(&parser));
-
-  GPR_ASSERT(expect_status == parser.r.status);
-  if (expect_body != NULL) {
-    GPR_ASSERT(strlen(expect_body) == parser.r.body_length);
-    GPR_ASSERT(0 == memcmp(expect_body, parser.r.body, parser.r.body_length));
-  } else {
-    GPR_ASSERT(parser.r.body_length == 0);
-  }
-
-  va_start(args, expect_body);
-  i = 0;
-  for (;;) {
-    char *expect_key;
-    char *expect_value;
-    expect_key = va_arg(args, char *);
-    if (!expect_key) break;
-    GPR_ASSERT(i < parser.r.hdr_count);
-    expect_value = va_arg(args, char *);
-    GPR_ASSERT(expect_value);
-    GPR_ASSERT(0 == strcmp(expect_key, parser.r.hdrs[i].key));
-    GPR_ASSERT(0 == strcmp(expect_value, parser.r.hdrs[i].value));
-    i++;
-  }
-  va_end(args);
-  GPR_ASSERT(i == parser.r.hdr_count);
-
-  grpc_httpcli_parser_destroy(&parser);
-  gpr_free(slices);
-}
-
-static void test_fails(grpc_slice_split_mode split_mode, char *response) {
-  grpc_httpcli_parser parser;
-  gpr_slice input_slice = gpr_slice_from_copied_string(response);
-  size_t num_slices;
-  size_t i;
-  gpr_slice *slices;
-  int done = 0;
-
-  grpc_split_slices(split_mode, &input_slice, 1, &slices, &num_slices);
-  gpr_slice_unref(input_slice);
-
-  grpc_httpcli_parser_init(&parser);
-
-  for (i = 0; i < num_slices; i++) {
-    if (!done && !grpc_httpcli_parser_parse(&parser, slices[i])) {
-      done = 1;
-    }
-    gpr_slice_unref(slices[i]);
-  }
-  if (!done && !grpc_httpcli_parser_eof(&parser)) {
-    done = 1;
-  }
-  GPR_ASSERT(done);
-
-  grpc_httpcli_parser_destroy(&parser);
-  gpr_free(slices);
-}
-
-int main(int argc, char **argv) {
-  size_t i;
-  const grpc_slice_split_mode split_modes[] = {GRPC_SLICE_SPLIT_IDENTITY,
-                                               GRPC_SLICE_SPLIT_ONE_BYTE};
-  char *tmp1, *tmp2;
-
-  grpc_test_init(argc, argv);
-
-  for (i = 0; i < GPR_ARRAY_SIZE(split_modes); i++) {
-    test_succeeds(split_modes[i],
-                  "HTTP/1.0 200 OK\r\n"
-                  "xyz: abc\r\n"
-                  "\r\n"
-                  "hello world!",
-                  200, "hello world!", "xyz", "abc", NULL);
-    test_succeeds(split_modes[i],
-                  "HTTP/1.0 404 Not Found\r\n"
-                  "\r\n",
-                  404, NULL, NULL);
-    test_succeeds(split_modes[i],
-                  "HTTP/1.1 200 OK\r\n"
-                  "xyz: abc\r\n"
-                  "\r\n"
-                  "hello world!",
-                  200, "hello world!", "xyz", "abc", NULL);
-    test_fails(split_modes[i], "HTTP/1.0\r\n");
-    test_fails(split_modes[i], "HTTP/1.2\r\n");
-    test_fails(split_modes[i], "HTTP/1.0 000 XYX\r\n");
-    test_fails(split_modes[i], "HTTP/1.0 200 OK\n");
-    test_fails(split_modes[i], "HTTP/1.0 200 OK\r\n");
-    test_fails(split_modes[i], "HTTP/1.0 200 OK\r\nFoo x\r\n");
-    test_fails(split_modes[i],
-               "HTTP/1.0 200 OK\r\n"
-               "xyz: abc\r\n"
-               "  def\r\n"
-               "\r\n"
-               "hello world!");
-
-    tmp1 = gpr_malloc(2 * GRPC_HTTPCLI_MAX_HEADER_LENGTH);
-    memset(tmp1, 'a', 2 * GRPC_HTTPCLI_MAX_HEADER_LENGTH - 1);
-    tmp1[2 * GRPC_HTTPCLI_MAX_HEADER_LENGTH - 1] = 0;
-    gpr_asprintf(&tmp2, "HTTP/1.0 200 OK\r\nxyz: %s\r\n\r\n", tmp1);
-    test_fails(split_modes[i], tmp2);
-    gpr_free(tmp1);
-    gpr_free(tmp2);
-  }
-
-  return 0;
-}
diff --git a/test/core/httpcli/test_server.py b/test/core/httpcli/test_server.py
deleted file mode 100755
index dbbf5ce..0000000
--- a/test/core/httpcli/test_server.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/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.
-
-"""Server for httpcli_test"""
-
-import argparse
-import BaseHTTPServer
-import os
-import ssl
-import sys
-
-_PEM = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../../..', 'src/core/tsi/test_creds/server1.pem'))
-_KEY = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../../..', 'src/core/tsi/test_creds/server1.key'))
-print _PEM
-open(_PEM).close()
-
-argp = argparse.ArgumentParser(description='Server for httpcli_test')
-argp.add_argument('-p', '--port', default=10080, type=int)
-argp.add_argument('-s', '--ssl', default=False, action='store_true')
-args = argp.parse_args()
-
-print 'server running on port %d' % args.port
-
-class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
-	def good(self):
-		self.send_response(200)
-		self.send_header('Content-Type', 'text/html')
-		self.end_headers()
-		self.wfile.write('<html><head><title>Hello world!</title></head>')
-		self.wfile.write('<body><p>This is a test</p></body></html>')
-
-	def do_GET(self):
-		if self.path == '/get':
-			self.good()
-
-	def do_POST(self):
-		content = self.rfile.read(int(self.headers.getheader('content-length')))
-		if self.path == '/post' and content == 'hello':
-			self.good()
-
-httpd = BaseHTTPServer.HTTPServer(('localhost', args.port), Handler)
-if args.ssl:
-	httpd.socket = ssl.wrap_socket(httpd.socket, certfile=_PEM, keyfile=_KEY, server_side=True)
-httpd.serve_forever()
diff --git a/test/core/iomgr/endpoint_pair_test.c b/test/core/iomgr/endpoint_pair_test.c
index c3a9108..a91a9a7 100644
--- a/test/core/iomgr/endpoint_pair_test.c
+++ b/test/core/iomgr/endpoint_pair_test.c
@@ -31,14 +31,14 @@
  *
  */
 
-#include "src/core/iomgr/tcp_posix.h"
+#include "src/core/lib/iomgr/tcp_posix.h"
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
-#include "src/core/iomgr/endpoint_pair.h"
+#include "src/core/lib/iomgr/endpoint_pair.h"
 #include "test/core/iomgr/endpoint_tests.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/iomgr/endpoint_tests.h b/test/core/iomgr/endpoint_tests.h
index 8ea47e3..c7542a0 100644
--- a/test/core/iomgr/endpoint_tests.h
+++ b/test/core/iomgr/endpoint_tests.h
@@ -36,7 +36,7 @@
 
 #include <sys/types.h>
 
-#include "src/core/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/endpoint.h"
 
 typedef struct grpc_endpoint_test_config grpc_endpoint_test_config;
 typedef struct grpc_endpoint_test_fixture grpc_endpoint_test_fixture;
diff --git a/test/core/iomgr/fd_conservation_posix_test.c b/test/core/iomgr/fd_conservation_posix_test.c
index 401bf70..aae94e7 100644
--- a/test/core/iomgr/fd_conservation_posix_test.c
+++ b/test/core/iomgr/fd_conservation_posix_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,9 +35,9 @@
 
 #include <grpc/support/log.h>
 
+#include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/test_config.h"
-#include "src/core/iomgr/endpoint_pair.h"
-#include "src/core/iomgr/iomgr.h"
 
 int main(int argc, char **argv) {
   int i;
diff --git a/test/core/iomgr/fd_posix_test.c b/test/core/iomgr/fd_posix_test.c
index 99689eb..203e1e3 100644
--- a/test/core/iomgr/fd_posix_test.c
+++ b/test/core/iomgr/fd_posix_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/iomgr/fd_posix.h"
+#include "src/core/lib/iomgr/fd_posix.h"
 
 #include <ctype.h>
 #include <errno.h>
@@ -50,7 +50,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
-#include "src/core/iomgr/pollset_posix.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
 #include "test/core/util/test_config.h"
 
 static gpr_mu *g_mu;
diff --git a/test/core/iomgr/resolve_address_test.c b/test/core/iomgr/resolve_address_test.c
index 56ce091..7aec91a 100644
--- a/test/core/iomgr/resolve_address_test.c
+++ b/test/core/iomgr/resolve_address_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,11 +31,11 @@
  *
  */
 
-#include "src/core/iomgr/resolve_address.h"
-#include "src/core/iomgr/executor.h"
+#include "src/core/lib/iomgr/resolve_address.h"
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
+#include "src/core/lib/iomgr/executor.h"
 #include "test/core/util/test_config.h"
 
 static gpr_timespec test_deadline(void) {
diff --git a/test/core/iomgr/sockaddr_utils_test.c b/test/core/iomgr/sockaddr_utils_test.c
index a7b57c1..19bee9a 100644
--- a/test/core/iomgr/sockaddr_utils_test.c
+++ b/test/core/iomgr/sockaddr_utils_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
 
 #include <errno.h>
 #include <string.h>
diff --git a/test/core/iomgr/socket_utils_test.c b/test/core/iomgr/socket_utils_test.c
index 58c3fbc..8238a9c 100644
--- a/test/core/iomgr/socket_utils_test.c
+++ b/test/core/iomgr/socket_utils_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@
  */
 
 #include <grpc/support/port_platform.h>
-#include "src/core/iomgr/socket_utils_posix.h"
+#include "src/core/lib/iomgr/socket_utils_posix.h"
 
 #include <errno.h>
 #include <string.h>
diff --git a/test/core/iomgr/tcp_client_posix_test.c b/test/core/iomgr/tcp_client_posix_test.c
index 746dfd8..d798bf2 100644
--- a/test/core/iomgr/tcp_client_posix_test.c
+++ b/test/core/iomgr/tcp_client_posix_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/iomgr/tcp_client.h"
+#include "src/core/lib/iomgr/tcp_client.h"
 
 #include <errno.h>
 #include <netinet/in.h>
@@ -44,9 +44,9 @@
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/iomgr/socket_utils_posix.h"
-#include "src/core/iomgr/timer.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+#include "src/core/lib/iomgr/timer.h"
 #include "test/core/util/test_config.h"
 
 static grpc_pollset_set *g_pollset_set;
diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index 4351642..79f18c6 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/iomgr/tcp_posix.h"
+#include "src/core/lib/iomgr/tcp_posix.h"
 
 #include <errno.h>
 #include <fcntl.h>
diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c
index 7933468..cde147d 100644
--- a/test/core/iomgr/tcp_server_posix_test.c
+++ b/test/core/iomgr/tcp_server_posix_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/iomgr/tcp_server.h"
+#include "src/core/lib/iomgr/tcp_server.h"
 
 #include <errno.h>
 #include <netinet/in.h>
@@ -45,8 +45,8 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/iomgr/time_averaged_stats_test.c b/test/core/iomgr/time_averaged_stats_test.c
index cb006d1..a49d899 100644
--- a/test/core/iomgr/time_averaged_stats_test.c
+++ b/test/core/iomgr/time_averaged_stats_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/iomgr/time_averaged_stats.h"
+#include "src/core/lib/iomgr/time_averaged_stats.h"
 
 #include <math.h>
 
diff --git a/test/core/iomgr/timer_heap_test.c b/test/core/iomgr/timer_heap_test.c
index cd34696..d230c83 100644
--- a/test/core/iomgr/timer_heap_test.c
+++ b/test/core/iomgr/timer_heap_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/iomgr/timer_heap.h"
+#include "src/core/lib/iomgr/timer_heap.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -177,11 +177,12 @@
 
   grpc_timer_heap pq;
 
-  elem_struct elems[1000];
+  static const size_t elems_size = 1000;
+  elem_struct *elems = gpr_malloc(elems_size * sizeof(elem_struct));
   size_t num_inserted = 0;
 
   grpc_timer_heap_init(&pq);
-  memset(elems, 0, sizeof(elems));
+  memset(elems, 0, elems_size);
 
   for (size_t round = 0; round < 10000; round++) {
     int r = rand() % 1000;
@@ -209,7 +210,7 @@
       if (num_inserted > 0) {
         grpc_timer *top = grpc_timer_heap_top(&pq);
         grpc_timer_heap_pop(&pq);
-        for (size_t i = 0; i < GPR_ARRAY_SIZE(elems); i++) {
+        for (size_t i = 0; i < elems_size; i++) {
           if (top == &elems[i].elem) {
             GPR_ASSERT(elems[i].inserted);
             elems[i].inserted = false;
@@ -222,7 +223,7 @@
 
     if (num_inserted) {
       gpr_timespec *min_deadline = NULL;
-      for (size_t i = 0; i < GPR_ARRAY_SIZE(elems); i++) {
+      for (size_t i = 0; i < elems_size; i++) {
         if (elems[i].inserted) {
           if (min_deadline == NULL) {
             min_deadline = &elems[i].elem.deadline;
@@ -239,6 +240,7 @@
   }
 
   grpc_timer_heap_destroy(&pq);
+  gpr_free(elems);
 }
 
 static void shrink_test(void) {
diff --git a/test/core/iomgr/timer_list_test.c b/test/core/iomgr/timer_list_test.c
index 7a21fdd..0333a75 100644
--- a/test/core/iomgr/timer_list_test.c
+++ b/test/core/iomgr/timer_list_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/iomgr/timer.h"
+#include "src/core/lib/iomgr/timer.h"
 
 #include <string.h>
 
@@ -81,9 +81,8 @@
   }
 
   GPR_ASSERT(!grpc_timer_check(
-                 &exec_ctx,
-                 gpr_time_add(start, gpr_time_from_millis(600, GPR_TIMESPAN)),
-                 NULL));
+      &exec_ctx, gpr_time_add(start, gpr_time_from_millis(600, GPR_TIMESPAN)),
+      NULL));
   grpc_exec_ctx_finish(&exec_ctx);
   for (i = 0; i < 30; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 10));
@@ -101,9 +100,8 @@
   }
 
   GPR_ASSERT(!grpc_timer_check(
-                 &exec_ctx,
-                 gpr_time_add(start, gpr_time_from_millis(1600, GPR_TIMESPAN)),
-                 NULL));
+      &exec_ctx, 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);
diff --git a/test/core/iomgr/udp_server_test.c b/test/core/iomgr/udp_server_test.c
index 2e253d8..0c55ef0 100644
--- a/test/core/iomgr/udp_server_test.c
+++ b/test/core/iomgr/udp_server_test.c
@@ -31,16 +31,18 @@
  *
  */
 
-#include "src/core/iomgr/udp_server.h"
-#include "src/core/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/udp_server.h"
+#include <grpc/grpc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
 #include "test/core/util/test_config.h"
 
-#include <sys/socket.h>
 #include <netinet/in.h>
 #include <string.h>
+#include <sys/socket.h>
 #include <unistd.h>
 
 #ifdef GRPC_NEED_UDP
@@ -48,6 +50,7 @@
 #define LOG_TEST(x) gpr_log(GPR_INFO, "%s", #x)
 
 static grpc_pollset g_pollset;
+static gpr_mu *g_mu;
 static int g_number_of_reads = 0;
 static int g_number_of_bytes_read = 0;
 
@@ -56,14 +59,14 @@
   char read_buffer[512];
   ssize_t byte_count;
 
-  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  gpr_mu_lock(g_mu);
   byte_count = recv(emfd->fd, read_buffer, sizeof(read_buffer), 0);
 
   g_number_of_reads++;
   g_number_of_bytes_read += (int)byte_count;
 
   grpc_pollset_kick(&g_pollset, NULL);
-  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+  gpr_mu_unlock(g_mu);
 }
 
 static void test_no_op(void) {
@@ -142,7 +145,7 @@
   pollsets[0] = &g_pollset;
   grpc_udp_server_start(&exec_ctx, s, pollsets, 1, NULL);
 
-  gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+  gpr_mu_lock(g_mu);
 
   for (i = 0; i < number_of_clients; i++) {
     deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
@@ -155,19 +158,19 @@
     GPR_ASSERT(5 == write(clifd, "hello", 5));
     while (g_number_of_reads == number_of_reads_before &&
            gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) > 0) {
-      grpc_pollset_worker worker;
+      grpc_pollset_worker *worker = NULL;
       grpc_pollset_work(&exec_ctx, &g_pollset, &worker,
                         gpr_now(GPR_CLOCK_MONOTONIC), deadline);
-      gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+      gpr_mu_unlock(g_mu);
       grpc_exec_ctx_finish(&exec_ctx);
-      gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
+      gpr_mu_lock(g_mu);
     }
     GPR_ASSERT(g_number_of_reads == number_of_reads_before + 1);
     close(clifd);
   }
   GPR_ASSERT(g_number_of_bytes_read == 5 * number_of_clients);
 
-  gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+  gpr_mu_unlock(g_mu);
 
   grpc_udp_server_destroy(&exec_ctx, s, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
@@ -181,8 +184,8 @@
   grpc_closure destroyed;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_test_init(argc, argv);
-  grpc_iomgr_init();
-  grpc_pollset_init(&g_pollset);
+  grpc_init();
+  grpc_pollset_init(&g_pollset, &g_mu);
 
   test_no_op();
   test_no_op_with_start();
diff --git a/test/core/iomgr/workqueue_test.c b/test/core/iomgr/workqueue_test.c
index 8a1faf6..2d9b5d0 100644
--- a/test/core/iomgr/workqueue_test.c
+++ b/test/core/iomgr/workqueue_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/iomgr/workqueue.h"
+#include "src/core/lib/iomgr/workqueue.h"
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
diff --git a/test/core/json/corpus/006d552e952c42b5340baaeb85c2cb80c81e78dd b/test/core/json/corpus/006d552e952c42b5340baaeb85c2cb80c81e78dd
new file mode 100644
index 0000000..762064c
--- /dev/null
+++ b/test/core/json/corpus/006d552e952c42b5340baaeb85c2cb80c81e78dd
@@ -0,0 +1 @@
+1e9
\ No newline at end of file
diff --git a/test/core/json/corpus/007eb985c44b6089a34995a7d9ebf349f1c2bf18 b/test/core/json/corpus/007eb985c44b6089a34995a7d9ebf349f1c2bf18
new file mode 100644
index 0000000..8affa52
--- /dev/null
+++ b/test/core/json/corpus/007eb985c44b6089a34995a7d9ebf349f1c2bf18
@@ -0,0 +1 @@
+{}3[
\ No newline at end of file
diff --git a/test/core/json/corpus/03b74a08f23734691512cb12d0b38d189a8df905 b/test/core/json/corpus/03b74a08f23734691512cb12d0b38d189a8df905
new file mode 100644
index 0000000..7ffe3f3
--- /dev/null
+++ b/test/core/json/corpus/03b74a08f23734691512cb12d0b38d189a8df905
@@ -0,0 +1 @@
+0.6991 
\ No newline at end of file
diff --git a/test/core/json/corpus/0495693af07325fb0d52eafd2d4c4d802c6457c6 b/test/core/json/corpus/0495693af07325fb0d52eafd2d4c4d802c6457c6
new file mode 100644
index 0000000..f7752ee
--- /dev/null
+++ b/test/core/json/corpus/0495693af07325fb0d52eafd2d4c4d802c6457c6
@@ -0,0 +1 @@
+0.83282
\ No newline at end of file
diff --git a/test/core/json/corpus/05454ab015cf74e9c3e8574d995517e05dd56751 b/test/core/json/corpus/05454ab015cf74e9c3e8574d995517e05dd56751
new file mode 100644
index 0000000..8377c55
--- /dev/null
+++ b/test/core/json/corpus/05454ab015cf74e9c3e8574d995517e05dd56751
@@ -0,0 +1 @@
+21.595»
\ No newline at end of file
diff --git a/test/core/json/corpus/0716d9708d321ffb6a00818614779e779925365c b/test/core/json/corpus/0716d9708d321ffb6a00818614779e779925365c
new file mode 100644
index 0000000..8e2afd3
--- /dev/null
+++ b/test/core/json/corpus/0716d9708d321ffb6a00818614779e779925365c
@@ -0,0 +1 @@
+17
\ No newline at end of file
diff --git a/test/core/json/corpus/0a9b3522a8e711e3bd53e2c2eb9d28b34a003acc b/test/core/json/corpus/0a9b3522a8e711e3bd53e2c2eb9d28b34a003acc
new file mode 100644
index 0000000..d249eb2
--- /dev/null
+++ b/test/core/json/corpus/0a9b3522a8e711e3bd53e2c2eb9d28b34a003acc
@@ -0,0 +1 @@
+[2.1e	"ˆÃ796;]3*
\ No newline at end of file
diff --git a/test/core/json/corpus/0ade7c2cf97f75d009975f4d720d1fa6c19f4897 b/test/core/json/corpus/0ade7c2cf97f75d009975f4d720d1fa6c19f4897
new file mode 100644
index 0000000..f11c82a
--- /dev/null
+++ b/test/core/json/corpus/0ade7c2cf97f75d009975f4d720d1fa6c19f4897
@@ -0,0 +1 @@
+9
\ No newline at end of file
diff --git a/test/core/json/corpus/0b1fcf0ac07e1e50cfe27316c7e1c8cc997f1318 b/test/core/json/corpus/0b1fcf0ac07e1e50cfe27316c7e1c8cc997f1318
new file mode 100644
index 0000000..b66d61b
--- /dev/null
+++ b/test/core/json/corpus/0b1fcf0ac07e1e50cfe27316c7e1c8cc997f1318
@@ -0,0 +1 @@
+{"'5E885,!\u065E{
\ No newline at end of file
diff --git a/test/core/json/corpus/0bc13548356d08009703d35e9c8d74397367bdfb b/test/core/json/corpus/0bc13548356d08009703d35e9c8d74397367bdfb
new file mode 100644
index 0000000..2c23914
--- /dev/null
+++ b/test/core/json/corpus/0bc13548356d08009703d35e9c8d74397367bdfb
@@ -0,0 +1 @@
+nu,*:
\ No newline at end of file
diff --git a/test/core/json/corpus/0ea9a160c57f2c705dce037196e360bf9be739c5 b/test/core/json/corpus/0ea9a160c57f2c705dce037196e360bf9be739c5
new file mode 100644
index 0000000..f92893d
--- /dev/null
+++ b/test/core/json/corpus/0ea9a160c57f2c705dce037196e360bf9be739c5
@@ -0,0 +1 @@
+f'
\ No newline at end of file
diff --git a/test/core/json/corpus/0f20d9c46991c0e97419e2cca07c7389f1d6bdf8 b/test/core/json/corpus/0f20d9c46991c0e97419e2cca07c7389f1d6bdf8
new file mode 100644
index 0000000..05a6fb2
--- /dev/null
+++ b/test/core/json/corpus/0f20d9c46991c0e97419e2cca07c7389f1d6bdf8
@@ -0,0 +1 @@
+1e	"ˆÃ9
\ No newline at end of file
diff --git a/test/core/json/corpus/0f2e2e6346f70c419300b661251754d50f7ca8ea b/test/core/json/corpus/0f2e2e6346f70c419300b661251754d50f7ca8ea
new file mode 100644
index 0000000..e429f50
--- /dev/null
+++ b/test/core/json/corpus/0f2e2e6346f70c419300b661251754d50f7ca8ea
@@ -0,0 +1 @@
+[2.1982
\ No newline at end of file
diff --git a/test/core/json/corpus/108b310facc1a193833fc2971fd83081f775ea0c b/test/core/json/corpus/108b310facc1a193833fc2971fd83081f775ea0c
new file mode 100644
index 0000000..45be455
--- /dev/null
+++ b/test/core/json/corpus/108b310facc1a193833fc2971fd83081f775ea0c
@@ -0,0 +1 @@
+false)
\ No newline at end of file
diff --git a/test/core/json/corpus/108e5bcd69b19ad0df743641085163b84f376fe8 b/test/core/json/corpus/108e5bcd69b19ad0df743641085163b84f376fe8
new file mode 100644
index 0000000..0973cbb
--- /dev/null
+++ b/test/core/json/corpus/108e5bcd69b19ad0df743641085163b84f376fe8
@@ -0,0 +1,2 @@
+[{
+"ˆÃ" "ˆÃ"
\ No newline at end of file
diff --git a/test/core/json/corpus/10e3ecd5624465020fdf0662a67e0f0885536cae b/test/core/json/corpus/10e3ecd5624465020fdf0662a67e0f0885536cae
new file mode 100644
index 0000000..5230607
--- /dev/null
+++ b/test/core/json/corpus/10e3ecd5624465020fdf0662a67e0f0885536cae
@@ -0,0 +1 @@
+{"":0,(!Ó'(\'!)
\ No newline at end of file
diff --git a/test/core/json/corpus/113c8c97cbb0a2b6176d75eaa9ac9baaa7ccddcc b/test/core/json/corpus/113c8c97cbb0a2b6176d75eaa9ac9baaa7ccddcc
new file mode 100644
index 0000000..8f04034
--- /dev/null
+++ b/test/core/json/corpus/113c8c97cbb0a2b6176d75eaa9ac9baaa7ccddcc
@@ -0,0 +1 @@
+1¹
\ No newline at end of file
diff --git a/test/core/json/corpus/11479d936dd006410a5946b6081a94d573bf8efd b/test/core/json/corpus/11479d936dd006410a5946b6081a94d573bf8efd
new file mode 100644
index 0000000..58cf749
--- /dev/null
+++ b/test/core/json/corpus/11479d936dd006410a5946b6081a94d573bf8efd
@@ -0,0 +1 @@
+tr¹82 'A\E57;)
\ No newline at end of file
diff --git a/test/core/json/corpus/11aa091189b78d1cc35c7ff4907ac16a73aba547 b/test/core/json/corpus/11aa091189b78d1cc35c7ff4907ac16a73aba547
new file mode 100644
index 0000000..cb88820
--- /dev/null
+++ b/test/core/json/corpus/11aa091189b78d1cc35c7ff4907ac16a73aba547
@@ -0,0 +1 @@
+[9281.2;
\ No newline at end of file
diff --git a/test/core/json/corpus/1227907b2ee5a9492a890beed55332e4560834c8 b/test/core/json/corpus/1227907b2ee5a9492a890beed55332e4560834c8
new file mode 100644
index 0000000..fd35270
--- /dev/null
+++ b/test/core/json/corpus/1227907b2ee5a9492a890beed55332e4560834c8
@@ -0,0 +1 @@
+2}5
\ No newline at end of file
diff --git a/test/core/json/corpus/134d65130947ec69cf8df8483424b45e99cf04e3 b/test/core/json/corpus/134d65130947ec69cf8df8483424b45e99cf04e3
new file mode 100644
index 0000000..522a9be
--- /dev/null
+++ b/test/core/json/corpus/134d65130947ec69cf8df8483424b45e99cf04e3
@@ -0,0 +1 @@
+0.2995 
\ No newline at end of file
diff --git a/test/core/json/corpus/13584505caa892d94982a968bbc4391ebcfe0d06 b/test/core/json/corpus/13584505caa892d94982a968bbc4391ebcfe0d06
new file mode 100644
index 0000000..9fb628a
--- /dev/null
+++ b/test/core/json/corpus/13584505caa892d94982a968bbc4391ebcfe0d06
@@ -0,0 +1 @@
+{"',!\uA>Š
\ No newline at end of file
diff --git a/test/core/json/corpus/137f554ee0f6b903acb81ab4e1f98c11fe92b008 b/test/core/json/corpus/137f554ee0f6b903acb81ab4e1f98c11fe92b008
new file mode 100644
index 0000000..98232c6
--- /dev/null
+++ b/test/core/json/corpus/137f554ee0f6b903acb81ab4e1f98c11fe92b008
@@ -0,0 +1 @@
+{
diff --git a/test/core/json/corpus/1401ea03ec78b8f20dc7be952555004d7147f0f5 b/test/core/json/corpus/1401ea03ec78b8f20dc7be952555004d7147f0f5
new file mode 100644
index 0000000..595fe02
--- /dev/null
+++ b/test/core/json/corpus/1401ea03ec78b8f20dc7be952555004d7147f0f5
@@ -0,0 +1 @@
+"ˆÃ{)ˆ!
\ No newline at end of file
diff --git a/test/core/json/corpus/141d45a59b073aeec4443cd7bcf20f7833ddbc95 b/test/core/json/corpus/141d45a59b073aeec4443cd7bcf20f7833ddbc95
new file mode 100644
index 0000000..e2e68e8
--- /dev/null
+++ b/test/core/json/corpus/141d45a59b073aeec4443cd7bcf20f7833ddbc95
@@ -0,0 +1 @@
+"'',!\u658E{128031:;):ˆ)!Ã5*¾?'ʳ³!!*!à):!*à::)!9:\udbD86'
\ No newline at end of file
diff --git a/test/core/json/corpus/15c9c1284c27c8893559e15c9b2a50cbd5bbb56f b/test/core/json/corpus/15c9c1284c27c8893559e15c9b2a50cbd5bbb56f
new file mode 100644
index 0000000..21a9555
--- /dev/null
+++ b/test/core/json/corpus/15c9c1284c27c8893559e15c9b2a50cbd5bbb56f
@@ -0,0 +1 @@
+[2,"ˆÃ!{)!:",ˆÃ
\ No newline at end of file
diff --git a/test/core/json/corpus/15d1a6cda48ef569b368a0c4627435bc2c80a988 b/test/core/json/corpus/15d1a6cda48ef569b368a0c4627435bc2c80a988
new file mode 100644
index 0000000..8017a98
--- /dev/null
+++ b/test/core/json/corpus/15d1a6cda48ef569b368a0c4627435bc2c80a988
@@ -0,0 +1 @@
+	"ˆÃ "
\ No newline at end of file
diff --git a/test/core/json/corpus/17a29f2ac6df774585d7713091b299729738030c b/test/core/json/corpus/17a29f2ac6df774585d7713091b299729738030c
new file mode 100644
index 0000000..9402a603
--- /dev/null
+++ b/test/core/json/corpus/17a29f2ac6df774585d7713091b299729738030c
@@ -0,0 +1 @@
+[)
\ No newline at end of file
diff --git a/test/core/json/corpus/17b815f1f72cb64481bc40263e91ce063040f739 b/test/core/json/corpus/17b815f1f72cb64481bc40263e91ce063040f739
new file mode 100644
index 0000000..81b218e
--- /dev/null
+++ b/test/core/json/corpus/17b815f1f72cb64481bc40263e91ce063040f739
@@ -0,0 +1 @@
+[tr
\ No newline at end of file
diff --git a/test/core/json/corpus/182d57403d2c973a394055017d35b7621aa0aa05 b/test/core/json/corpus/182d57403d2c973a394055017d35b7621aa0aa05
new file mode 100644
index 0000000..f48f55e
--- /dev/null
+++ b/test/core/json/corpus/182d57403d2c973a394055017d35b7621aa0aa05
@@ -0,0 +1 @@
+null*:
\ No newline at end of file
diff --git a/test/core/json/corpus/190fbe2da448f6bdec0706c5301ad13363ae3ad9 b/test/core/json/corpus/190fbe2da448f6bdec0706c5301ad13363ae3ad9
new file mode 100644
index 0000000..37144c7
--- /dev/null
+++ b/test/core/json/corpus/190fbe2da448f6bdec0706c5301ad13363ae3ad9
@@ -0,0 +1 @@
+1e+2187560
\ No newline at end of file
diff --git a/test/core/json/corpus/1b045a24b8f1f1fd6e8234d5019952ee7713a8b7 b/test/core/json/corpus/1b045a24b8f1f1fd6e8234d5019952ee7713a8b7
new file mode 100644
index 0000000..04ac543
--- /dev/null
+++ b/test/core/json/corpus/1b045a24b8f1f1fd6e8234d5019952ee7713a8b7
@@ -0,0 +1 @@
+\5
\ No newline at end of file
diff --git a/test/core/json/corpus/1b6453892473a467d07372d45eb05abc2031647a b/test/core/json/corpus/1b6453892473a467d07372d45eb05abc2031647a
new file mode 100644
index 0000000..bf0d87a
--- /dev/null
+++ b/test/core/json/corpus/1b6453892473a467d07372d45eb05abc2031647a
@@ -0,0 +1 @@
+4
\ No newline at end of file
diff --git a/test/core/json/corpus/1c6463aa2dabcb4fadc8e5441d8b418535e768af b/test/core/json/corpus/1c6463aa2dabcb4fadc8e5441d8b418535e768af
new file mode 100644
index 0000000..7fa1b27
--- /dev/null
+++ b/test/core/json/corpus/1c6463aa2dabcb4fadc8e5441d8b418535e768af
@@ -0,0 +1 @@
+0{:ˆ)!Ã"*¾?'ʳ³!!*!à):!*à:::\udbD8ˆ)Ã!:{!`!?`¾¾!?'!*m,');…'`
\ No newline at end of file
diff --git a/test/core/json/corpus/1dea95b5050b766274ef80847505c0e4f47f3ebb b/test/core/json/corpus/1dea95b5050b766274ef80847505c0e4f47f3ebb
new file mode 100644
index 0000000..1237d77
--- /dev/null
+++ b/test/core/json/corpus/1dea95b5050b766274ef80847505c0e4f47f3ebb
@@ -0,0 +1 @@
+13e190560
\ No newline at end of file
diff --git a/test/core/json/corpus/1df0754d3e7970b3afe549b11ca128dcd0d4832b b/test/core/json/corpus/1df0754d3e7970b3afe549b11ca128dcd0d4832b
new file mode 100644
index 0000000..dd9df88
--- /dev/null
+++ b/test/core/json/corpus/1df0754d3e7970b3afe549b11ca128dcd0d4832b
@@ -0,0 +1 @@
+{"'5E885,!\u000E{
\ No newline at end of file
diff --git a/test/core/json/corpus/1dfe267b623b20cd97c6e8969d8b9148af9f4a2c b/test/core/json/corpus/1dfe267b623b20cd97c6e8969d8b9148af9f4a2c
new file mode 100644
index 0000000..7f010a2
--- /dev/null
+++ b/test/core/json/corpus/1dfe267b623b20cd97c6e8969d8b9148af9f4a2c
@@ -0,0 +1 @@
+6(0
\ No newline at end of file
diff --git a/test/core/json/corpus/1e5c2f367f02e47a8c160cda1cd9d91decbac441 b/test/core/json/corpus/1e5c2f367f02e47a8c160cda1cd9d91decbac441
new file mode 100644
index 0000000..8e2f0be
--- /dev/null
+++ b/test/core/json/corpus/1e5c2f367f02e47a8c160cda1cd9d91decbac441
@@ -0,0 +1 @@
+[
\ No newline at end of file
diff --git a/test/core/json/corpus/20efdba13ca7a3657d071b3d56997aa3b083068a b/test/core/json/corpus/20efdba13ca7a3657d071b3d56997aa3b083068a
new file mode 100644
index 0000000..5194be3
--- /dev/null
+++ b/test/core/json/corpus/20efdba13ca7a3657d071b3d56997aa3b083068a
@@ -0,0 +1 @@
+"ˆÃ{)!:*])Ã!:{"*¾?¾;?Xʳ³'!!Ê
\ No newline at end of file
diff --git a/test/core/json/corpus/215a956168f77421253e947c2436371d56aa7ea1 b/test/core/json/corpus/215a956168f77421253e947c2436371d56aa7ea1
new file mode 100644
index 0000000..a0aeede
--- /dev/null
+++ b/test/core/json/corpus/215a956168f77421253e947c2436371d56aa7ea1
@@ -0,0 +1 @@
+fa
\ No newline at end of file
diff --git a/test/core/json/corpus/2174b9ab6bf4f7c21fe1ed56957f1776ef611959 b/test/core/json/corpus/2174b9ab6bf4f7c21fe1ed56957f1776ef611959
new file mode 100644
index 0000000..ef32707
--- /dev/null
+++ b/test/core/json/corpus/2174b9ab6bf4f7c21fe1ed56957f1776ef611959
@@ -0,0 +1 @@
+13e5!01860
\ No newline at end of file
diff --git a/test/core/json/corpus/232f4bced4075545bb1469d5c2360f083ec7ec65 b/test/core/json/corpus/232f4bced4075545bb1469d5c2360f083ec7ec65
new file mode 100644
index 0000000..d4e4ebe
--- /dev/null
+++ b/test/core/json/corpus/232f4bced4075545bb1469d5c2360f083ec7ec65
@@ -0,0 +1 @@
+{"',!\u65E8850{2312;):ˆ)!Ã"*¾?'ʳ³!!*!à):!*à::8!9:\udbD86'
\ No newline at end of file
diff --git a/test/core/json/corpus/26aca41ee8f199e7c0c7cf31d979952571c53fc9 b/test/core/json/corpus/26aca41ee8f199e7c0c7cf31d979952571c53fc9
new file mode 100644
index 0000000..016fe56
--- /dev/null
+++ b/test/core/json/corpus/26aca41ee8f199e7c0c7cf31d979952571c53fc9
Binary files differ
diff --git a/test/core/json/corpus/27d84210636e9e83786be9e9b96b69f70b743b86 b/test/core/json/corpus/27d84210636e9e83786be9e9b96b69f70b743b86
new file mode 100644
index 0000000..701bd00
--- /dev/null
+++ b/test/core/json/corpus/27d84210636e9e83786be9e9b96b69f70b743b86
@@ -0,0 +1 @@
+{"',!\u'Š
\ No newline at end of file
diff --git a/test/core/json/corpus/27da426a5883662d19ea78f306d7a992be52f827 b/test/core/json/corpus/27da426a5883662d19ea78f306d7a992be52f827
new file mode 100644
index 0000000..2e7373e
--- /dev/null
+++ b/test/core/json/corpus/27da426a5883662d19ea78f306d7a992be52f827
@@ -0,0 +1,2 @@
+2

+P2÷
\ No newline at end of file
diff --git a/test/core/json/corpus/296dcda6f7e6979e68ddef7cbc1206a355084ad3 b/test/core/json/corpus/296dcda6f7e6979e68ddef7cbc1206a355084ad3
new file mode 100644
index 0000000..e510185
--- /dev/null
+++ b/test/core/json/corpus/296dcda6f7e6979e68ddef7cbc1206a355084ad3
@@ -0,0 +1 @@
+,ˆÃ""
\ No newline at end of file
diff --git a/test/core/json/corpus/29b08c03ca5a6851fa4604a984cb7ff44433a5a5 b/test/core/json/corpus/29b08c03ca5a6851fa4604a984cb7ff44433a5a5
new file mode 100644
index 0000000..60ec6c5
--- /dev/null
+++ b/test/core/json/corpus/29b08c03ca5a6851fa4604a984cb7ff44433a5a5
@@ -0,0 +1 @@
+3]5
\ No newline at end of file
diff --git a/test/core/json/corpus/2a3d964ec4527ad9f02129fcbf087b67a6ea6444 b/test/core/json/corpus/2a3d964ec4527ad9f02129fcbf087b67a6ea6444
new file mode 100644
index 0000000..e5e723f
--- /dev/null
+++ b/test/core/json/corpus/2a3d964ec4527ad9f02129fcbf087b67a6ea6444
@@ -0,0 +1 @@
+-w9'Á6
\ No newline at end of file
diff --git a/test/core/json/corpus/2b04974149815b143afb17af4388d751217e54ec b/test/core/json/corpus/2b04974149815b143afb17af4388d751217e54ec
new file mode 100644
index 0000000..880fb54
--- /dev/null
+++ b/test/core/json/corpus/2b04974149815b143afb17af4388d751217e54ec
@@ -0,0 +1 @@
+832E46;)
\ No newline at end of file
diff --git a/test/core/json/corpus/2b3b1ad952e3acb566e32a84e2d503acde13eb53 b/test/core/json/corpus/2b3b1ad952e3acb566e32a84e2d503acde13eb53
new file mode 100644
index 0000000..0f5e2da
--- /dev/null
+++ b/test/core/json/corpus/2b3b1ad952e3acb566e32a84e2d503acde13eb53
@@ -0,0 +1 @@
+31e8¤560
\ No newline at end of file
diff --git a/test/core/json/corpus/2cc301a6ed7f01e2cd339f02bd0fda20c227a17e b/test/core/json/corpus/2cc301a6ed7f01e2cd339f02bd0fda20c227a17e
new file mode 100644
index 0000000..f457fd8
--- /dev/null
+++ b/test/core/json/corpus/2cc301a6ed7f01e2cd339f02bd0fda20c227a17e
@@ -0,0 +1 @@
+825E132})
\ No newline at end of file
diff --git a/test/core/json/corpus/2d3d5b9275553430b4cfa68114099120ad7809ee b/test/core/json/corpus/2d3d5b9275553430b4cfa68114099120ad7809ee
new file mode 100644
index 0000000..7e7e3f7
--- /dev/null
+++ b/test/core/json/corpus/2d3d5b9275553430b4cfa68114099120ad7809ee
@@ -0,0 +1 @@
+[4*
\ No newline at end of file
diff --git a/test/core/json/corpus/2d5dbf403e0c12e2fe21b04ca3daff171c028ab7 b/test/core/json/corpus/2d5dbf403e0c12e2fe21b04ca3daff171c028ab7
new file mode 100644
index 0000000..42bbdf9
--- /dev/null
+++ b/test/core/json/corpus/2d5dbf403e0c12e2fe21b04ca3daff171c028ab7
@@ -0,0 +1 @@
+""919
\ No newline at end of file
diff --git a/test/core/json/corpus/2d7c769bed62004270034b976b1d940a5686106b b/test/core/json/corpus/2d7c769bed62004270034b976b1d940a5686106b
new file mode 100644
index 0000000..8a2b433
--- /dev/null
+++ b/test/core/json/corpus/2d7c769bed62004270034b976b1d940a5686106b
@@ -0,0 +1 @@
+{"',!\u65E8850{2312;):)ˆ!*?'¾Êѳ³!!ª!À):*!à::8!9:\udbD6\\'
\ No newline at end of file
diff --git a/test/core/json/corpus/2db120231eea12d9cdc6a00f30839b3cef2046be b/test/core/json/corpus/2db120231eea12d9cdc6a00f30839b3cef2046be
new file mode 100644
index 0000000..0cfb6e8
--- /dev/null
+++ b/test/core/json/corpus/2db120231eea12d9cdc6a00f30839b3cef2046be
@@ -0,0 +1 @@
+0.0 
\ No newline at end of file
diff --git a/test/core/json/corpus/2db610e1a230409a205cf22fbad3348a54cbe703 b/test/core/json/corpus/2db610e1a230409a205cf22fbad3348a54cbe703
new file mode 100644
index 0000000..3541d8d
--- /dev/null
+++ b/test/core/json/corpus/2db610e1a230409a205cf22fbad3348a54cbe703
@@ -0,0 +1 @@
+faå
\ No newline at end of file
diff --git a/test/core/json/corpus/2df1dd2e2f5d57e7d9d4e60a756a86e603573225 b/test/core/json/corpus/2df1dd2e2f5d57e7d9d4e60a756a86e603573225
new file mode 100644
index 0000000..390f409
--- /dev/null
+++ b/test/core/json/corpus/2df1dd2e2f5d57e7d9d4e60a756a86e603573225
@@ -0,0 +1 @@
+0.9!
\ No newline at end of file
diff --git a/test/core/json/corpus/2e32faacd3ea4461ec7aace297b4be6904d9a389 b/test/core/json/corpus/2e32faacd3ea4461ec7aace297b4be6904d9a389
new file mode 100644
index 0000000..83323c2
--- /dev/null
+++ b/test/core/json/corpus/2e32faacd3ea4461ec7aace297b4be6904d9a389
@@ -0,0 +1 @@
+[["ˆÃ{)!:*¾;?'ʳ³!!*!à):!*à:::\u1.y2db)8ˆÃ!‡:{!`!.7;?
\ No newline at end of file
diff --git a/test/core/json/corpus/2e756d91759d7e74f5b776c0d2a1935292f576d1 b/test/core/json/corpus/2e756d91759d7e74f5b776c0d2a1935292f576d1
new file mode 100644
index 0000000..037d9ce
--- /dev/null
+++ b/test/core/json/corpus/2e756d91759d7e74f5b776c0d2a1935292f576d1
@@ -0,0 +1 @@
+"ˆÃ{)!:*¾;?'ʳ³!!*!à):!*à::d\r:8))ˆÃ![1.‡97:{
\ No newline at end of file
diff --git a/test/core/json/corpus/2f09b24f9f5fa0af2c29b604b4b0f97fa6163895 b/test/core/json/corpus/2f09b24f9f5fa0af2c29b604b4b0f97fa6163895
new file mode 100644
index 0000000..f7e8e7b
--- /dev/null
+++ b/test/core/json/corpus/2f09b24f9f5fa0af2c29b604b4b0f97fa6163895
@@ -0,0 +1 @@
+ 9Š
\ No newline at end of file
diff --git a/test/core/json/corpus/3027d901361162b38fcaf17f97ba7d9646e32495 b/test/core/json/corpus/3027d901361162b38fcaf17f97ba7d9646e32495
new file mode 100644
index 0000000..8372b41
--- /dev/null
+++ b/test/core/json/corpus/3027d901361162b38fcaf17f97ba7d9646e32495
Binary files differ
diff --git a/test/core/json/corpus/30d4467ecb771ece9ed6c78a46adc299072d9db9 b/test/core/json/corpus/30d4467ecb771ece9ed6c78a46adc299072d9db9
new file mode 100644
index 0000000..e396fba
--- /dev/null
+++ b/test/core/json/corpus/30d4467ecb771ece9ed6c78a46adc299072d9db9
@@ -0,0 +1 @@
+4.9!
\ No newline at end of file
diff --git a/test/core/json/corpus/311048bbf4c4bbabcde73607d7e76915cee9312e b/test/core/json/corpus/311048bbf4c4bbabcde73607d7e76915cee9312e
new file mode 100644
index 0000000..79453e9
--- /dev/null
+++ b/test/core/json/corpus/311048bbf4c4bbabcde73607d7e76915cee9312e
Binary files differ
diff --git a/test/core/json/corpus/323b48969d7bf9a50aacf0912f1b5cb02119e2ab b/test/core/json/corpus/323b48969d7bf9a50aacf0912f1b5cb02119e2ab
new file mode 100644
index 0000000..b558a9a
--- /dev/null
+++ b/test/core/json/corpus/323b48969d7bf9a50aacf0912f1b5cb02119e2ab
@@ -0,0 +1 @@
+"',!\u65E8850{2312;):ˆ)!Ã"*¾?'ʳ³!!*!à):!*à::)!9:\udbD86'
\ No newline at end of file
diff --git a/test/core/json/corpus/33400a242baeb5c46ddb1578c28b10d32a9c3cd3 b/test/core/json/corpus/33400a242baeb5c46ddb1578c28b10d32a9c3cd3
new file mode 100644
index 0000000..ffb93e3
--- /dev/null
+++ b/test/core/json/corpus/33400a242baeb5c46ddb1578c28b10d32a9c3cd3
@@ -0,0 +1 @@
+{"',!\ru65E8850{2312;):ˆ)!Ã"*¾{"',!u65E?'8Ê85
\ No newline at end of file
diff --git a/test/core/json/corpus/356a192b7913b04c54574d18c28d46e6395428ab b/test/core/json/corpus/356a192b7913b04c54574d18c28d46e6395428ab
new file mode 100644
index 0000000..56a6051
--- /dev/null
+++ b/test/core/json/corpus/356a192b7913b04c54574d18c28d46e6395428ab
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/test/core/json/corpus/35e995c107a71caeb833bb3b79f9f54781b33fa1 b/test/core/json/corpus/35e995c107a71caeb833bb3b79f9f54781b33fa1
new file mode 100644
index 0000000..e77a963
--- /dev/null
+++ b/test/core/json/corpus/35e995c107a71caeb833bb3b79f9f54781b33fa1
@@ -0,0 +1 @@
+73
\ No newline at end of file
diff --git a/test/core/json/corpus/373769c15c145472c8ec3bdde8fc84e85ec79211 b/test/core/json/corpus/373769c15c145472c8ec3bdde8fc84e85ec79211
new file mode 100644
index 0000000..7f34060
--- /dev/null
+++ b/test/core/json/corpus/373769c15c145472c8ec3bdde8fc84e85ec79211
Binary files differ
diff --git a/test/core/json/corpus/3795d911970a1fd8416b93649051b418948e3edf b/test/core/json/corpus/3795d911970a1fd8416b93649051b418948e3edf
new file mode 100644
index 0000000..1df36a5
--- /dev/null
+++ b/test/core/json/corpus/3795d911970a1fd8416b93649051b418948e3edf
@@ -0,0 +1 @@
+[[2.76;]3*
\ No newline at end of file
diff --git a/test/core/json/corpus/37d3333e1e2a384c3ba14a52682ca29f061d1ac7 b/test/core/json/corpus/37d3333e1e2a384c3ba14a52682ca29f061d1ac7
new file mode 100644
index 0000000..c37e132
--- /dev/null
+++ b/test/core/json/corpus/37d3333e1e2a384c3ba14a52682ca29f061d1ac7
@@ -0,0 +1 @@
+{"!(!\u'
\ No newline at end of file
diff --git a/test/core/json/corpus/38cd33bb390445e35b6514024b1317902cb7ba1b b/test/core/json/corpus/38cd33bb390445e35b6514024b1317902cb7ba1b
new file mode 100644
index 0000000..83312e5
--- /dev/null
+++ b/test/core/json/corpus/38cd33bb390445e35b6514024b1317902cb7ba1b
@@ -0,0 +1 @@
+"ˆÃ!{)!:",ˆÃ
\ No newline at end of file
diff --git a/test/core/json/corpus/3a90c688f44447a78efc111872b061a001f04d2b b/test/core/json/corpus/3a90c688f44447a78efc111872b061a001f04d2b
new file mode 100644
index 0000000..2b729e7
--- /dev/null
+++ b/test/core/json/corpus/3a90c688f44447a78efc111872b061a001f04d2b
@@ -0,0 +1 @@
+181e32560
\ No newline at end of file
diff --git a/test/core/json/corpus/3b1e7b56ad4465d126ea994d34d20dcecbb3a50a b/test/core/json/corpus/3b1e7b56ad4465d126ea994d34d20dcecbb3a50a
new file mode 100644
index 0000000..3029e04
--- /dev/null
+++ b/test/core/json/corpus/3b1e7b56ad4465d126ea994d34d20dcecbb3a50a
@@ -0,0 +1 @@
+5E882392);)
\ No newline at end of file
diff --git a/test/core/json/corpus/3c0a8d6c31edaca124714624eb64cb8ec0cbab13 b/test/core/json/corpus/3c0a8d6c31edaca124714624eb64cb8ec0cbab13
new file mode 100644
index 0000000..82db9e7
--- /dev/null
+++ b/test/core/json/corpus/3c0a8d6c31edaca124714624eb64cb8ec0cbab13
@@ -0,0 +1 @@
+{"*]:Ã!{)¾?'ʳ³!!*!à):!*à:::\udbD8ˆ)!{Ã:{!`!?`¾¾"(¡
\ No newline at end of file
diff --git a/test/core/json/corpus/3cc0c9adcf3882f01409c70391c3cd30588ef34c b/test/core/json/corpus/3cc0c9adcf3882f01409c70391c3cd30588ef34c
new file mode 100644
index 0000000..7a63c8c
--- /dev/null
+++ b/test/core/json/corpus/3cc0c9adcf3882f01409c70391c3cd30588ef34c
@@ -0,0 +1 @@
+[{
\ No newline at end of file
diff --git a/test/core/json/corpus/3d0d9878b812ce4634962ba3dd755c0953550200 b/test/core/json/corpus/3d0d9878b812ce4634962ba3dd755c0953550200
new file mode 100644
index 0000000..8793f1e
--- /dev/null
+++ b/test/core/json/corpus/3d0d9878b812ce4634962ba3dd755c0953550200
@@ -0,0 +1 @@
+[tru[(0.193;]4*
\ No newline at end of file
diff --git a/test/core/json/corpus/3d4d5887a2fcdc5dd360b8a6f89dbce6500d8580 b/test/core/json/corpus/3d4d5887a2fcdc5dd360b8a6f89dbce6500d8580
new file mode 100644
index 0000000..c524697
--- /dev/null
+++ b/test/core/json/corpus/3d4d5887a2fcdc5dd360b8a6f89dbce6500d8580
@@ -0,0 +1 @@
+"'',!\u658E{128031:;):ˆ)!Ã5*¾?'ʳ³!!*!à):!*à::)!9:\udbD8 '
\ No newline at end of file
diff --git a/test/core/json/corpus/3efb5b7ff94c5b9d411c93da9a70e1cc547f4c59 b/test/core/json/corpus/3efb5b7ff94c5b9d411c93da9a70e1cc547f4c59
new file mode 100644
index 0000000..90a082d
--- /dev/null
+++ b/test/core/json/corpus/3efb5b7ff94c5b9d411c93da9a70e1cc547f4c59
@@ -0,0 +1 @@
+13e290560
\ No newline at end of file
diff --git a/test/core/json/corpus/421b7e8ea86e3c07474af16ab3ccef55d1857205 b/test/core/json/corpus/421b7e8ea86e3c07474af16ab3ccef55d1857205
new file mode 100644
index 0000000..1274714
--- /dev/null
+++ b/test/core/json/corpus/421b7e8ea86e3c07474af16ab3ccef55d1857205
@@ -0,0 +1,2 @@
+[2.1
+'{"ˆ"ÈÃ""
\ No newline at end of file
diff --git a/test/core/json/corpus/428d051e437dd260f2a2f7ed920d9734ca34dc90 b/test/core/json/corpus/428d051e437dd260f2a2f7ed920d9734ca34dc90
new file mode 100644
index 0000000..ad50d48
--- /dev/null
+++ b/test/core/json/corpus/428d051e437dd260f2a2f7ed920d9734ca34dc90
@@ -0,0 +1 @@
+[2.
\ No newline at end of file
diff --git a/test/core/json/corpus/42adc281578ffb1b8684b78b47aa40a16d10b6e7 b/test/core/json/corpus/42adc281578ffb1b8684b78b47aa40a16d10b6e7
new file mode 100644
index 0000000..59b1709
--- /dev/null
+++ b/test/core/json/corpus/42adc281578ffb1b8684b78b47aa40a16d10b6e7
@@ -0,0 +1 @@
+363,
\ No newline at end of file
diff --git a/test/core/json/corpus/43620ecd2e2fd58fe5650da2e9783f980f29ec07 b/test/core/json/corpus/43620ecd2e2fd58fe5650da2e9783f980f29ec07
new file mode 100644
index 0000000..f198034
--- /dev/null
+++ b/test/core/json/corpus/43620ecd2e2fd58fe5650da2e9783f980f29ec07
@@ -0,0 +1 @@
+13e109560
\ No newline at end of file
diff --git a/test/core/json/corpus/43b1ffcda49477adb1632822202631990ed3a269 b/test/core/json/corpus/43b1ffcda49477adb1632822202631990ed3a269
new file mode 100644
index 0000000..19db1d4
--- /dev/null
+++ b/test/core/json/corpus/43b1ffcda49477adb1632822202631990ed3a269
@@ -0,0 +1 @@
+1e+2,1ˆÃ"x
\ No newline at end of file
diff --git a/test/core/json/corpus/45279f85bf2f533a629073caf89403006279fab2 b/test/core/json/corpus/45279f85bf2f533a629073caf89403006279fab2
new file mode 100644
index 0000000..e6d3d7c
--- /dev/null
+++ b/test/core/json/corpus/45279f85bf2f533a629073caf89403006279fab2
@@ -0,0 +1,2 @@
+{
+620
\ No newline at end of file
diff --git a/test/core/json/corpus/455d9bb597f08bf698454157ecd86647b5dec4e0 b/test/core/json/corpus/455d9bb597f08bf698454157ecd86647b5dec4e0
new file mode 100644
index 0000000..0a601eb
--- /dev/null
+++ b/test/core/json/corpus/455d9bb597f08bf698454157ecd86647b5dec4e0
@@ -0,0 +1 @@
+0.3282
\ No newline at end of file
diff --git a/test/core/json/corpus/4561eb5c7e43cae048c06aaaad3d5f5218b376e9 b/test/core/json/corpus/4561eb5c7e43cae048c06aaaad3d5f5218b376e9
new file mode 100644
index 0000000..1fdd026
--- /dev/null
+++ b/test/core/json/corpus/4561eb5c7e43cae048c06aaaad3d5f5218b376e9
@@ -0,0 +1 @@
+fal0%)
\ No newline at end of file
diff --git a/test/core/json/corpus/46417b001eeb87c32b642499fd5e1690d5d88c7f b/test/core/json/corpus/46417b001eeb87c32b642499fd5e1690d5d88c7f
new file mode 100644
index 0000000..f084840
--- /dev/null
+++ b/test/core/json/corpus/46417b001eeb87c32b642499fd5e1690d5d88c7f
@@ -0,0 +1 @@
+825E}321)
\ No newline at end of file
diff --git a/test/core/json/corpus/468af040024e96e9878ef33cc52755c5e7f5cbd5 b/test/core/json/corpus/468af040024e96e9878ef33cc52755c5e7f5cbd5
new file mode 100644
index 0000000..c9ff1a1
--- /dev/null
+++ b/test/core/json/corpus/468af040024e96e9878ef33cc52755c5e7f5cbd5
@@ -0,0 +1 @@
+0.72479834e;0.Ü3ï993)
\ No newline at end of file
diff --git a/test/core/json/corpus/469e5ed2547e9e55a96e96eb832c615631e3b576 b/test/core/json/corpus/469e5ed2547e9e55a96e96eb832c615631e3b576
new file mode 100644
index 0000000..97e7caf
--- /dev/null
+++ b/test/core/json/corpus/469e5ed2547e9e55a96e96eb832c615631e3b576
@@ -0,0 +1 @@
+[])Ã!:{"*¾?'ʳ³!!*!à):!*à:::\udbD8ˆ){Ã!:{!`!?`¾¾"(¡
\ No newline at end of file
diff --git a/test/core/json/corpus/472b07b9fcf2c2451e8781e944bf5f77cd8457c8 b/test/core/json/corpus/472b07b9fcf2c2451e8781e944bf5f77cd8457c8
new file mode 100644
index 0000000..b5045cc
--- /dev/null
+++ b/test/core/json/corpus/472b07b9fcf2c2451e8781e944bf5f77cd8457c8
@@ -0,0 +1 @@
+21
\ No newline at end of file
diff --git a/test/core/json/corpus/486da8aff04083c5e0fe112e733f2ae510e312a1 b/test/core/json/corpus/486da8aff04083c5e0fe112e733f2ae510e312a1
new file mode 100644
index 0000000..0afcc5f
--- /dev/null
+++ b/test/core/json/corpus/486da8aff04083c5e0fe112e733f2ae510e312a1
@@ -0,0 +1 @@
+tru¹82 'A\E60;)
\ No newline at end of file
diff --git a/test/core/json/corpus/488a5ed641e340ae51992e04ce6590bdec587218 b/test/core/json/corpus/488a5ed641e340ae51992e04ce6590bdec587218
new file mode 100644
index 0000000..f0b671b
--- /dev/null
+++ b/test/core/json/corpus/488a5ed641e340ae51992e04ce6590bdec587218
@@ -0,0 +1 @@
+0.1)¹
\ No newline at end of file
diff --git a/test/core/json/corpus/4a0a19218e082a343a1b17e5333409af9d98f0f5 b/test/core/json/corpus/4a0a19218e082a343a1b17e5333409af9d98f0f5
new file mode 100644
index 0000000..4d1ae35
--- /dev/null
+++ b/test/core/json/corpus/4a0a19218e082a343a1b17e5333409af9d98f0f5
@@ -0,0 +1 @@
+f
\ No newline at end of file
diff --git a/test/core/json/corpus/4a6644a1a3d5218f4bbd60220cab79c0b7bef45e b/test/core/json/corpus/4a6644a1a3d5218f4bbd60220cab79c0b7bef45e
new file mode 100644
index 0000000..90b4ca3
--- /dev/null
+++ b/test/core/json/corpus/4a6644a1a3d5218f4bbd60220cab79c0b7bef45e
@@ -0,0 +1 @@
+[21.82
\ No newline at end of file
diff --git a/test/core/json/corpus/4b39d4b8a9a04b9469e8fe4016322327fe540882 b/test/core/json/corpus/4b39d4b8a9a04b9469e8fe4016322327fe540882
new file mode 100644
index 0000000..a7c1d08
--- /dev/null
+++ b/test/core/json/corpus/4b39d4b8a9a04b9469e8fe4016322327fe540882
@@ -0,0 +1 @@
+3E8;4)
\ No newline at end of file
diff --git a/test/core/json/corpus/4bb0294e14946fb1f64213384097a676d3ef94f0 b/test/core/json/corpus/4bb0294e14946fb1f64213384097a676d3ef94f0
new file mode 100644
index 0000000..56e2dbc
--- /dev/null
+++ b/test/core/json/corpus/4bb0294e14946fb1f64213384097a676d3ef94f0
@@ -0,0 +1 @@
+363	
diff --git a/test/core/json/corpus/4cd66dfabbd964f8c6c4414b07cdb45dae692e19 b/test/core/json/corpus/4cd66dfabbd964f8c6c4414b07cdb45dae692e19
new file mode 100644
index 0000000..a46c9d2
--- /dev/null
+++ b/test/core/json/corpus/4cd66dfabbd964f8c6c4414b07cdb45dae692e19
@@ -0,0 +1 @@
+91
\ No newline at end of file
diff --git a/test/core/json/corpus/4d134bc072212ace2df385dae143139da74ec0ef b/test/core/json/corpus/4d134bc072212ace2df385dae143139da74ec0ef
new file mode 100644
index 0000000..cabf43b
--- /dev/null
+++ b/test/core/json/corpus/4d134bc072212ace2df385dae143139da74ec0ef
@@ -0,0 +1 @@
+24
\ No newline at end of file
diff --git a/test/core/json/corpus/4efa35221b2088e785048d0ff8fd99b03d5316fc b/test/core/json/corpus/4efa35221b2088e785048d0ff8fd99b03d5316fc
new file mode 100644
index 0000000..ecf2233
--- /dev/null
+++ b/test/core/json/corpus/4efa35221b2088e785048d0ff8fd99b03d5316fc
@@ -0,0 +1 @@
+0.)
\ No newline at end of file
diff --git a/test/core/json/corpus/4fa2a4a5a2f7dc4ddbdecae3ee85c787817b4cf8 b/test/core/json/corpus/4fa2a4a5a2f7dc4ddbdecae3ee85c787817b4cf8
new file mode 100644
index 0000000..17ef43e
--- /dev/null
+++ b/test/core/json/corpus/4fa2a4a5a2f7dc4ddbdecae3ee85c787817b4cf8
@@ -0,0 +1 @@
+813e128560
\ No newline at end of file
diff --git a/test/core/json/corpus/4fed4bf2dc6259d9de54e9fa7db4fd5a61f2535e b/test/core/json/corpus/4fed4bf2dc6259d9de54e9fa7db4fd5a61f2535e
new file mode 100644
index 0000000..e9cb940
--- /dev/null
+++ b/test/core/json/corpus/4fed4bf2dc6259d9de54e9fa7db4fd5a61f2535e
@@ -0,0 +1 @@
+2531E117t)*6
\ No newline at end of file
diff --git a/test/core/json/corpus/4ff800de0863adb5851fa26935159aa53b11cba7 b/test/core/json/corpus/4ff800de0863adb5851fa26935159aa53b11cba7
new file mode 100644
index 0000000..edd3d2b
--- /dev/null
+++ b/test/core/json/corpus/4ff800de0863adb5851fa26935159aa53b11cba7
@@ -0,0 +1 @@
+0.82510
\ No newline at end of file
diff --git a/test/core/json/corpus/4ff99a030518a132748c44bc1d836018e5b82cd0 b/test/core/json/corpus/4ff99a030518a132748c44bc1d836018e5b82cd0
new file mode 100644
index 0000000..bc59462
--- /dev/null
+++ b/test/core/json/corpus/4ff99a030518a132748c44bc1d836018e5b82cd0
@@ -0,0 +1 @@
+{"*]:Ã!{)¾?'Ê)“ :*!à):!*à:::\udb81\uDeA12])!{Ã:{!`!?
\ No newline at end of file
diff --git a/test/core/json/corpus/531c87b9772e54e3e183ef729f0a7d5a0d584f46 b/test/core/json/corpus/531c87b9772e54e3e183ef729f0a7d5a0d584f46
new file mode 100644
index 0000000..08f1be3
--- /dev/null
+++ b/test/core/json/corpus/531c87b9772e54e3e183ef729f0a7d5a0d584f46
@@ -0,0 +1 @@
+{"',!\u65E8850{2312;):ˆ)!*?'¾Ê³³!!ª!à):!*à::8!9:\udbD86'
\ No newline at end of file
diff --git a/test/core/json/corpus/534d66e7b0709d1e7692faae9e7f7299c92bba4b b/test/core/json/corpus/534d66e7b0709d1e7692faae9e7f7299c92bba4b
new file mode 100644
index 0000000..44b3fa0
--- /dev/null
+++ b/test/core/json/corpus/534d66e7b0709d1e7692faae9e7f7299c92bba4b
@@ -0,0 +1 @@
+[[2.193]4*
\ No newline at end of file
diff --git a/test/core/json/corpus/548775f9d7d13339dba3001f8238b84e9a457533 b/test/core/json/corpus/548775f9d7d13339dba3001f8238b84e9a457533
new file mode 100644
index 0000000..9fed6d1
--- /dev/null
+++ b/test/core/json/corpus/548775f9d7d13339dba3001f8238b84e9a457533
@@ -0,0 +1 @@
+[1.97;
\ No newline at end of file
diff --git a/test/core/json/corpus/54ec3b2d8a9b7a6d8204712eb1b90da703cf8a79 b/test/core/json/corpus/54ec3b2d8a9b7a6d8204712eb1b90da703cf8a79
new file mode 100644
index 0000000..25984e7
--- /dev/null
+++ b/test/core/json/corpus/54ec3b2d8a9b7a6d8204712eb1b90da703cf8a79
@@ -0,0 +1 @@
+"ˆÃ{)!:*¾;?Xʳ³!!*!à):!*à:::\udÃb)ˆ8!‡:{!`!*`¾¾!?'!*m,');…'`
\ No newline at end of file
diff --git a/test/core/json/corpus/552cfe1d8958e6d003ec8e883c4983dd67ef255e b/test/core/json/corpus/552cfe1d8958e6d003ec8e883c4983dd67ef255e
new file mode 100644
index 0000000..1b18370
--- /dev/null
+++ b/test/core/json/corpus/552cfe1d8958e6d003ec8e883c4983dd67ef255e
@@ -0,0 +1 @@
+nu#
\ No newline at end of file
diff --git a/test/core/json/corpus/55f0c61d096a08506076489ded3b868db4086770 b/test/core/json/corpus/55f0c61d096a08506076489ded3b868db4086770
new file mode 100644
index 0000000..d65b537
--- /dev/null
+++ b/test/core/json/corpus/55f0c61d096a08506076489ded3b868db4086770
@@ -0,0 +1 @@
+0.2]G)
\ No newline at end of file
diff --git a/test/core/json/corpus/56e5f35e3d08b4e17e3558cacddf9e5ed13a0159 b/test/core/json/corpus/56e5f35e3d08b4e17e3558cacddf9e5ed13a0159
new file mode 100644
index 0000000..1960fad
--- /dev/null
+++ b/test/core/json/corpus/56e5f35e3d08b4e17e3558cacddf9e5ed13a0159
@@ -0,0 +1 @@
+[[[{"ˆÃ{)!:*¾;?'ʳ³!!*!à):!*à:::\u12198.y2db)8ˆÃ!3;!ȇ:!`!.7;?
\ No newline at end of file
diff --git a/test/core/json/corpus/580b03c49fba02bb8e399500eb66f2ff0482b22a b/test/core/json/corpus/580b03c49fba02bb8e399500eb66f2ff0482b22a
new file mode 100644
index 0000000..5c23e62
--- /dev/null
+++ b/test/core/json/corpus/580b03c49fba02bb8e399500eb66f2ff0482b22a
@@ -0,0 +1 @@
+2]G)y3
\ No newline at end of file
diff --git a/test/core/json/corpus/5852643fbbcf92b0181327b69b4874c6ba6fa9f4 b/test/core/json/corpus/5852643fbbcf92b0181327b69b4874c6ba6fa9f4
new file mode 100644
index 0000000..d72c7c7
--- /dev/null
+++ b/test/core/json/corpus/5852643fbbcf92b0181327b69b4874c6ba6fa9f4
@@ -0,0 +1 @@
+{"'!\u3@:Š
\ No newline at end of file
diff --git a/test/core/json/corpus/58f497e5efaf9f69080f9eef63b0b9dabcfdbc0d b/test/core/json/corpus/58f497e5efaf9f69080f9eef63b0b9dabcfdbc0d
new file mode 100644
index 0000000..3ed722a
--- /dev/null
+++ b/test/core/json/corpus/58f497e5efaf9f69080f9eef63b0b9dabcfdbc0d
Binary files differ
diff --git a/test/core/json/corpus/59129aacfb6cebbe2c52f30ef3424209f7252e82 b/test/core/json/corpus/59129aacfb6cebbe2c52f30ef3424209f7252e82
new file mode 100644
index 0000000..d1cbcfa
--- /dev/null
+++ b/test/core/json/corpus/59129aacfb6cebbe2c52f30ef3424209f7252e82
@@ -0,0 +1 @@
+66
\ No newline at end of file
diff --git a/test/core/json/corpus/598a287a3e56caae23ed63abc95d5f3457165eef b/test/core/json/corpus/598a287a3e56caae23ed63abc95d5f3457165eef
new file mode 100644
index 0000000..7d3db88
--- /dev/null
+++ b/test/core/json/corpus/598a287a3e56caae23ed63abc95d5f3457165eef
@@ -0,0 +1 @@
+81e6125380
\ No newline at end of file
diff --git a/test/core/json/corpus/5a37a26dd2482226f534f79d321d28e7a615ab72 b/test/core/json/corpus/5a37a26dd2482226f534f79d321d28e7a615ab72
new file mode 100644
index 0000000..c9b11ff
--- /dev/null
+++ b/test/core/json/corpus/5a37a26dd2482226f534f79d321d28e7a615ab72
@@ -0,0 +1 @@
+[0.959] 
\ No newline at end of file
diff --git a/test/core/json/corpus/5a710dcd4c78ca1a74ceb9fbfb011f7ac86a5f7b b/test/core/json/corpus/5a710dcd4c78ca1a74ceb9fbfb011f7ac86a5f7b
new file mode 100644
index 0000000..a1cd2e7
--- /dev/null
+++ b/test/core/json/corpus/5a710dcd4c78ca1a74ceb9fbfb011f7ac86a5f7b
@@ -0,0 +1 @@
+[[{}G3
\ No newline at end of file
diff --git a/test/core/json/corpus/5ae7b87f5377d5ffc16fd3f69b4a4aa7be8b1184 b/test/core/json/corpus/5ae7b87f5377d5ffc16fd3f69b4a4aa7be8b1184
new file mode 100644
index 0000000..a1c1118
--- /dev/null
+++ b/test/core/json/corpus/5ae7b87f5377d5ffc16fd3f69b4a4aa7be8b1184
@@ -0,0 +1,2 @@
+{
+"ˆ"ÈÃ""
\ No newline at end of file
diff --git a/test/core/json/corpus/5b3fe86d5a309a6ba745881bd220fe1100b271ce b/test/core/json/corpus/5b3fe86d5a309a6ba745881bd220fe1100b271ce
new file mode 100644
index 0000000..bd45ebf
--- /dev/null
+++ b/test/core/json/corpus/5b3fe86d5a309a6ba745881bd220fe1100b271ce
@@ -0,0 +1 @@
+true82 'ANE2(0;)
\ No newline at end of file
diff --git a/test/core/json/corpus/5c38b7da113ab4535dbc22777ce8a1480c1c9d1e b/test/core/json/corpus/5c38b7da113ab4535dbc22777ce8a1480c1c9d1e
new file mode 100644
index 0000000..a135742
--- /dev/null
+++ b/test/core/json/corpus/5c38b7da113ab4535dbc22777ce8a1480c1c9d1e
@@ -0,0 +1 @@
+{"'!'\u3B:Š
\ No newline at end of file
diff --git a/test/core/json/corpus/5ca6c45a8d2e11c782806df43e7668beb4aba8f5 b/test/core/json/corpus/5ca6c45a8d2e11c782806df43e7668beb4aba8f5
new file mode 100644
index 0000000..ef736fd
--- /dev/null
+++ b/test/core/json/corpus/5ca6c45a8d2e11c782806df43e7668beb4aba8f5
@@ -0,0 +1 @@
+nul
\ No newline at end of file
diff --git a/test/core/json/corpus/5da7b543313339f84fd52e96bacf3a73368a1d2c b/test/core/json/corpus/5da7b543313339f84fd52e96bacf3a73368a1d2c
new file mode 100644
index 0000000..0e44b3e
--- /dev/null
+++ b/test/core/json/corpus/5da7b543313339f84fd52e96bacf3a73368a1d2c
@@ -0,0 +1 @@
+])Ã!:{"*¾?'ʳ³!!*!à):!*à:::\udbD8ˆ)Ã!:{!`!?`¾¾!?'!*m,');…'`
\ No newline at end of file
diff --git a/test/core/json/corpus/5e12ae9117668bcc22832640cc626315940aeba8 b/test/core/json/corpus/5e12ae9117668bcc22832640cc626315940aeba8
new file mode 100644
index 0000000..c182018
--- /dev/null
+++ b/test/core/json/corpus/5e12ae9117668bcc22832640cc626315940aeba8
Binary files differ
diff --git a/test/core/json/corpus/5e397439a2680ed827c46704969c6711dabbda84 b/test/core/json/corpus/5e397439a2680ed827c46704969c6711dabbda84
new file mode 100644
index 0000000..3be1f86
--- /dev/null
+++ b/test/core/json/corpus/5e397439a2680ed827c46704969c6711dabbda84
@@ -0,0 +1 @@
+"!!\\''
\ No newline at end of file
diff --git a/test/core/json/corpus/5e629dfb8b7533c7c2d173d4c3d587c88112cc29 b/test/core/json/corpus/5e629dfb8b7533c7c2d173d4c3d587c88112cc29
new file mode 100644
index 0000000..08b9840
--- /dev/null
+++ b/test/core/json/corpus/5e629dfb8b7533c7c2d173d4c3d587c88112cc29
@@ -0,0 +1 @@
+1e2188560
\ No newline at end of file
diff --git a/test/core/json/corpus/5e785c7c26813577f3e30ef8f7e37ab2a9ffe39c b/test/core/json/corpus/5e785c7c26813577f3e30ef8f7e37ab2a9ffe39c
new file mode 100644
index 0000000..134ad52
--- /dev/null
+++ b/test/core/json/corpus/5e785c7c26813577f3e30ef8f7e37ab2a9ffe39c
@@ -0,0 +1 @@
+{"":0,}f'+G{)13(§!(''\!
\ No newline at end of file
diff --git a/test/core/json/corpus/5f3394f5058822cc044b92654837625897176480 b/test/core/json/corpus/5f3394f5058822cc044b92654837625897176480
new file mode 100644
index 0000000..fb460ce
--- /dev/null
+++ b/test/core/json/corpus/5f3394f5058822cc044b92654837625897176480
@@ -0,0 +1 @@
+813e1622427913e1099560
\ No newline at end of file
diff --git a/test/core/json/corpus/5fb9bcbbb30a377209eab0541d144e44e71508d7 b/test/core/json/corpus/5fb9bcbbb30a377209eab0541d144e44e71508d7
new file mode 100644
index 0000000..a83c813
--- /dev/null
+++ b/test/core/json/corpus/5fb9bcbbb30a377209eab0541d144e44e71508d7
@@ -0,0 +1 @@
+,0)
\ No newline at end of file
diff --git a/test/core/json/corpus/6008213a61d06b4382b223768530c3452968b7b3 b/test/core/json/corpus/6008213a61d06b4382b223768530c3452968b7b3
new file mode 100644
index 0000000..46f8135
--- /dev/null
+++ b/test/core/json/corpus/6008213a61d06b4382b223768530c3452968b7b3
@@ -0,0 +1 @@
+{"',!u65E8850{2312;):ˆ)!*?'¾Ê³³!ª!à):!*Àà::4!9:\udD86'
\ No newline at end of file
diff --git a/test/core/json/corpus/60ba4b2daa4ed4d070fec06687e249e0e6f9ee45 b/test/core/json/corpus/60ba4b2daa4ed4d070fec06687e249e0e6f9ee45
new file mode 100644
index 0000000..81750b9
--- /dev/null
+++ b/test/core/json/corpus/60ba4b2daa4ed4d070fec06687e249e0e6f9ee45
@@ -0,0 +1 @@
+{
\ No newline at end of file
diff --git a/test/core/json/corpus/625ed64c30c8ab2f0b3bc75690f9faa4270f0041 b/test/core/json/corpus/625ed64c30c8ab2f0b3bc75690f9faa4270f0041
new file mode 100644
index 0000000..a9322d4
--- /dev/null
+++ b/test/core/json/corpus/625ed64c30c8ab2f0b3bc75690f9faa4270f0041
@@ -0,0 +1 @@
+"ˆÃ{)!:*¾;?'ʳ³!!*!à):!*à::d\b:8))ˆÃ![1.‡97:{
\ No newline at end of file
diff --git a/test/core/json/corpus/6314c2b304d04dc0108a95d29a93515e85e2b0b0 b/test/core/json/corpus/6314c2b304d04dc0108a95d29a93515e85e2b0b0
new file mode 100644
index 0000000..5981d9b
--- /dev/null
+++ b/test/core/json/corpus/6314c2b304d04dc0108a95d29a93515e85e2b0b0
@@ -0,0 +1 @@
+{"*]:Ã!{)¾?'ʳ³ :*!à):!*à:::\udbD8\u)!{Ã:{!`!?`¾¾")(¡
\ No newline at end of file
diff --git a/test/core/json/corpus/6462d8079d2ea921617e7d073b85cfab706800d3 b/test/core/json/corpus/6462d8079d2ea921617e7d073b85cfab706800d3
new file mode 100644
index 0000000..8ecd203
--- /dev/null
+++ b/test/core/json/corpus/6462d8079d2ea921617e7d073b85cfab706800d3
@@ -0,0 +1 @@
+null³
\ No newline at end of file
diff --git a/test/core/json/corpus/6474383282788e556aa86f57fc8650137ad264d0 b/test/core/json/corpus/6474383282788e556aa86f57fc8650137ad264d0
new file mode 100644
index 0000000..9210f64
--- /dev/null
+++ b/test/core/json/corpus/6474383282788e556aa86f57fc8650137ad264d0
@@ -0,0 +1 @@
+{"!!\/!!\'''
\ No newline at end of file
diff --git a/test/core/json/corpus/648c3f58ecc8fb4b8c779e6b11006ab5b1986dad b/test/core/json/corpus/648c3f58ecc8fb4b8c779e6b11006ab5b1986dad
new file mode 100644
index 0000000..dc9a929
--- /dev/null
+++ b/test/core/json/corpus/648c3f58ecc8fb4b8c779e6b11006ab5b1986dad
@@ -0,0 +1 @@
+21.498"
\ No newline at end of file
diff --git a/test/core/json/corpus/66328e03a2ccd5e54dab23b816182786e6f518b6 b/test/core/json/corpus/66328e03a2ccd5e54dab23b816182786e6f518b6
new file mode 100644
index 0000000..0d7016b
--- /dev/null
+++ b/test/core/json/corpus/66328e03a2ccd5e54dab23b816182786e6f518b6
@@ -0,0 +1 @@
+[{"ˆÃ\t5{)!:*
\ No newline at end of file
diff --git a/test/core/json/corpus/683e9045bc95e0cb5fc16ec64b118433475ba559 b/test/core/json/corpus/683e9045bc95e0cb5fc16ec64b118433475ba559
new file mode 100644
index 0000000..ab9ecdf
--- /dev/null
+++ b/test/core/json/corpus/683e9045bc95e0cb5fc16ec64b118433475ba559
Binary files differ
diff --git a/test/core/json/corpus/689f13680f4682303c8aa6828b67955959dc9669 b/test/core/json/corpus/689f13680f4682303c8aa6828b67955959dc9669
new file mode 100644
index 0000000..e49c890
--- /dev/null
+++ b/test/core/json/corpus/689f13680f4682303c8aa6828b67955959dc9669
@@ -0,0 +1 @@
+["*]:Ã!{)¾?'ʳ³!!*!à):!*à:::\udcD8ˆ){Ã!:{!`!?`¾¾"(¡
\ No newline at end of file
diff --git a/test/core/json/corpus/68c6ba7f0602a5410d1fa3c5de24fe264436b993 b/test/core/json/corpus/68c6ba7f0602a5410d1fa3c5de24fe264436b993
new file mode 100644
index 0000000..05c556c
--- /dev/null
+++ b/test/core/json/corpus/68c6ba7f0602a5410d1fa3c5de24fe264436b993
@@ -0,0 +1 @@
+{},[
\ No newline at end of file
diff --git a/test/core/json/corpus/699cafde80b1e1777306f781186d1253f018ab23 b/test/core/json/corpus/699cafde80b1e1777306f781186d1253f018ab23
new file mode 100644
index 0000000..54a4e1e
--- /dev/null
+++ b/test/core/json/corpus/699cafde80b1e1777306f781186d1253f018ab23
@@ -0,0 +1 @@
+[2}5{
\ No newline at end of file
diff --git a/test/core/json/corpus/69ab053b59e235fd6af246c5180f15bd95295113 b/test/core/json/corpus/69ab053b59e235fd6af246c5180f15bd95295113
new file mode 100644
index 0000000..dc0f5a0
--- /dev/null
+++ b/test/core/json/corpus/69ab053b59e235fd6af246c5180f15bd95295113
Binary files differ
diff --git a/test/core/json/corpus/69afa12510b2e653b0af7c7030832647b2d63c37 b/test/core/json/corpus/69afa12510b2e653b0af7c7030832647b2d63c37
new file mode 100644
index 0000000..5cd5103
--- /dev/null
+++ b/test/core/json/corpus/69afa12510b2e653b0af7c7030832647b2d63c37
@@ -0,0 +1 @@
+"ˆÃ,"
\ No newline at end of file
diff --git a/test/core/json/corpus/6b75857f86be5c51b21a97f4a61e69e8bb6cd698 b/test/core/json/corpus/6b75857f86be5c51b21a97f4a61e69e8bb6cd698
new file mode 100644
index 0000000..890abf2
--- /dev/null
+++ b/test/core/json/corpus/6b75857f86be5c51b21a97f4a61e69e8bb6cd698
@@ -0,0 +1 @@
+310560
\ No newline at end of file
diff --git a/test/core/json/corpus/6c75e71ecde9f073a7bad89f4831c8cde0bc1830 b/test/core/json/corpus/6c75e71ecde9f073a7bad89f4831c8cde0bc1830
new file mode 100644
index 0000000..84d8fa5
--- /dev/null
+++ b/test/core/json/corpus/6c75e71ecde9f073a7bad89f4831c8cde0bc1830
@@ -0,0 +1 @@
+9	3'Á6
\ No newline at end of file
diff --git a/test/core/json/corpus/6ce5170dc4f2eee3b31a875b6a41f2444959f3dd b/test/core/json/corpus/6ce5170dc4f2eee3b31a875b6a41f2444959f3dd
new file mode 100644
index 0000000..c91aab3
--- /dev/null
+++ b/test/core/json/corpus/6ce5170dc4f2eee3b31a875b6a41f2444959f3dd
@@ -0,0 +1 @@
+0}54
\ No newline at end of file
diff --git a/test/core/json/corpus/6d2859436fbbee637f0a5981ca82e8f88a1d0d28 b/test/core/json/corpus/6d2859436fbbee637f0a5981ca82e8f88a1d0d28
new file mode 100644
index 0000000..12d7c03
--- /dev/null
+++ b/test/core/json/corpus/6d2859436fbbee637f0a5981ca82e8f88a1d0d28
@@ -0,0 +1 @@
+[tr[[0.193;]4*
\ No newline at end of file
diff --git a/test/core/json/corpus/6d63e39f56d1d537bab9c2830303cabab3cd9035 b/test/core/json/corpus/6d63e39f56d1d537bab9c2830303cabab3cd9035
new file mode 100644
index 0000000..6b51382
--- /dev/null
+++ b/test/core/json/corpus/6d63e39f56d1d537bab9c2830303cabab3cd9035
@@ -0,0 +1 @@
+{"":}+G{12§(!(''\!
\ No newline at end of file
diff --git a/test/core/json/corpus/6e05a0a240fe2974e14527bbe390d294564156e2 b/test/core/json/corpus/6e05a0a240fe2974e14527bbe390d294564156e2
new file mode 100644
index 0000000..82236fc
--- /dev/null
+++ b/test/core/json/corpus/6e05a0a240fe2974e14527bbe390d294564156e2
@@ -0,0 +1 @@
+[2.1981
\ No newline at end of file
diff --git a/test/core/json/corpus/6e6c9d301adb0f0ddffd79cdf3426a2de99bad48 b/test/core/json/corpus/6e6c9d301adb0f0ddffd79cdf3426a2de99bad48
new file mode 100644
index 0000000..363c669
--- /dev/null
+++ b/test/core/json/corpus/6e6c9d301adb0f0ddffd79cdf3426a2de99bad48
@@ -0,0 +1,2 @@
+{
+"ˆÃ"
\ No newline at end of file
diff --git a/test/core/json/corpus/6e989edf725ec64849377681ce02641c3d1870e8 b/test/core/json/corpus/6e989edf725ec64849377681ce02641c3d1870e8
new file mode 100644
index 0000000..45cb64d
--- /dev/null
+++ b/test/core/json/corpus/6e989edf725ec64849377681ce02641c3d1870e8
@@ -0,0 +1 @@
+2}G)y3
\ No newline at end of file
diff --git a/test/core/json/corpus/70142f66475ae2fb33722d8d4750f386ecfefe7b b/test/core/json/corpus/70142f66475ae2fb33722d8d4750f386ecfefe7b
new file mode 100644
index 0000000..415b19f
--- /dev/null
+++ b/test/core/json/corpus/70142f66475ae2fb33722d8d4750f386ecfefe7b
@@ -0,0 +1 @@
+2.0
\ No newline at end of file
diff --git a/test/core/json/corpus/719edbe667ce2729ac78a22dac29263c91144029 b/test/core/json/corpus/719edbe667ce2729ac78a22dac29263c91144029
new file mode 100644
index 0000000..fccbca3
--- /dev/null
+++ b/test/core/json/corpus/719edbe667ce2729ac78a22dac29263c91144029
Binary files differ
diff --git a/test/core/json/corpus/71f99ca2bda6ef2e15b965479a79587f9d794be0 b/test/core/json/corpus/71f99ca2bda6ef2e15b965479a79587f9d794be0
new file mode 100644
index 0000000..bad49bb
--- /dev/null
+++ b/test/core/json/corpus/71f99ca2bda6ef2e15b965479a79587f9d794be0
@@ -0,0 +1 @@
+834E;)
\ No newline at end of file
diff --git a/test/core/json/corpus/7714a1a32872442a2eaff472685f3ea69451a732 b/test/core/json/corpus/7714a1a32872442a2eaff472685f3ea69451a732
new file mode 100644
index 0000000..03a8147
--- /dev/null
+++ b/test/core/json/corpus/7714a1a32872442a2eaff472685f3ea69451a732
@@ -0,0 +1 @@
+8324E685;)
\ No newline at end of file
diff --git a/test/core/json/corpus/7719a1c782a1ba91c031a682a0a2f8658209adbf b/test/core/json/corpus/7719a1c782a1ba91c031a682a0a2f8658209adbf
new file mode 100644
index 0000000..d99e90e
--- /dev/null
+++ b/test/core/json/corpus/7719a1c782a1ba91c031a682a0a2f8658209adbf
@@ -0,0 +1 @@
+29
\ No newline at end of file
diff --git a/test/core/json/corpus/77de68daecd823babbb58edb1c8e14d7106e83bb b/test/core/json/corpus/77de68daecd823babbb58edb1c8e14d7106e83bb
new file mode 100644
index 0000000..e440e5c
--- /dev/null
+++ b/test/core/json/corpus/77de68daecd823babbb58edb1c8e14d7106e83bb
@@ -0,0 +1 @@
+3
\ No newline at end of file
diff --git a/test/core/json/corpus/7957dc9aac31e6a6783fb3a6ee073688fed6cf9d b/test/core/json/corpus/7957dc9aac31e6a6783fb3a6ee073688fed6cf9d
new file mode 100644
index 0000000..27410a6
--- /dev/null
+++ b/test/core/json/corpus/7957dc9aac31e6a6783fb3a6ee073688fed6cf9d
@@ -0,0 +1 @@
+fal[2.1982
\ No newline at end of file
diff --git a/test/core/json/corpus/7ae893cbbf9b11ff411640b80985ce618907559c b/test/core/json/corpus/7ae893cbbf9b11ff411640b80985ce618907559c
new file mode 100644
index 0000000..2306064
--- /dev/null
+++ b/test/core/json/corpus/7ae893cbbf9b11ff411640b80985ce618907559c
@@ -0,0 +1 @@
+[0.29]95 
\ No newline at end of file
diff --git a/test/core/json/corpus/7b20ac50954063e3ad00813acab4a98b2bfdb858 b/test/core/json/corpus/7b20ac50954063e3ad00813acab4a98b2bfdb858
new file mode 100644
index 0000000..0bfbc04
--- /dev/null
+++ b/test/core/json/corpus/7b20ac50954063e3ad00813acab4a98b2bfdb858
@@ -0,0 +1 @@
+[2.198
\ No newline at end of file
diff --git a/test/core/json/corpus/7b6273145fb090de1c6163586f884a1da4b5cfbf b/test/core/json/corpus/7b6273145fb090de1c6163586f884a1da4b5cfbf
new file mode 100644
index 0000000..7e75a57
--- /dev/null
+++ b/test/core/json/corpus/7b6273145fb090de1c6163586f884a1da4b5cfbf
Binary files differ
diff --git a/test/core/json/corpus/7cf84b5a78281e6c6b5a9884110f3dbc6a40e310 b/test/core/json/corpus/7cf84b5a78281e6c6b5a9884110f3dbc6a40e310
new file mode 100644
index 0000000..6409a85
--- /dev/null
+++ b/test/core/json/corpus/7cf84b5a78281e6c6b5a9884110f3dbc6a40e310
@@ -0,0 +1,2 @@
+{
+"ˆ[2":}5ˆÃ["}5""{
\ No newline at end of file
diff --git a/test/core/json/corpus/7ef13b83e6bde582d9000be043e729cd3221c150 b/test/core/json/corpus/7ef13b83e6bde582d9000be043e729cd3221c150
new file mode 100644
index 0000000..bb69053
--- /dev/null
+++ b/test/core/json/corpus/7ef13b83e6bde582d9000be043e729cd3221c150
@@ -0,0 +1 @@
+{"" \!'(\'!
\ No newline at end of file
diff --git a/test/core/json/corpus/82059e250904b478f65daa0e647c1647ba6d6a3d b/test/core/json/corpus/82059e250904b478f65daa0e647c1647ba6d6a3d
new file mode 100644
index 0000000..7912fa5
--- /dev/null
+++ b/test/core/json/corpus/82059e250904b478f65daa0e647c1647ba6d6a3d
@@ -0,0 +1 @@
+21.596»
\ No newline at end of file
diff --git a/test/core/json/corpus/8207fdf4bd302d6b6b1894990b353944a8716aa7 b/test/core/json/corpus/8207fdf4bd302d6b6b1894990b353944a8716aa7
new file mode 100644
index 0000000..bbc3e31
--- /dev/null
+++ b/test/core/json/corpus/8207fdf4bd302d6b6b1894990b353944a8716aa7
@@ -0,0 +1 @@
+{"*]:Ã!{)¾?'Ê)“ :*!à):!*à:::\udb81\uD83e12])!{Ã:{!`!?
\ No newline at end of file
diff --git a/test/core/json/corpus/831a49ad81b59025c241ac9e58bd88463fd798eb b/test/core/json/corpus/831a49ad81b59025c241ac9e58bd88463fd798eb
new file mode 100644
index 0000000..8d42875
--- /dev/null
+++ b/test/core/json/corpus/831a49ad81b59025c241ac9e58bd88463fd798eb
@@ -0,0 +1 @@
+5E8850{2312;):ˆ)!Ã"*¾?'ʳ³!!*!à):!*à::8!9:\udbD8ˆ)Ã!:{!`
\ No newline at end of file
diff --git a/test/core/json/corpus/84582c1dbe026475319df14c19967d1dd0bf751f b/test/core/json/corpus/84582c1dbe026475319df14c19967d1dd0bf751f
new file mode 100644
index 0000000..7f509bf
--- /dev/null
+++ b/test/core/json/corpus/84582c1dbe026475319df14c19967d1dd0bf751f
@@ -0,0 +1 @@
+560
\ No newline at end of file
diff --git a/test/core/json/corpus/860d4ad0b7c026d1fcf51932b5e46500be7860a6 b/test/core/json/corpus/860d4ad0b7c026d1fcf51932b5e46500be7860a6
new file mode 100644
index 0000000..6e1ec85
--- /dev/null
+++ b/test/core/json/corpus/860d4ad0b7c026d1fcf51932b5e46500be7860a6
@@ -0,0 +1,2 @@
+3
+)
\ No newline at end of file
diff --git a/test/core/json/corpus/865c7cf36a4f4499a6242e51b77b58b868a7447b b/test/core/json/corpus/865c7cf36a4f4499a6242e51b77b58b868a7447b
new file mode 100644
index 0000000..f78c7b5
--- /dev/null
+++ b/test/core/json/corpus/865c7cf36a4f4499a6242e51b77b58b868a7447b
@@ -0,0 +1 @@
+"9![\b
\ No newline at end of file
diff --git a/test/core/json/corpus/87a2b80f9272583517c0207af176fc40ea55022c b/test/core/json/corpus/87a2b80f9272583517c0207af176fc40ea55022c
new file mode 100644
index 0000000..1ba5237
--- /dev/null
+++ b/test/core/json/corpus/87a2b80f9272583517c0207af176fc40ea55022c
@@ -0,0 +1 @@
+0.
\ No newline at end of file
diff --git a/test/core/json/corpus/887309d048beef83ad3eabf2a79a64a389ab1c9f b/test/core/json/corpus/887309d048beef83ad3eabf2a79a64a389ab1c9f
new file mode 100644
index 0000000..978b4e8
--- /dev/null
+++ b/test/core/json/corpus/887309d048beef83ad3eabf2a79a64a389ab1c9f
@@ -0,0 +1 @@
+26
\ No newline at end of file
diff --git a/test/core/json/corpus/88d89860ccaf21e5f0f002303a2cd853ecbb2acb b/test/core/json/corpus/88d89860ccaf21e5f0f002303a2cd853ecbb2acb
new file mode 100644
index 0000000..7fffca8
--- /dev/null
+++ b/test/core/json/corpus/88d89860ccaf21e5f0f002303a2cd853ecbb2acb
@@ -0,0 +1 @@
+{"":{}+G'(!'(\'!
\ No newline at end of file
diff --git a/test/core/json/corpus/88f658400b1870ddf081fb03020c3098b0b1e083 b/test/core/json/corpus/88f658400b1870ddf081fb03020c3098b0b1e083
new file mode 100644
index 0000000..6c4c537
--- /dev/null
+++ b/test/core/json/corpus/88f658400b1870ddf081fb03020c3098b0b1e083
@@ -0,0 +1 @@
+[[])Ã!:{"*¾?'ʳ³!!*!à):!*à:::\udbD{8ˆ){Ã!:{!`!?`¾¾"(¡
\ No newline at end of file
diff --git a/test/core/json/corpus/88f8b0984bb2f081918ad883c8f0ffacb5a8ff0a b/test/core/json/corpus/88f8b0984bb2f081918ad883c8f0ffacb5a8ff0a
new file mode 100644
index 0000000..e37941d
--- /dev/null
+++ b/test/core/json/corpus/88f8b0984bb2f081918ad883c8f0ffacb5a8ff0a
@@ -0,0 +1,2 @@
+2

\ No newline at end of file
diff --git a/test/core/json/corpus/89304953495f060c7abd3584d83cb1c8e6d6653b b/test/core/json/corpus/89304953495f060c7abd3584d83cb1c8e6d6653b
new file mode 100644
index 0000000..fa86cb3
--- /dev/null
+++ b/test/core/json/corpus/89304953495f060c7abd3584d83cb1c8e6d6653b
@@ -0,0 +1 @@
+[[["ˆÃ{)!:*¾;?'ʳ³!!*!à)])Ã!:{:!*à:::\"u12*1¾
\ No newline at end of file
diff --git a/test/core/json/corpus/8a5f6dc6873e3fd51fd866854d85258f8aa83a02 b/test/core/json/corpus/8a5f6dc6873e3fd51fd866854d85258f8aa83a02
new file mode 100644
index 0000000..057adde
--- /dev/null
+++ b/test/core/json/corpus/8a5f6dc6873e3fd51fd866854d85258f8aa83a02
@@ -0,0 +1,2 @@
+{
+"ˆ":ˆÃ""
\ No newline at end of file
diff --git a/test/core/json/corpus/8a87261277c15667e2957dd52c5db6757ebc8e88 b/test/core/json/corpus/8a87261277c15667e2957dd52c5db6757ebc8e88
new file mode 100644
index 0000000..9d7ee39
--- /dev/null
+++ b/test/core/json/corpus/8a87261277c15667e2957dd52c5db6757ebc8e88
@@ -0,0 +1 @@
+t"ˆÃ{)!:*¾;?Xʳ³!!*!à):!*à:::\
\ No newline at end of file
diff --git a/test/core/json/corpus/8aa61d8bd260942521bb1ba82cd4cce2324fdbee b/test/core/json/corpus/8aa61d8bd260942521bb1ba82cd4cce2324fdbee
new file mode 100644
index 0000000..9c93de0
--- /dev/null
+++ b/test/core/json/corpus/8aa61d8bd260942521bb1ba82cd4cce2324fdbee
@@ -0,0 +1 @@
+fal
\ No newline at end of file
diff --git a/test/core/json/corpus/8d8874439569824e371a0284460440175cdb8a27 b/test/core/json/corpus/8d8874439569824e371a0284460440175cdb8a27
new file mode 100644
index 0000000..ba964c2
--- /dev/null
+++ b/test/core/json/corpus/8d8874439569824e371a0284460440175cdb8a27
@@ -0,0 +1 @@
+5E882312;)
\ No newline at end of file
diff --git a/test/core/json/corpus/8e6fec8a05b24f221b6e94fdfe205e5bf7709a2c b/test/core/json/corpus/8e6fec8a05b24f221b6e94fdfe205e5bf7709a2c
new file mode 100644
index 0000000..2146b21
--- /dev/null
+++ b/test/core/json/corpus/8e6fec8a05b24f221b6e94fdfe205e5bf7709a2c
@@ -0,0 +1 @@
+[{"[])Ã!:{&*¾ˆÃ\f5{)!?'ʳ³!!*!à):!–à:::\ubD8:ˆ)kÃ!:{!`!?`¾¾"(*
\ No newline at end of file
diff --git a/test/core/json/corpus/8e7fda77644ff91578d25243fad51a3cd6d60860 b/test/core/json/corpus/8e7fda77644ff91578d25243fad51a3cd6d60860
new file mode 100644
index 0000000..538c0cc
--- /dev/null
+++ b/test/core/json/corpus/8e7fda77644ff91578d25243fad51a3cd6d60860
@@ -0,0 +1 @@
+[2.1982;
\ No newline at end of file
diff --git a/test/core/json/corpus/8ea6295ff82bb119acd44a91b463b19fedafb226 b/test/core/json/corpus/8ea6295ff82bb119acd44a91b463b19fedafb226
new file mode 100644
index 0000000..1acdc8e
--- /dev/null
+++ b/test/core/json/corpus/8ea6295ff82bb119acd44a91b463b19fedafb226
@@ -0,0 +1 @@
+[[2.6»7]3*
\ No newline at end of file
diff --git a/test/core/json/corpus/8ee51caaa2c2f4ee2e5b4b7ef5a89db7df1068d7 b/test/core/json/corpus/8ee51caaa2c2f4ee2e5b4b7ef5a89db7df1068d7
new file mode 100644
index 0000000..69226f7
--- /dev/null
+++ b/test/core/json/corpus/8ee51caaa2c2f4ee2e5b4b7ef5a89db7df1068d7
@@ -0,0 +1 @@
+92
\ No newline at end of file
diff --git a/test/core/json/corpus/8ef4dd9f2d0f9d770c937d9a43413d24df83f09b b/test/core/json/corpus/8ef4dd9f2d0f9d770c937d9a43413d24df83f09b
new file mode 100644
index 0000000..64adcb3
--- /dev/null
+++ b/test/core/json/corpus/8ef4dd9f2d0f9d770c937d9a43413d24df83f09b
@@ -0,0 +1 @@
+[{"ˆÃ\f5{)!:*]){
\ No newline at end of file
diff --git a/test/core/json/corpus/8efd86fb78a56a5145ed7739dcb00c78581c5375 b/test/core/json/corpus/8efd86fb78a56a5145ed7739dcb00c78581c5375
new file mode 100644
index 0000000..32f64f4
--- /dev/null
+++ b/test/core/json/corpus/8efd86fb78a56a5145ed7739dcb00c78581c5375
@@ -0,0 +1 @@
+t
\ No newline at end of file
diff --git a/test/core/json/corpus/8f0ba762c2fed0fc993feb91948902ac397b0919 b/test/core/json/corpus/8f0ba762c2fed0fc993feb91948902ac397b0919
new file mode 100644
index 0000000..cda6df2
--- /dev/null
+++ b/test/core/json/corpus/8f0ba762c2fed0fc993feb91948902ac397b0919
@@ -0,0 +1 @@
+["*:Ã!{)¾?'ʳ³!**!à):!*à:::\udbD8,ˆ
\ No newline at end of file
diff --git a/test/core/json/corpus/8fe81e450694cac1eb4c4a5c966ffbc56ade3513 b/test/core/json/corpus/8fe81e450694cac1eb4c4a5c966ffbc56ade3513
new file mode 100644
index 0000000..6b3c043
--- /dev/null
+++ b/test/core/json/corpus/8fe81e450694cac1eb4c4a5c966ffbc56ade3513
@@ -0,0 +1 @@
+0.2497Ü 
\ No newline at end of file
diff --git a/test/core/json/corpus/902ba3cda1883801594b6e1b452790cc53948fda b/test/core/json/corpus/902ba3cda1883801594b6e1b452790cc53948fda
new file mode 100644
index 0000000..c793025
--- /dev/null
+++ b/test/core/json/corpus/902ba3cda1883801594b6e1b452790cc53948fda
@@ -0,0 +1 @@
+7
\ No newline at end of file
diff --git a/test/core/json/corpus/910a1528b28ebc6ff2f2a4fedb013c86de4103e2 b/test/core/json/corpus/910a1528b28ebc6ff2f2a4fedb013c86de4103e2
new file mode 100644
index 0000000..1c5bc51
--- /dev/null
+++ b/test/core/json/corpus/910a1528b28ebc6ff2f2a4fedb013c86de4103e2
@@ -0,0 +1 @@
+8162E2517;)6
\ No newline at end of file
diff --git a/test/core/json/corpus/92049bf3d8a0ec93c2d1633631c0082e66ca69e7 b/test/core/json/corpus/92049bf3d8a0ec93c2d1633631c0082e66ca69e7
new file mode 100644
index 0000000..a4e01a7
--- /dev/null
+++ b/test/core/json/corpus/92049bf3d8a0ec93c2d1633631c0082e66ca69e7
@@ -0,0 +1,2 @@
+0

\ No newline at end of file
diff --git a/test/core/json/corpus/920a3c318f3127b9c30ab02a077555c7dfbb6edb b/test/core/json/corpus/920a3c318f3127b9c30ab02a077555c7dfbb6edb
new file mode 100644
index 0000000..2e7a62e
--- /dev/null
+++ b/test/core/json/corpus/920a3c318f3127b9c30ab02a077555c7dfbb6edb
@@ -0,0 +1 @@
+[[["ˆÃ{)!:*¾;?'ʳ³!!*!à):!*à:::\u12198.y2db)8ˆÃ!3;!‡:{!`!.7;?
\ No newline at end of file
diff --git a/test/core/json/corpus/925fc05dd661aeb4a776dcbc5df3dcb2cefaf0a6 b/test/core/json/corpus/925fc05dd661aeb4a776dcbc5df3dcb2cefaf0a6
new file mode 100644
index 0000000..22425f2
--- /dev/null
+++ b/test/core/json/corpus/925fc05dd661aeb4a776dcbc5df3dcb2cefaf0a6
@@ -0,0 +1 @@
+{}+G'
\ No newline at end of file
diff --git a/test/core/json/corpus/9367ba65affd5bf7aabf79c28e783cc5d93518e8 b/test/core/json/corpus/9367ba65affd5bf7aabf79c28e783cc5d93518e8
new file mode 100644
index 0000000..8e9c1aa
--- /dev/null
+++ b/test/core/json/corpus/9367ba65affd5bf7aabf79c28e783cc5d93518e8
@@ -0,0 +1 @@
+[2.11E02	"ˆÁ960
\ No newline at end of file
diff --git a/test/core/json/corpus/939f5049b1eefb91ccbd3fcecaed8cb21ea6b285 b/test/core/json/corpus/939f5049b1eefb91ccbd3fcecaed8cb21ea6b285
new file mode 100644
index 0000000..20dd34e
--- /dev/null
+++ b/test/core/json/corpus/939f5049b1eefb91ccbd3fcecaed8cb21ea6b285
@@ -0,0 +1 @@
+"!\'
\ No newline at end of file
diff --git a/test/core/json/corpus/9405c2b00eaa5526f71cc78914dbd3ecaf093b6e b/test/core/json/corpus/9405c2b00eaa5526f71cc78914dbd3ecaf093b6e
new file mode 100644
index 0000000..f996624
--- /dev/null
+++ b/test/core/json/corpus/9405c2b00eaa5526f71cc78914dbd3ecaf093b6e
@@ -0,0 +1 @@
+"9![\"
\ No newline at end of file
diff --git a/test/core/json/corpus/94d3598751569d2a5be258e59665cbbf0692dfbe b/test/core/json/corpus/94d3598751569d2a5be258e59665cbbf0692dfbe
new file mode 100644
index 0000000..e179cde
--- /dev/null
+++ b/test/core/json/corpus/94d3598751569d2a5be258e59665cbbf0692dfbe
@@ -0,0 +1 @@
+"',!\u65E8850{2312;):ˆ)!*?'¾Ê³0.³!!ª!À):*!à:;8!9:\udbD8\uDe250'
\ No newline at end of file
diff --git a/test/core/json/corpus/94f96d95d01e98fd2f04ce26c0913e5f9a882fb4 b/test/core/json/corpus/94f96d95d01e98fd2f04ce26c0913e5f9a882fb4
new file mode 100644
index 0000000..1de2ca8
--- /dev/null
+++ b/test/core/json/corpus/94f96d95d01e98fd2f04ce26c0913e5f9a882fb4
@@ -0,0 +1 @@
+58!9
\ No newline at end of file
diff --git a/test/core/json/corpus/95b54a84db75abab401d282fdb04440a879a9708 b/test/core/json/corpus/95b54a84db75abab401d282fdb04440a879a9708
new file mode 100644
index 0000000..5b41744
--- /dev/null
+++ b/test/core/json/corpus/95b54a84db75abab401d282fdb04440a879a9708
@@ -0,0 +1 @@
+{]3[
\ No newline at end of file
diff --git a/test/core/json/corpus/96189202e587ec951d5795da3e03062f2fb5d708 b/test/core/json/corpus/96189202e587ec951d5795da3e03062f2fb5d708
new file mode 100644
index 0000000..912fa7c
--- /dev/null
+++ b/test/core/json/corpus/96189202e587ec951d5795da3e03062f2fb5d708
@@ -0,0 +1 @@
+{"( \\!§('!
\ No newline at end of file
diff --git a/test/core/json/corpus/9711703428704ce2827a719eddb9d54be23a0cb7 b/test/core/json/corpus/9711703428704ce2827a719eddb9d54be23a0cb7
new file mode 100644
index 0000000..fdb93ea
--- /dev/null
+++ b/test/core/json/corpus/9711703428704ce2827a719eddb9d54be23a0cb7
@@ -0,0 +1 @@
+{"',!\u65E8850{2312;):ˆ)!*?'¾Ê³³!!ª!à):!*à::8!9:\udbD8,6'
\ No newline at end of file
diff --git a/test/core/json/corpus/9734597e96eebe99b2243121a51d178a338ec46f b/test/core/json/corpus/9734597e96eebe99b2243121a51d178a338ec46f
new file mode 100644
index 0000000..6903376
--- /dev/null
+++ b/test/core/json/corpus/9734597e96eebe99b2243121a51d178a338ec46f
@@ -0,0 +1 @@
+8162E-13;0.32)
\ No newline at end of file
diff --git a/test/core/json/corpus/9747c85a9510011bf87c23a80b029b9f2d04c37d b/test/core/json/corpus/9747c85a9510011bf87c23a80b029b9f2d04c37d
new file mode 100644
index 0000000..614c91b
--- /dev/null
+++ b/test/core/json/corpus/9747c85a9510011bf87c23a80b029b9f2d04c37d
@@ -0,0 +1 @@
+[0.3629,95 
\ No newline at end of file
diff --git a/test/core/json/corpus/97d170e1550eee4afc0af065b78cda302a97674c b/test/core/json/corpus/97d170e1550eee4afc0af065b78cda302a97674c
new file mode 100644
index 0000000..0637a08
--- /dev/null
+++ b/test/core/json/corpus/97d170e1550eee4afc0af065b78cda302a97674c
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/test/core/json/corpus/98e02e7fc96479e8d10ff2cc7610be772e2d6fba b/test/core/json/corpus/98e02e7fc96479e8d10ff2cc7610be772e2d6fba
new file mode 100644
index 0000000..6bc0fb8
--- /dev/null
+++ b/test/core/json/corpus/98e02e7fc96479e8d10ff2cc7610be772e2d6fba
@@ -0,0 +1 @@
+[[{"\/5nˆ[{+!:*
\ No newline at end of file
diff --git a/test/core/json/corpus/996156b191b619eff79b2fcbb7598518a09b06bc b/test/core/json/corpus/996156b191b619eff79b2fcbb7598518a09b06bc
new file mode 100644
index 0000000..c3f582e
--- /dev/null
+++ b/test/core/json/corpus/996156b191b619eff79b2fcbb7598518a09b06bc
@@ -0,0 +1 @@
+2.1498 
\ No newline at end of file
diff --git a/test/core/json/corpus/99667fcfa6d583a742fb5450527fc86dfb78ebbf b/test/core/json/corpus/99667fcfa6d583a742fb5450527fc86dfb78ebbf
new file mode 100644
index 0000000..861ae02
--- /dev/null
+++ b/test/core/json/corpus/99667fcfa6d583a742fb5450527fc86dfb78ebbf
@@ -0,0 +1 @@
+[{"ˆÃ{)!:*])Ã!:{"*¾?¾;?Xʳ³'!!Ê
\ No newline at end of file
diff --git a/test/core/json/corpus/9b1ead2dbeeb1a3e9a7bebcf6964c3cfbc7e8867 b/test/core/json/corpus/9b1ead2dbeeb1a3e9a7bebcf6964c3cfbc7e8867
new file mode 100644
index 0000000..d4f8951
--- /dev/null
+++ b/test/core/json/corpus/9b1ead2dbeeb1a3e9a7bebcf6964c3cfbc7e8867
@@ -0,0 +1 @@
+t \'
\ No newline at end of file
diff --git a/test/core/json/corpus/9b7669e201574bfb979d56110539a90da5aca2c0 b/test/core/json/corpus/9b7669e201574bfb979d56110539a90da5aca2c0
new file mode 100644
index 0000000..0cb3d49
--- /dev/null
+++ b/test/core/json/corpus/9b7669e201574bfb979d56110539a90da5aca2c0
@@ -0,0 +1 @@
+{""!!\'!!\'''
\ No newline at end of file
diff --git a/test/core/json/corpus/9c24b456af3cb51a1ff2780c2d9cbdd7d93f6c76 b/test/core/json/corpus/9c24b456af3cb51a1ff2780c2d9cbdd7d93f6c76
new file mode 100644
index 0000000..cbf048b
--- /dev/null
+++ b/test/core/json/corpus/9c24b456af3cb51a1ff2780c2d9cbdd7d93f6c76
@@ -0,0 +1 @@
+nuþ*:
\ No newline at end of file
diff --git a/test/core/json/corpus/9d0441f23ae7d5a3a5b1140497868ee6eeab656b b/test/core/json/corpus/9d0441f23ae7d5a3a5b1140497868ee6eeab656b
new file mode 100644
index 0000000..ed86228
--- /dev/null
+++ b/test/core/json/corpus/9d0441f23ae7d5a3a5b1140497868ee6eeab656b
@@ -0,0 +1,2 @@
+{
+"ˆÃ
\ No newline at end of file
diff --git a/test/core/json/corpus/9d890bd3139a8f9a44d435ff8edfbeb5b072ded0 b/test/core/json/corpus/9d890bd3139a8f9a44d435ff8edfbeb5b072ded0
new file mode 100644
index 0000000..468bde0
--- /dev/null
+++ b/test/core/json/corpus/9d890bd3139a8f9a44d435ff8edfbeb5b072ded0
Binary files differ
diff --git a/test/core/json/corpus/9e6a55b6b4563e652a23be9d623ca5055c356940 b/test/core/json/corpus/9e6a55b6b4563e652a23be9d623ca5055c356940
new file mode 100644
index 0000000..25bf17f
--- /dev/null
+++ b/test/core/json/corpus/9e6a55b6b4563e652a23be9d623ca5055c356940
@@ -0,0 +1 @@
+18
\ No newline at end of file
diff --git a/test/core/json/corpus/9ec88420ef0408642f6930996e35f5b9f18ec88c b/test/core/json/corpus/9ec88420ef0408642f6930996e35f5b9f18ec88c
new file mode 100644
index 0000000..852eeab
--- /dev/null
+++ b/test/core/json/corpus/9ec88420ef0408642f6930996e35f5b9f18ec88c
@@ -0,0 +1 @@
+"ˆÃ"
\ No newline at end of file
diff --git a/test/core/json/corpus/9edd067c569315d5e93b0d14c7eac9fa6d81d3cd b/test/core/json/corpus/9edd067c569315d5e93b0d14c7eac9fa6d81d3cd
new file mode 100644
index 0000000..86d0a11
--- /dev/null
+++ b/test/core/json/corpus/9edd067c569315d5e93b0d14c7eac9fa6d81d3cd
@@ -0,0 +1 @@
+[0.3629,]95 
\ No newline at end of file
diff --git a/test/core/json/corpus/9fbda4f714043d975389b536b4497c6d713452e5 b/test/core/json/corpus/9fbda4f714043d975389b536b4497c6d713452e5
new file mode 100644
index 0000000..c02cbb5
--- /dev/null
+++ b/test/core/json/corpus/9fbda4f714043d975389b536b4497c6d713452e5
@@ -0,0 +1 @@
+[2.4
\ No newline at end of file
diff --git a/test/core/json/corpus/9fc8cb8ab3b05e306e5e81d9d949e69f931244ea b/test/core/json/corpus/9fc8cb8ab3b05e306e5e81d9d949e69f931244ea
new file mode 100644
index 0000000..c85b1ce
--- /dev/null
+++ b/test/core/json/corpus/9fc8cb8ab3b05e306e5e81d9d949e69f931244ea
Binary files differ
diff --git a/test/core/json/corpus/a02b857f2eff73e8e188f35529dd91f8144b23b9 b/test/core/json/corpus/a02b857f2eff73e8e188f35529dd91f8144b23b9
new file mode 100644
index 0000000..3d9983a
--- /dev/null
+++ b/test/core/json/corpus/a02b857f2eff73e8e188f35529dd91f8144b23b9
@@ -0,0 +1 @@
+295
\ No newline at end of file
diff --git a/test/core/json/corpus/a060d5bfd1235cbbe4bcecf332fa3b03bc2282e3 b/test/core/json/corpus/a060d5bfd1235cbbe4bcecf332fa3b03bc2282e3
new file mode 100644
index 0000000..d6eb38c
--- /dev/null
+++ b/test/core/json/corpus/a060d5bfd1235cbbe4bcecf332fa3b03bc2282e3
@@ -0,0 +1 @@
+8324E7"!;\'
\ No newline at end of file
diff --git a/test/core/json/corpus/a0931fae1d43e7887c1cabde83fdfc52eaeedba8 b/test/core/json/corpus/a0931fae1d43e7887c1cabde83fdfc52eaeedba8
new file mode 100644
index 0000000..2950be2
--- /dev/null
+++ b/test/core/json/corpus/a0931fae1d43e7887c1cabde83fdfc52eaeedba8
@@ -0,0 +1 @@
+"',!\u65E8850{2312;):ˆ)!*?'¾Ê³³!!ª!À):*!à::8!9:\udbD8\u'
\ No newline at end of file
diff --git a/test/core/json/corpus/a1abe8a785030d475a7350438fd23a05c382c110 b/test/core/json/corpus/a1abe8a785030d475a7350438fd23a05c382c110
new file mode 100644
index 0000000..bb4e42e
--- /dev/null
+++ b/test/core/json/corpus/a1abe8a785030d475a7350438fd23a05c382c110
@@ -0,0 +1,2 @@
+[{
+"ˆÃ" :"ˆÃ!{)!:",}"ˆˆÃ;"
\ No newline at end of file
diff --git a/test/core/json/corpus/a1fb86293eac950c2b4f5182d9e4b5d9e0982ef6 b/test/core/json/corpus/a1fb86293eac950c2b4f5182d9e4b5d9e0982ef6
new file mode 100644
index 0000000..9ab1dd2
--- /dev/null
+++ b/test/core/json/corpus/a1fb86293eac950c2b4f5182d9e4b5d9e0982ef6
@@ -0,0 +1 @@
+1e+2,[2}1ˆ5{Ã"
\ No newline at end of file
diff --git a/test/core/json/corpus/a2d4e3d6f5ba43c9199d5d2011678f82cfd55afc b/test/core/json/corpus/a2d4e3d6f5ba43c9199d5d2011678f82cfd55afc
new file mode 100644
index 0000000..cfd2339
--- /dev/null
+++ b/test/core/json/corpus/a2d4e3d6f5ba43c9199d5d2011678f82cfd55afc
@@ -0,0 +1 @@
+[{"ˆ\\t5{)!:*
\ No newline at end of file
diff --git a/test/core/json/corpus/a39653cb3d97c58c44013197f4d7557577700177 b/test/core/json/corpus/a39653cb3d97c58c44013197f4d7557577700177
new file mode 100644
index 0000000..9e667cc
--- /dev/null
+++ b/test/core/json/corpus/a39653cb3d97c58c44013197f4d7557577700177
@@ -0,0 +1 @@
+[true[(0.193;]4*
\ No newline at end of file
diff --git a/test/core/json/corpus/a4c74ad56ae0e94e96101a8f2ce9b1e588df5e44 b/test/core/json/corpus/a4c74ad56ae0e94e96101a8f2ce9b1e588df5e44
new file mode 100644
index 0000000..079936b
--- /dev/null
+++ b/test/core/json/corpus/a4c74ad56ae0e94e96101a8f2ce9b1e588df5e44
@@ -0,0 +1 @@
+{])
\ No newline at end of file
diff --git a/test/core/json/corpus/a6b34b06b00e9226f2bd961483f9da81d8de99a8 b/test/core/json/corpus/a6b34b06b00e9226f2bd961483f9da81d8de99a8
new file mode 100644
index 0000000..56fbef6
--- /dev/null
+++ b/test/core/json/corpus/a6b34b06b00e9226f2bd961483f9da81d8de99a8
@@ -0,0 +1 @@
+{"*]:Ã!{)¾?'ʳ³ :!)à!*:*à:::\udbD8\\){!uÃ:{!`!?`¾¾")(¡
\ No newline at end of file
diff --git a/test/core/json/corpus/a72c3b9cc71eb7f0e0e4dabcd2dcd2b997f21c07 b/test/core/json/corpus/a72c3b9cc71eb7f0e0e4dabcd2dcd2b997f21c07
new file mode 100644
index 0000000..30b2379
--- /dev/null
+++ b/test/core/json/corpus/a72c3b9cc71eb7f0e0e4dabcd2dcd2b997f21c07
@@ -0,0 +1 @@
+0.9 }G3
\ No newline at end of file
diff --git a/test/core/json/corpus/a749d24bac55bc19465acc92b12244c56ca0f20d b/test/core/json/corpus/a749d24bac55bc19465acc92b12244c56ca0f20d
new file mode 100644
index 0000000..0fc6abd
--- /dev/null
+++ b/test/core/json/corpus/a749d24bac55bc19465acc92b12244c56ca0f20d
@@ -0,0 +1 @@
+}G3
\ No newline at end of file
diff --git a/test/core/json/corpus/a78009ff8b3f4d722ee0eb84795e857e74a58aea b/test/core/json/corpus/a78009ff8b3f4d722ee0eb84795e857e74a58aea
new file mode 100644
index 0000000..6f1758e
--- /dev/null
+++ b/test/core/json/corpus/a78009ff8b3f4d722ee0eb84795e857e74a58aea
@@ -0,0 +1 @@
+3836278E344;2E;))
\ No newline at end of file
diff --git a/test/core/json/corpus/a7ae4b16677806d78d0016c276b6722eba8eef3c b/test/core/json/corpus/a7ae4b16677806d78d0016c276b6722eba8eef3c
new file mode 100644
index 0000000..a42916a
--- /dev/null
+++ b/test/core/json/corpus/a7ae4b16677806d78d0016c276b6722eba8eef3c
@@ -0,0 +1 @@
+0.724790.Ü32996  
\ No newline at end of file
diff --git a/test/core/json/corpus/a806f43dd48e35e75c27814c13a2a96c12449bd1 b/test/core/json/corpus/a806f43dd48e35e75c27814c13a2a96c12449bd1
new file mode 100644
index 0000000..91725db
--- /dev/null
+++ b/test/core/json/corpus/a806f43dd48e35e75c27814c13a2a96c12449bd1
@@ -0,0 +1 @@
+[2.1491
\ No newline at end of file
diff --git a/test/core/json/corpus/a90a858013f90d2a94e0d62a7156ffd6848bf238 b/test/core/json/corpus/a90a858013f90d2a94e0d62a7156ffd6848bf238
new file mode 100644
index 0000000..cf6637a
--- /dev/null
+++ b/test/core/json/corpus/a90a858013f90d2a94e0d62a7156ffd6848bf238
@@ -0,0 +1 @@
+[{"ˆÃ\n5{)!:*]){
\ No newline at end of file
diff --git a/test/core/json/corpus/a94bfbfe16d026b52d7f73cf78fdf7d6a6c5c58b b/test/core/json/corpus/a94bfbfe16d026b52d7f73cf78fdf7d6a6c5c58b
new file mode 100644
index 0000000..6678fba
--- /dev/null
+++ b/test/core/json/corpus/a94bfbfe16d026b52d7f73cf78fdf7d6a6c5c58b
Binary files differ
diff --git a/test/core/json/corpus/a9718f029d11a9335ef596cbd42794de5b0b18b5 b/test/core/json/corpus/a9718f029d11a9335ef596cbd42794de5b0b18b5
new file mode 100644
index 0000000..70a969b
--- /dev/null
+++ b/test/core/json/corpus/a9718f029d11a9335ef596cbd42794de5b0b18b5
@@ -0,0 +1 @@
+0.9 
\ No newline at end of file
diff --git a/test/core/json/corpus/aa6e08a488d1ed00aa51f20c2477fc89e7b0a852 b/test/core/json/corpus/aa6e08a488d1ed00aa51f20c2477fc89e7b0a852
new file mode 100644
index 0000000..9794ac1
--- /dev/null
+++ b/test/core/json/corpus/aa6e08a488d1ed00aa51f20c2477fc89e7b0a852
@@ -0,0 +1,2 @@
+[{
+"ˆÃ" :"ˆÃ"
\ No newline at end of file
diff --git a/test/core/json/corpus/aaa038513c192fec501e4e7302156872ce2fde37 b/test/core/json/corpus/aaa038513c192fec501e4e7302156872ce2fde37
new file mode 100644
index 0000000..3959c2e
--- /dev/null
+++ b/test/core/json/corpus/aaa038513c192fec501e4e7302156872ce2fde37
@@ -0,0 +1,2 @@
+-2:
+p}5
\ No newline at end of file
diff --git a/test/core/json/corpus/ac2686c095a5a1c92a1d4209a6c287778720c86d b/test/core/json/corpus/ac2686c095a5a1c92a1d4209a6c287778720c86d
new file mode 100644
index 0000000..f02f0b8
--- /dev/null
+++ b/test/core/json/corpus/ac2686c095a5a1c92a1d4209a6c287778720c86d
@@ -0,0 +1 @@
+[2.3
\ No newline at end of file
diff --git a/test/core/json/corpus/ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4 b/test/core/json/corpus/ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4
new file mode 100644
index 0000000..7813681
--- /dev/null
+++ b/test/core/json/corpus/ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4
@@ -0,0 +1 @@
+5
\ No newline at end of file
diff --git a/test/core/json/corpus/ac9231da4082430afe8f4d40127814c613648d8e b/test/core/json/corpus/ac9231da4082430afe8f4d40127814c613648d8e
new file mode 100644
index 0000000..501a6bb
--- /dev/null
+++ b/test/core/json/corpus/ac9231da4082430afe8f4d40127814c613648d8e
@@ -0,0 +1 @@
+	
\ No newline at end of file
diff --git a/test/core/json/corpus/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc b/test/core/json/corpus/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/test/core/json/corpus/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc
@@ -0,0 +1 @@
+
diff --git a/test/core/json/corpus/aff25e569bd8c93157e08cd18ebcd896438e34c9 b/test/core/json/corpus/aff25e569bd8c93157e08cd18ebcd896438e34c9
new file mode 100644
index 0000000..ca42430
--- /dev/null
+++ b/test/core/json/corpus/aff25e569bd8c93157e08cd18ebcd896438e34c9
@@ -0,0 +1 @@
+{"( \!'(\'!
\ No newline at end of file
diff --git a/test/core/json/corpus/affced8168ec801de89deac663f708f0c96cf1a4 b/test/core/json/corpus/affced8168ec801de89deac663f708f0c96cf1a4
new file mode 100644
index 0000000..3579fbd
--- /dev/null
+++ b/test/core/json/corpus/affced8168ec801de89deac663f708f0c96cf1a4
@@ -0,0 +1 @@
+t92 \'862E517;)
\ No newline at end of file
diff --git a/test/core/json/corpus/b015dfc2f62b640d7c25adab7b38c5fcb5cb64c8 b/test/core/json/corpus/b015dfc2f62b640d7c25adab7b38c5fcb5cb64c8
new file mode 100644
index 0000000..d5ffeff
--- /dev/null
+++ b/test/core/json/corpus/b015dfc2f62b640d7c25adab7b38c5fcb5cb64c8
@@ -0,0 +1 @@
+58E+³4y;0)ˆ	)!Ã
\ No newline at end of file
diff --git a/test/core/json/corpus/b021dd7cd98b63092685ea092df0dc01c8f63334 b/test/core/json/corpus/b021dd7cd98b63092685ea092df0dc01c8f63334
new file mode 100644
index 0000000..43789b2
--- /dev/null
+++ b/test/core/json/corpus/b021dd7cd98b63092685ea092df0dc01c8f63334
@@ -0,0 +1 @@
+{"*]:Ã!{)¾?'ʳ³ :*!à):!*à:::\udbD8\u813e12)!{Ã:{!`!?
\ No newline at end of file
diff --git a/test/core/json/corpus/b17485b8bdec8809b3819a83753ca893871df403 b/test/core/json/corpus/b17485b8bdec8809b3819a83753ca893871df403
new file mode 100644
index 0000000..375ad53
--- /dev/null
+++ b/test/core/json/corpus/b17485b8bdec8809b3819a83753ca893871df403
@@ -0,0 +1 @@
+0,Ó)
\ No newline at end of file
diff --git a/test/core/json/corpus/b32ef51eca9c6c658e6fb75fdf96bbba066404e7 b/test/core/json/corpus/b32ef51eca9c6c658e6fb75fdf96bbba066404e7
new file mode 100644
index 0000000..6283767
--- /dev/null
+++ b/test/core/json/corpus/b32ef51eca9c6c658e6fb75fdf96bbba066404e7
@@ -0,0 +1 @@
+fals%)
\ No newline at end of file
diff --git a/test/core/json/corpus/b3f0c7f6bb763af1be91d9e74eabfeb199dc1f1f b/test/core/json/corpus/b3f0c7f6bb763af1be91d9e74eabfeb199dc1f1f
new file mode 100644
index 0000000..dec2bf5
--- /dev/null
+++ b/test/core/json/corpus/b3f0c7f6bb763af1be91d9e74eabfeb199dc1f1f
@@ -0,0 +1 @@
+19
\ No newline at end of file
diff --git a/test/core/json/corpus/b45a1635ec526bcc890f9d735976704e516c5f19 b/test/core/json/corpus/b45a1635ec526bcc890f9d735976704e516c5f19
new file mode 100644
index 0000000..5df3969
--- /dev/null
+++ b/test/core/json/corpus/b45a1635ec526bcc890f9d735976704e516c5f19
@@ -0,0 +1 @@
+{"":(!'(\'!
\ No newline at end of file
diff --git a/test/core/json/corpus/b50ce51a7baa28cd298ebd05b4a3b9b70f9d4370 b/test/core/json/corpus/b50ce51a7baa28cd298ebd05b4a3b9b70f9d4370
new file mode 100644
index 0000000..cb9a114
--- /dev/null
+++ b/test/core/json/corpus/b50ce51a7baa28cd298ebd05b4a3b9b70f9d4370
@@ -0,0 +1 @@
+832834E4E;6;))
\ No newline at end of file
diff --git a/test/core/json/corpus/b5126721812b925426b30d283d2bb8b6969f230a b/test/core/json/corpus/b5126721812b925426b30d283d2bb8b6969f230a
new file mode 100644
index 0000000..fdd7734
--- /dev/null
+++ b/test/core/json/corpus/b5126721812b925426b30d283d2bb8b6969f230a
@@ -0,0 +1 @@
+5E9	3'Á8)232;)6
\ No newline at end of file
diff --git a/test/core/json/corpus/b57af943a3ee411bffeaa3872eec9c6fb01569a4 b/test/core/json/corpus/b57af943a3ee411bffeaa3872eec9c6fb01569a4
new file mode 100644
index 0000000..b6970dd
--- /dev/null
+++ b/test/core/json/corpus/b57af943a3ee411bffeaa3872eec9c6fb01569a4
Binary files differ
diff --git a/test/core/json/corpus/b5abf6fd22ed0f852781de35d043059d0f86f3cd b/test/core/json/corpus/b5abf6fd22ed0f852781de35d043059d0f86f3cd
new file mode 100644
index 0000000..7bf416f
--- /dev/null
+++ b/test/core/json/corpus/b5abf6fd22ed0f852781de35d043059d0f86f3cd
@@ -0,0 +1 @@
+0,f')
\ No newline at end of file
diff --git a/test/core/json/corpus/b6589fc6ab0dc82cf12099d1c2d40ab994e8410c b/test/core/json/corpus/b6589fc6ab0dc82cf12099d1c2d40ab994e8410c
new file mode 100644
index 0000000..c227083
--- /dev/null
+++ b/test/core/json/corpus/b6589fc6ab0dc82cf12099d1c2d40ab994e8410c
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/test/core/json/corpus/b6f19238d2b04c5b86a17369093dafda34f332e7 b/test/core/json/corpus/b6f19238d2b04c5b86a17369093dafda34f332e7
new file mode 100644
index 0000000..fb1edb4
--- /dev/null
+++ b/test/core/json/corpus/b6f19238d2b04c5b86a17369093dafda34f332e7
@@ -0,0 +1,2 @@
+")
+è"ˆÃ{)!:*¾;!'ʳ³!!*!à):!*"ˆÃ{)!:*])à
\ No newline at end of file
diff --git a/test/core/json/corpus/b858cb282617fb0956d960215c8e84d1ccf909c6 b/test/core/json/corpus/b858cb282617fb0956d960215c8e84d1ccf909c6
new file mode 100644
index 0000000..0519ecb
--- /dev/null
+++ b/test/core/json/corpus/b858cb282617fb0956d960215c8e84d1ccf909c6
@@ -0,0 +1 @@
+ 
\ No newline at end of file
diff --git a/test/core/json/corpus/b9c38fad09c80db7781fefbe51039752de575ecc b/test/core/json/corpus/b9c38fad09c80db7781fefbe51039752de575ecc
new file mode 100644
index 0000000..c16d3bc
--- /dev/null
+++ b/test/core/json/corpus/b9c38fad09c80db7781fefbe51039752de575ecc
@@ -0,0 +1 @@
+3e45!01860
\ No newline at end of file
diff --git a/test/core/json/corpus/bb407c8992800444201dccfe744dac49c0295fde b/test/core/json/corpus/bb407c8992800444201dccfe744dac49c0295fde
new file mode 100644
index 0000000..7984a6f
--- /dev/null
+++ b/test/core/json/corpus/bb407c8992800444201dccfe744dac49c0295fde
@@ -0,0 +1 @@
+{"!(!\t'
\ No newline at end of file
diff --git a/test/core/json/corpus/bc335734f73502b92d2bd3587259ce915985f0ee b/test/core/json/corpus/bc335734f73502b92d2bd3587259ce915985f0ee
new file mode 100644
index 0000000..75ce6ce
--- /dev/null
+++ b/test/core/json/corpus/bc335734f73502b92d2bd3587259ce915985f0ee
@@ -0,0 +1 @@
+0.6995 
\ No newline at end of file
diff --git a/test/core/json/corpus/bd113c2c8a2328e3674c680c7cff829a6c8ab924 b/test/core/json/corpus/bd113c2c8a2328e3674c680c7cff829a6c8ab924
new file mode 100644
index 0000000..08894ee
--- /dev/null
+++ b/test/core/json/corpus/bd113c2c8a2328e3674c680c7cff829a6c8ab924
@@ -0,0 +1 @@
+[2.10;2;®
\ No newline at end of file
diff --git a/test/core/json/corpus/be051d58015d4af1977a5dfd14ef3fd070ecc9d2 b/test/core/json/corpus/be051d58015d4af1977a5dfd14ef3fd070ecc9d2
new file mode 100644
index 0000000..c56ae0e
--- /dev/null
+++ b/test/core/json/corpus/be051d58015d4af1977a5dfd14ef3fd070ecc9d2
@@ -0,0 +1 @@
+9!
\ No newline at end of file
diff --git a/test/core/json/corpus/be461a0cd1fda052a69c3fd94f8cf5f6f86afa34 b/test/core/json/corpus/be461a0cd1fda052a69c3fd94f8cf5f6f86afa34
new file mode 100644
index 0000000..3ca9062
--- /dev/null
+++ b/test/core/json/corpus/be461a0cd1fda052a69c3fd94f8cf5f6f86afa34
@@ -0,0 +1 @@
+84
\ No newline at end of file
diff --git a/test/core/json/corpus/bef524502f8dbbc45af717ece01ec88edd7f903b b/test/core/json/corpus/bef524502f8dbbc45af717ece01ec88edd7f903b
new file mode 100644
index 0000000..2a42b12
--- /dev/null
+++ b/test/core/json/corpus/bef524502f8dbbc45af717ece01ec88edd7f903b
@@ -0,0 +1 @@
+13e108560
\ No newline at end of file
diff --git a/test/core/json/corpus/bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f b/test/core/json/corpus/bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/test/core/json/corpus/bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/test/core/json/corpus/c0b6a90832b78ed5f6d129d3640c612540527c85 b/test/core/json/corpus/c0b6a90832b78ed5f6d129d3640c612540527c85
new file mode 100644
index 0000000..a03cfc1
--- /dev/null
+++ b/test/core/json/corpus/c0b6a90832b78ed5f6d129d3640c612540527c85
@@ -0,0 +1 @@
+{"'!\u3Â:Š
\ No newline at end of file
diff --git a/test/core/json/corpus/c18d315f0d35849b2aae4a47cab4608204b85d76 b/test/core/json/corpus/c18d315f0d35849b2aae4a47cab4608204b85d76
new file mode 100644
index 0000000..d082c57
--- /dev/null
+++ b/test/core/json/corpus/c18d315f0d35849b2aae4a47cab4608204b85d76
@@ -0,0 +1,2 @@
+[{")
+è"ˆÃ{)!:*¾;!'ʳ³!!*!à):!*"ˆÃ{)!:*])à
\ No newline at end of file
diff --git a/test/core/json/corpus/c257fd6bc9e5254a733378ab4ddd39629c4a3069 b/test/core/json/corpus/c257fd6bc9e5254a733378ab4ddd39629c4a3069
new file mode 100644
index 0000000..b040a5e
--- /dev/null
+++ b/test/core/json/corpus/c257fd6bc9e5254a733378ab4ddd39629c4a3069
@@ -0,0 +1 @@
+13e128560
\ No newline at end of file
diff --git a/test/core/json/corpus/c2bf7f49d8f2e13a60af4473b3b3451b65b3aa9a b/test/core/json/corpus/c2bf7f49d8f2e13a60af4473b3b3451b65b3aa9a
new file mode 100644
index 0000000..7f9e4a6
--- /dev/null
+++ b/test/core/json/corpus/c2bf7f49d8f2e13a60af4473b3b3451b65b3aa9a
@@ -0,0 +1 @@
+1e+2188560
\ No newline at end of file
diff --git a/test/core/json/corpus/c308517acf6f7088634d491a1608240f83a3ac95 b/test/core/json/corpus/c308517acf6f7088634d491a1608240f83a3ac95
new file mode 100644
index 0000000..cc56474
--- /dev/null
+++ b/test/core/json/corpus/c308517acf6f7088634d491a1608240f83a3ac95
@@ -0,0 +1 @@
+0.427Ü$
\ No newline at end of file
diff --git a/test/core/json/corpus/c3badd71ef8a51b97ce93cbfe99f6778048f2128 b/test/core/json/corpus/c3badd71ef8a51b97ce93cbfe99f6778048f2128
new file mode 100644
index 0000000..4d10e08
--- /dev/null
+++ b/test/core/json/corpus/c3badd71ef8a51b97ce93cbfe99f6778048f2128
@@ -0,0 +1 @@
+3(
\ No newline at end of file
diff --git a/test/core/json/corpus/c482a632702ae7f532d126e70149dda4fadc3cd7 b/test/core/json/corpus/c482a632702ae7f532d126e70149dda4fadc3cd7
new file mode 100644
index 0000000..e041368
--- /dev/null
+++ b/test/core/json/corpus/c482a632702ae7f532d126e70149dda4fadc3cd7
@@ -0,0 +1 @@
+0.2996 
\ No newline at end of file
diff --git a/test/core/json/corpus/c541bb86e55b98e083b141114066f9c17d853374 b/test/core/json/corpus/c541bb86e55b98e083b141114066f9c17d853374
new file mode 100644
index 0000000..8162989
--- /dev/null
+++ b/test/core/json/corpus/c541bb86e55b98e083b141114066f9c17d853374
@@ -0,0 +1 @@
+[[["ˆÃ{)!:*¾;?'ʳ³!!*!à):!*à:::\u06099.y2db)8ˆÃ!3;!‡:{!`!.7;?
\ No newline at end of file
diff --git a/test/core/json/corpus/c5b50b9015b6aaedd7eb1077b1204858f837b53c b/test/core/json/corpus/c5b50b9015b6aaedd7eb1077b1204858f837b53c
new file mode 100644
index 0000000..deb26ed
--- /dev/null
+++ b/test/core/json/corpus/c5b50b9015b6aaedd7eb1077b1204858f837b53c
@@ -0,0 +1 @@
+"',!\u65E8850{2312;):ˆ)!*?'¾Ê³0.³!!ª!À):*!à::8!9:\udbD8\u82510'
\ No newline at end of file
diff --git a/test/core/json/corpus/c62ef0dbd1350da9ea5a32e56672d385837643e7 b/test/core/json/corpus/c62ef0dbd1350da9ea5a32e56672d385837643e7
new file mode 100644
index 0000000..f7ac687
--- /dev/null
+++ b/test/core/json/corpus/c62ef0dbd1350da9ea5a32e56672d385837643e7
Binary files differ
diff --git a/test/core/json/corpus/c7a34d6d49e1da1ccd490350c2df3a168ed09ae8 b/test/core/json/corpus/c7a34d6d49e1da1ccd490350c2df3a168ed09ae8
new file mode 100644
index 0000000..1d06e43
--- /dev/null
+++ b/test/core/json/corpus/c7a34d6d49e1da1ccd490350c2df3a168ed09ae8
@@ -0,0 +1,3 @@
+{
+"ˆ[2":{}
+5‰Ã["
\ No newline at end of file
diff --git a/test/core/json/corpus/c88c4bec8d440c56d3ea7abce39276f0927dbe0a b/test/core/json/corpus/c88c4bec8d440c56d3ea7abce39276f0927dbe0a
new file mode 100644
index 0000000..9442128
--- /dev/null
+++ b/test/core/json/corpus/c88c4bec8d440c56d3ea7abce39276f0927dbe0a
@@ -0,0 +1 @@
+33(
\ No newline at end of file
diff --git a/test/core/json/corpus/c92f147bfc034003ac42ed9e62a16c84102ab417 b/test/core/json/corpus/c92f147bfc034003ac42ed9e62a16c84102ab417
new file mode 100644
index 0000000..3fae4b1
--- /dev/null
+++ b/test/core/json/corpus/c92f147bfc034003ac42ed9e62a16c84102ab417
@@ -0,0 +1 @@
+[[2.193,]4ˆÃ"*("
\ No newline at end of file
diff --git a/test/core/json/corpus/c96b0fe6034668edf37ef0f5f391d5107953dc06 b/test/core/json/corpus/c96b0fe6034668edf37ef0f5f391d5107953dc06
new file mode 100644
index 0000000..975bc39
--- /dev/null
+++ b/test/core/json/corpus/c96b0fe6034668edf37ef0f5f391d5107953dc06
@@ -0,0 +1 @@
+8162E517;)
\ No newline at end of file
diff --git a/test/core/json/corpus/cac74aa5d7aab7fce0253f00c1a025980c1f9b7a b/test/core/json/corpus/cac74aa5d7aab7fce0253f00c1a025980c1f9b7a
new file mode 100644
index 0000000..e2c8b2a
--- /dev/null
+++ b/test/core/json/corpus/cac74aa5d7aab7fce0253f00c1a025980c1f9b7a
@@ -0,0 +1 @@
+ \'
\ No newline at end of file
diff --git a/test/core/json/corpus/caea0a0e6d8708cf682eaa446c344da56a7d5515 b/test/core/json/corpus/caea0a0e6d8708cf682eaa446c344da56a7d5515
new file mode 100644
index 0000000..767d851
--- /dev/null
+++ b/test/core/json/corpus/caea0a0e6d8708cf682eaa446c344da56a7d5515
@@ -0,0 +1 @@
+"!2}G!\'')y3
\ No newline at end of file
diff --git a/test/core/json/corpus/cc8a3dd2678d4b400ad630f402012b894e841b05 b/test/core/json/corpus/cc8a3dd2678d4b400ad630f402012b894e841b05
new file mode 100644
index 0000000..f115f81
--- /dev/null
+++ b/test/core/json/corpus/cc8a3dd2678d4b400ad630f402012b894e841b05
@@ -0,0 +1 @@
+"9![\f
\ No newline at end of file
diff --git a/test/core/json/corpus/cd851bec7adad52f79777fb9347d5fd2f9486aa7 b/test/core/json/corpus/cd851bec7adad52f79777fb9347d5fd2f9486aa7
new file mode 100644
index 0000000..0f8b1eb
--- /dev/null
+++ b/test/core/json/corpus/cd851bec7adad52f79777fb9347d5fd2f9486aa7
@@ -0,0 +1 @@
+{"',!\u@':Š
\ No newline at end of file
diff --git a/test/core/json/corpus/ce3899b62ba3efe00eb31ddad2861ffe16a30d06 b/test/core/json/corpus/ce3899b62ba3efe00eb31ddad2861ffe16a30d06
new file mode 100644
index 0000000..91bd82a
--- /dev/null
+++ b/test/core/json/corpus/ce3899b62ba3efe00eb31ddad2861ffe16a30d06
@@ -0,0 +1 @@
+[[["ˆÃ{)!:*¾;?'ʳ³!!*!à):!*à:::\\06099.y2db)8ˆÃ!3;!‡:{!`!.7;?
\ No newline at end of file
diff --git a/test/core/json/corpus/ce8b76fdcdbf1c951afc2b115be9acc8a6358b32 b/test/core/json/corpus/ce8b76fdcdbf1c951afc2b115be9acc8a6358b32
new file mode 100644
index 0000000..8ecd07a
--- /dev/null
+++ b/test/core/json/corpus/ce8b76fdcdbf1c951afc2b115be9acc8a6358b32
@@ -0,0 +1 @@
+8324E512;)
\ No newline at end of file
diff --git a/test/core/json/corpus/cec87b67871fc7a59652bc3546fbbb68e4d31e28 b/test/core/json/corpus/cec87b67871fc7a59652bc3546fbbb68e4d31e28
new file mode 100644
index 0000000..56e1cf4
--- /dev/null
+++ b/test/core/json/corpus/cec87b67871fc7a59652bc3546fbbb68e4d31e28
@@ -0,0 +1,2 @@
+[{
+"ˆÃ" :"ˆÃ!{)!:","ˆˆÃÃ"
\ No newline at end of file
diff --git a/test/core/json/corpus/cf32406111908544e504c84731147f072cdf2fbd b/test/core/json/corpus/cf32406111908544e504c84731147f072cdf2fbd
new file mode 100644
index 0000000..a0d1ef1
--- /dev/null
+++ b/test/core/json/corpus/cf32406111908544e504c84731147f072cdf2fbd
@@ -0,0 +1 @@
+620
\ No newline at end of file
diff --git a/test/core/json/corpus/cf35dc76bf9a2052636c1ecc92942161830dcdc3 b/test/core/json/corpus/cf35dc76bf9a2052636c1ecc92942161830dcdc3
new file mode 100644
index 0000000..2401421
--- /dev/null
+++ b/test/core/json/corpus/cf35dc76bf9a2052636c1ecc92942161830dcdc3
@@ -0,0 +1 @@
+	3Á6
\ No newline at end of file
diff --git a/test/core/json/corpus/cf6a5e6bfe4f15b43e411dd2782e10f1670c9767 b/test/core/json/corpus/cf6a5e6bfe4f15b43e411dd2782e10f1670c9767
new file mode 100644
index 0000000..f4c0d10
--- /dev/null
+++ b/test/core/json/corpus/cf6a5e6bfe4f15b43e411dd2782e10f1670c9767
@@ -0,0 +1 @@
+30.5E8;!4;
\ No newline at end of file
diff --git a/test/core/json/corpus/cfc45616f5f0e7c25df91f6984ff5f6f1648beab b/test/core/json/corpus/cfc45616f5f0e7c25df91f6984ff5f6f1648beab
new file mode 100644
index 0000000..77db9a6
--- /dev/null
+++ b/test/core/json/corpus/cfc45616f5f0e7c25df91f6984ff5f6f1648beab
@@ -0,0 +1 @@
+{"',!\u65E8850{2312;):ˆ)!*?'¾Ê³³!!ª!À):*!à::8!9:\udbD8\6'
\ No newline at end of file
diff --git a/test/core/json/corpus/cff891e5858ae68d08ecc8470ca6a68c9438bfa3 b/test/core/json/corpus/cff891e5858ae68d08ecc8470ca6a68c9438bfa3
new file mode 100644
index 0000000..9ef39eb
--- /dev/null
+++ b/test/core/json/corpus/cff891e5858ae68d08ecc8470ca6a68c9438bfa3
@@ -0,0 +1 @@
+{"*]:Ë!{)¾?'ʳ³ !*!à):!*à:::\udbD8 !)!{Ã:{!`!?`¾¾"(¡
\ No newline at end of file
diff --git a/test/core/json/corpus/cfff4e9d08cba81b663dd1999710008342851e19 b/test/core/json/corpus/cfff4e9d08cba81b663dd1999710008342851e19
new file mode 100644
index 0000000..eb4d5f1
--- /dev/null
+++ b/test/core/json/corpus/cfff4e9d08cba81b663dd1999710008342851e19
@@ -0,0 +1 @@
+nul*:
\ No newline at end of file
diff --git a/test/core/json/corpus/crash-f21867fe8b6df0b54c13e2e6e613dce871ecf0f0 b/test/core/json/corpus/crash-f21867fe8b6df0b54c13e2e6e613dce871ecf0f0
new file mode 100644
index 0000000..6d3bcfe
--- /dev/null
+++ b/test/core/json/corpus/crash-f21867fe8b6df0b54c13e2e6e613dce871ecf0f0
@@ -0,0 +1 @@
+ˆ)Ã!:{"*¾?'ʳ³!!*!à):!*à:::\udbD8ˆ)Ã!:{!`!?`¾¾!?'!*m,');…'`
\ No newline at end of file
diff --git a/test/core/json/corpus/d1db03c626fb16c3b9cd44cc38cf40ebd355a194 b/test/core/json/corpus/d1db03c626fb16c3b9cd44cc38cf40ebd355a194
new file mode 100644
index 0000000..f292b52
--- /dev/null
+++ b/test/core/json/corpus/d1db03c626fb16c3b9cd44cc38cf40ebd355a194
@@ -0,0 +1 @@
+8324E684;)
\ No newline at end of file
diff --git a/test/core/json/corpus/d85ca051da784c0441898c5affbf11a2ae8f56bc b/test/core/json/corpus/d85ca051da784c0441898c5affbf11a2ae8f56bc
new file mode 100644
index 0000000..921f250
--- /dev/null
+++ b/test/core/json/corpus/d85ca051da784c0441898c5affbf11a2ae8f56bc
@@ -0,0 +1 @@
+[[["ˆÃ{)!:*¾;?'ʳ³!!*!à):!*à:::\u0049.y2db)8ˆÃ!3;!‡7`!{:!.;?
\ No newline at end of file
diff --git a/test/core/json/corpus/da03f536ceaf609972aa2a699687cc6f73ac0dcd b/test/core/json/corpus/da03f536ceaf609972aa2a699687cc6f73ac0dcd
new file mode 100644
index 0000000..68efa7b
--- /dev/null
+++ b/test/core/json/corpus/da03f536ceaf609972aa2a699687cc6f73ac0dcd
@@ -0,0 +1 @@
+"7 
\ No newline at end of file
diff --git a/test/core/json/corpus/da4b9237bacccdf19c0760cab7aec4a8359010b0 b/test/core/json/corpus/da4b9237bacccdf19c0760cab7aec4a8359010b0
new file mode 100644
index 0000000..d8263ee
--- /dev/null
+++ b/test/core/json/corpus/da4b9237bacccdf19c0760cab7aec4a8359010b0
@@ -0,0 +1 @@
+2
\ No newline at end of file
diff --git a/test/core/json/corpus/dcc45e405208d7a2db33d0b5b9da2a2f1b034957 b/test/core/json/corpus/dcc45e405208d7a2db33d0b5b9da2a2f1b034957
new file mode 100644
index 0000000..2f58c32
--- /dev/null
+++ b/test/core/json/corpus/dcc45e405208d7a2db33d0b5b9da2a2f1b034957
@@ -0,0 +1 @@
+0.5!
\ No newline at end of file
diff --git a/test/core/json/corpus/dcc60d3aaa1fc4d00201a3512284fcb79b5b68ef b/test/core/json/corpus/dcc60d3aaa1fc4d00201a3512284fcb79b5b68ef
new file mode 100644
index 0000000..9e15a74
--- /dev/null
+++ b/test/core/json/corpus/dcc60d3aaa1fc4d00201a3512284fcb79b5b68ef
Binary files differ
diff --git a/test/core/json/corpus/dd0567ae57bf3cc85891a1ca988c2945d9186678 b/test/core/json/corpus/dd0567ae57bf3cc85891a1ca988c2945d9186678
new file mode 100644
index 0000000..0e05e02
--- /dev/null
+++ b/test/core/json/corpus/dd0567ae57bf3cc85891a1ca988c2945d9186678
@@ -0,0 +1 @@
+"',!\u65E8850{2312;):ˆ)!*?'¾Ê³0.³!!ª!À):*!à::8!9:\udbD8\uD8250'
\ No newline at end of file
diff --git a/test/core/json/corpus/dd890a5a32e9f0489c6c77695f2155041f00fc9a b/test/core/json/corpus/dd890a5a32e9f0489c6c77695f2155041f00fc9a
new file mode 100644
index 0000000..86d708f
--- /dev/null
+++ b/test/core/json/corpus/dd890a5a32e9f0489c6c77695f2155041f00fc9a
@@ -0,0 +1 @@
+{"!!\''
\ No newline at end of file
diff --git a/test/core/json/corpus/df88e2baf7b76ffb2e94b9da57fd8d137f44b1ef b/test/core/json/corpus/df88e2baf7b76ffb2e94b9da57fd8d137f44b1ef
new file mode 100644
index 0000000..3c61ef6
--- /dev/null
+++ b/test/core/json/corpus/df88e2baf7b76ffb2e94b9da57fd8d137f44b1ef
@@ -0,0 +1 @@
+"ˆÃ{)!:*¾;?'ʳ³!!*!à):!*à:::\)db)8ˆÃ!‡:{!`!?`¾¾!'?'!*m,');…'`
\ No newline at end of file
diff --git a/test/core/json/corpus/e00ee378c3f6e0b3cd89bd6e7517478d093f73dd b/test/core/json/corpus/e00ee378c3f6e0b3cd89bd6e7517478d093f73dd
new file mode 100644
index 0000000..fb9c6f8
--- /dev/null
+++ b/test/core/json/corpus/e00ee378c3f6e0b3cd89bd6e7517478d093f73dd
@@ -0,0 +1 @@
+834e;)
\ No newline at end of file
diff --git a/test/core/json/corpus/e0c124e90d068e2a70a3e148052869033453ec58 b/test/core/json/corpus/e0c124e90d068e2a70a3e148052869033453ec58
new file mode 100644
index 0000000..e05343f
--- /dev/null
+++ b/test/core/json/corpus/e0c124e90d068e2a70a3e148052869033453ec58
@@ -0,0 +1 @@
+27e7¤2:60
\ No newline at end of file
diff --git a/test/core/json/corpus/e0d87b1f3e54e5adc5c2205f9e14772822a25766 b/test/core/json/corpus/e0d87b1f3e54e5adc5c2205f9e14772822a25766
new file mode 100644
index 0000000..83c6ab5
--- /dev/null
+++ b/test/core/json/corpus/e0d87b1f3e54e5adc5c2205f9e14772822a25766
@@ -0,0 +1 @@
+[{"ˆÃ\5{)!:*]){
\ No newline at end of file
diff --git a/test/core/json/corpus/e1199df649697c570db5d6b2ea09d755eddd32b7 b/test/core/json/corpus/e1199df649697c570db5d6b2ea09d755eddd32b7
new file mode 100644
index 0000000..adac51f
--- /dev/null
+++ b/test/core/json/corpus/e1199df649697c570db5d6b2ea09d755eddd32b7
@@ -0,0 +1 @@
+[[0.193;]4*
\ No newline at end of file
diff --git a/test/core/json/corpus/e235f6f2a8b6a22117f1baa932fb6c69799e1136 b/test/core/json/corpus/e235f6f2a8b6a22117f1baa932fb6c69799e1136
new file mode 100644
index 0000000..f3f2d8c
--- /dev/null
+++ b/test/core/json/corpus/e235f6f2a8b6a22117f1baa932fb6c69799e1136
@@ -0,0 +1 @@
+[1.197;
\ No newline at end of file
diff --git a/test/core/json/corpus/e3a654055a867ae62d8e68fa2c410228ac55cb6d b/test/core/json/corpus/e3a654055a867ae62d8e68fa2c410228ac55cb6d
new file mode 100644
index 0000000..428fe54
--- /dev/null
+++ b/test/core/json/corpus/e3a654055a867ae62d8e68fa2c410228ac55cb6d
@@ -0,0 +1 @@
+"!!\''
\ No newline at end of file
diff --git a/test/core/json/corpus/e3c680aac46b9c46392e3b2c43ecdcc1547f2023 b/test/core/json/corpus/e3c680aac46b9c46392e3b2c43ecdcc1547f2023
new file mode 100644
index 0000000..53f048b
--- /dev/null
+++ b/test/core/json/corpus/e3c680aac46b9c46392e3b2c43ecdcc1547f2023
@@ -0,0 +1 @@
+[}G3
\ No newline at end of file
diff --git a/test/core/json/corpus/e3d134b35cc25a4861d90023c95988ec6103ddd5 b/test/core/json/corpus/e3d134b35cc25a4861d90023c95988ec6103ddd5
new file mode 100644
index 0000000..a9f28d4
--- /dev/null
+++ b/test/core/json/corpus/e3d134b35cc25a4861d90023c95988ec6103ddd5
@@ -0,0 +1 @@
+"ˆÃ{)!:*¾;!'ʳ³!!*!à):!*à::\udb)8ˆÃ!‡:{`!?`¾¾!?'!*m,');…'`
\ No newline at end of file
diff --git a/test/core/json/corpus/e3ff65de4b1622315c3b34b7a5e39bffb275489d b/test/core/json/corpus/e3ff65de4b1622315c3b34b7a5e39bffb275489d
new file mode 100644
index 0000000..d188dbf
--- /dev/null
+++ b/test/core/json/corpus/e3ff65de4b1622315c3b34b7a5e39bffb275489d
@@ -0,0 +1 @@
+[2.19
\ No newline at end of file
diff --git a/test/core/json/corpus/e4a4085cc31476f5de9047422851d8ccf86339df b/test/core/json/corpus/e4a4085cc31476f5de9047422851d8ccf86339df
new file mode 100644
index 0000000..e673b6d
--- /dev/null
+++ b/test/core/json/corpus/e4a4085cc31476f5de9047422851d8ccf86339df
@@ -0,0 +1 @@
+{"',!\u@':Š
\ No newline at end of file
diff --git a/test/core/json/corpus/e4e3c69da200af932c8a79fa055d7aeea28eb1d1 b/test/core/json/corpus/e4e3c69da200af932c8a79fa055d7aeea28eb1d1
new file mode 100644
index 0000000..fa71dbe
--- /dev/null
+++ b/test/core/json/corpus/e4e3c69da200af932c8a79fa055d7aeea28eb1d1
@@ -0,0 +1 @@
+[2."ˆÃ!{)!:",ˆÃ
\ No newline at end of file
diff --git a/test/core/json/corpus/e6c3dd630428fd54834172b8fd2735fed9416da4 b/test/core/json/corpus/e6c3dd630428fd54834172b8fd2735fed9416da4
new file mode 100644
index 0000000..2b82dfe
--- /dev/null
+++ b/test/core/json/corpus/e6c3dd630428fd54834172b8fd2735fed9416da4
@@ -0,0 +1 @@
+60
\ No newline at end of file
diff --git a/test/core/json/corpus/e71eb37fca2070521e1e07c503c2bcd6445b35ea b/test/core/json/corpus/e71eb37fca2070521e1e07c503c2bcd6445b35ea
new file mode 100644
index 0000000..67a6628
--- /dev/null
+++ b/test/core/json/corpus/e71eb37fca2070521e1e07c503c2bcd6445b35ea
Binary files differ
diff --git a/test/core/json/corpus/e760e6e22ae8cd1ea78fe28b5eb1f3d7b5fdc536 b/test/core/json/corpus/e760e6e22ae8cd1ea78fe28b5eb1f3d7b5fdc536
new file mode 100644
index 0000000..3e747cc
--- /dev/null
+++ b/test/core/json/corpus/e760e6e22ae8cd1ea78fe28b5eb1f3d7b5fdc536
@@ -0,0 +1 @@
+{:ˆ)!Ã"*¾?'ʳ³!!*!à):!*à:::\udbD8ˆ)Ã!:{!`!?`¾¾!?'!*m,');…'`
\ No newline at end of file
diff --git a/test/core/json/corpus/e95ff1142118a2ca5b84935612a8a64d55360e64 b/test/core/json/corpus/e95ff1142118a2ca5b84935612a8a64d55360e64
new file mode 100644
index 0000000..ca8bbcc
--- /dev/null
+++ b/test/core/json/corpus/e95ff1142118a2ca5b84935612a8a64d55360e64
@@ -0,0 +1 @@
+"ˆÃ{)!:*¾;?'ʳ³!!*!à):!*à:::\udb)8ˆÃ!‡:{!`!?`¾¾!?'!*m,');…'`
\ No newline at end of file
diff --git a/test/core/json/corpus/e9c5e2c67930513941753c2d54591c7098c82f6c b/test/core/json/corpus/e9c5e2c67930513941753c2d54591c7098c82f6c
new file mode 100644
index 0000000..f9991b4
--- /dev/null
+++ b/test/core/json/corpus/e9c5e2c67930513941753c2d54591c7098c82f6c
@@ -0,0 +1 @@
+[3]4*
\ No newline at end of file
diff --git a/test/core/json/corpus/eb26070d17ffa908204912e75cb4313835042038 b/test/core/json/corpus/eb26070d17ffa908204912e75cb4313835042038
new file mode 100644
index 0000000..8122937
--- /dev/null
+++ b/test/core/json/corpus/eb26070d17ffa908204912e75cb4313835042038
@@ -0,0 +1 @@
+["*]:Ã!{)¾?'ʳ³!!*!à):!*à:::\udbD8ˆ){Ã!:{!`!?`¾¾"(¡
\ No newline at end of file
diff --git a/test/core/json/corpus/ebc6aee49e5ae57722df86e7fa33c420f045a449 b/test/core/json/corpus/ebc6aee49e5ae57722df86e7fa33c420f045a449
new file mode 100644
index 0000000..ee58b90
--- /dev/null
+++ b/test/core/json/corpus/ebc6aee49e5ae57722df86e7fa33c420f045a449
@@ -0,0 +1 @@
+03(
\ No newline at end of file
diff --git a/test/core/json/corpus/ed1dc11d713e7487de18ce8317b62916959206d0 b/test/core/json/corpus/ed1dc11d713e7487de18ce8317b62916959206d0
new file mode 100644
index 0000000..90e536e
--- /dev/null
+++ b/test/core/json/corpus/ed1dc11d713e7487de18ce8317b62916959206d0
@@ -0,0 +1 @@
+8324E6;)
\ No newline at end of file
diff --git a/test/core/json/corpus/ede3f66106acd7796da8b3942d029fe213058286 b/test/core/json/corpus/ede3f66106acd7796da8b3942d029fe213058286
new file mode 100644
index 0000000..69cea59
--- /dev/null
+++ b/test/core/json/corpus/ede3f66106acd7796da8b3942d029fe213058286
@@ -0,0 +1 @@
+5834E0y);)ˆ	)!Ã
\ No newline at end of file
diff --git a/test/core/json/corpus/eed7bd220cd511b6d42ce6553019266a22a3d56a b/test/core/json/corpus/eed7bd220cd511b6d42ce6553019266a22a3d56a
new file mode 100644
index 0000000..60f86bd
--- /dev/null
+++ b/test/core/json/corpus/eed7bd220cd511b6d42ce6553019266a22a3d56a
@@ -0,0 +1 @@
+0,0	
\ No newline at end of file
diff --git a/test/core/json/corpus/f090932162756b798b1a050b05e3d36a3437c4fc b/test/core/json/corpus/f090932162756b798b1a050b05e3d36a3437c4fc
new file mode 100644
index 0000000..24f98f2
--- /dev/null
+++ b/test/core/json/corpus/f090932162756b798b1a050b05e3d36a3437c4fc
@@ -0,0 +1 @@
+367
\ No newline at end of file
diff --git a/test/core/json/corpus/f1905eaa84ba6a3593ec6ac0486a5b42893c01f1 b/test/core/json/corpus/f1905eaa84ba6a3593ec6ac0486a5b42893c01f1
new file mode 100644
index 0000000..601a7b2
--- /dev/null
+++ b/test/core/json/corpus/f1905eaa84ba6a3593ec6ac0486a5b42893c01f1
@@ -0,0 +1 @@
+50{:ˆ)!Ã"*¾?'ʳ³!!*!à):!*à::8!9:\udbD8ˆ)Ã!:{!`
\ No newline at end of file
diff --git a/test/core/json/corpus/f4635fbbf765ead81a261ca152df02622e182d2c b/test/core/json/corpus/f4635fbbf765ead81a261ca152df02622e182d2c
new file mode 100644
index 0000000..30e0f2b
--- /dev/null
+++ b/test/core/json/corpus/f4635fbbf765ead81a261ca152df02622e182d2c
@@ -0,0 +1 @@
+"19
\ No newline at end of file
diff --git a/test/core/json/corpus/f46eeb1020c7c4153e742a50bc24c2c6939dab1e b/test/core/json/corpus/f46eeb1020c7c4153e742a50bc24c2c6939dab1e
new file mode 100644
index 0000000..8c0a186
--- /dev/null
+++ b/test/core/json/corpus/f46eeb1020c7c4153e742a50bc24c2c6939dab1e
@@ -0,0 +1 @@
+363
diff --git a/test/core/json/corpus/f473451610783521d51bc08cdd920ddd97f8a71f b/test/core/json/corpus/f473451610783521d51bc08cdd920ddd97f8a71f
new file mode 100644
index 0000000..b73c5ec
--- /dev/null
+++ b/test/core/json/corpus/f473451610783521d51bc08cdd920ddd97f8a71f
@@ -0,0 +1 @@
+{"*]:Ã!{)¾?'ʳ³ !*!à):!*à:::\udbD8\!)!{Ã:{!`!?`¾¾"(¡
\ No newline at end of file
diff --git a/test/core/json/corpus/f63aa599600f6e7d648c4287905e16e8e6e479fd b/test/core/json/corpus/f63aa599600f6e7d648c4287905e16e8e6e479fd
new file mode 100644
index 0000000..4b68125
--- /dev/null
+++ b/test/core/json/corpus/f63aa599600f6e7d648c4287905e16e8e6e479fd
@@ -0,0 +1 @@
+"ˆÃ{)!:"])Ã!:{"*¾?'ʳ³!!*!à):!*à:::\¾;?'ʳud
\ No newline at end of file
diff --git a/test/core/json/corpus/f667dcf1c06e87db2dc49d86ea1c285e796f8f8c b/test/core/json/corpus/f667dcf1c06e87db2dc49d86ea1c285e796f8f8c
new file mode 100644
index 0000000..b6dfbd5
--- /dev/null
+++ b/test/core/json/corpus/f667dcf1c06e87db2dc49d86ea1c285e796f8f8c
@@ -0,0 +1 @@
+813e124280
\ No newline at end of file
diff --git a/test/core/json/corpus/f8d0f85975e49b959799cc52847110cc940b9db1 b/test/core/json/corpus/f8d0f85975e49b959799cc52847110cc940b9db1
new file mode 100644
index 0000000..0c7f592
--- /dev/null
+++ b/test/core/json/corpus/f8d0f85975e49b959799cc52847110cc940b9db1
@@ -0,0 +1 @@
+604
\ No newline at end of file
diff --git a/test/core/json/corpus/f92c47e35da42d79a48beff54b93cd28f55f05fb b/test/core/json/corpus/f92c47e35da42d79a48beff54b93cd28f55f05fb
new file mode 100644
index 0000000..1444ba2
--- /dev/null
+++ b/test/core/json/corpus/f92c47e35da42d79a48beff54b93cd28f55f05fb
@@ -0,0 +1 @@
+1e9
\ No newline at end of file
diff --git a/test/core/json/corpus/f9a33bb8bd78d869fbafa402d9be58940ce2c318 b/test/core/json/corpus/f9a33bb8bd78d869fbafa402d9be58940ce2c318
new file mode 100644
index 0000000..fbcb9da
--- /dev/null
+++ b/test/core/json/corpus/f9a33bb8bd78d869fbafa402d9be58940ce2c318
@@ -0,0 +1 @@
+1E	"ˆÁ960
\ No newline at end of file
diff --git a/test/core/json/corpus/fbf6f3156c1bd4bb701839bc0e26533bdccd1c9a b/test/core/json/corpus/fbf6f3156c1bd4bb701839bc0e26533bdccd1c9a
new file mode 100644
index 0000000..d60f1d8
--- /dev/null
+++ b/test/core/json/corpus/fbf6f3156c1bd4bb701839bc0e26533bdccd1c9a
@@ -0,0 +1 @@
+0,fa%)
\ No newline at end of file
diff --git a/test/core/json/corpus/fe2ef495a1152561572949784c16bf23abb28057 b/test/core/json/corpus/fe2ef495a1152561572949784c16bf23abb28057
new file mode 100644
index 0000000..abc4eff
--- /dev/null
+++ b/test/core/json/corpus/fe2ef495a1152561572949784c16bf23abb28057
@@ -0,0 +1 @@
+46
\ No newline at end of file
diff --git a/test/core/json/corpus/fe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f b/test/core/json/corpus/fe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f
new file mode 100644
index 0000000..301160a
--- /dev/null
+++ b/test/core/json/corpus/fe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f
@@ -0,0 +1 @@
+8
\ No newline at end of file
diff --git a/test/core/json/corpus/ff8fb34603c7f772768d61504954553e6bed173c b/test/core/json/corpus/ff8fb34603c7f772768d61504954553e6bed173c
new file mode 100644
index 0000000..9586ab9
--- /dev/null
+++ b/test/core/json/corpus/ff8fb34603c7f772768d61504954553e6bed173c
@@ -0,0 +1 @@
+n'
\ No newline at end of file
diff --git a/test/core/json/corpus/test1.json b/test/core/json/corpus/test1.json
new file mode 100644
index 0000000..2393cd0
--- /dev/null
+++ b/test/core/json/corpus/test1.json
@@ -0,0 +1 @@
+{"foo":"bar"}
diff --git a/test/core/json/corpus/test2.json b/test/core/json/corpus/test2.json
new file mode 100644
index 0000000..810c96e
--- /dev/null
+++ b/test/core/json/corpus/test2.json
@@ -0,0 +1 @@
+"foo"
diff --git a/test/core/json/corpus/test3.json b/test/core/json/corpus/test3.json
new file mode 100644
index 0000000..8adb9bb
--- /dev/null
+++ b/test/core/json/corpus/test3.json
@@ -0,0 +1 @@
+[1,2,3,4]
diff --git a/test/core/json/corpus/test4.json b/test/core/json/corpus/test4.json
new file mode 100644
index 0000000..4c3fcf9
--- /dev/null
+++ b/test/core/json/corpus/test4.json
@@ -0,0 +1 @@
+1e943923
diff --git a/test/core/json/corpus/test5.json b/test/core/json/corpus/test5.json
new file mode 100644
index 0000000..03f1d79
--- /dev/null
+++ b/test/core/json/corpus/test5.json
@@ -0,0 +1 @@
+100000000000000000000000000000000000000000000000000000000000001
diff --git a/test/core/json/corpus/test6.json b/test/core/json/corpus/test6.json
new file mode 100644
index 0000000..27ba77d
--- /dev/null
+++ b/test/core/json/corpus/test6.json
@@ -0,0 +1 @@
+true
diff --git a/test/core/json/corpus/test7.json b/test/core/json/corpus/test7.json
new file mode 100644
index 0000000..c508d53
--- /dev/null
+++ b/test/core/json/corpus/test7.json
@@ -0,0 +1 @@
+false
diff --git a/test/core/json/corpus/test8.json b/test/core/json/corpus/test8.json
new file mode 100644
index 0000000..19765bd
--- /dev/null
+++ b/test/core/json/corpus/test8.json
@@ -0,0 +1 @@
+null
diff --git a/test/core/json/corpus/test9.json b/test/core/json/corpus/test9.json
new file mode 100644
index 0000000..affaba3
--- /dev/null
+++ b/test/core/json/corpus/test9.json
@@ -0,0 +1 @@
+{"alpha":null,"beta":false,"gamma":2.3,"xyz":"abc","negative":-133}
diff --git a/test/core/json/fuzzer.c b/test/core/json/fuzzer.c
new file mode 100644
index 0000000..65f89e6
--- /dev/null
+++ b/test/core/json/fuzzer.c
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+#include "src/core/lib/json/json.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  char *s = gpr_malloc(size);
+  memcpy(s, data, size);
+  grpc_json *x;
+  if ((x = grpc_json_parse_string_with_len(s, size))) {
+    grpc_json_destroy(x);
+  }
+  gpr_free(s);
+  return 0;
+}
diff --git a/test/core/json/json_rewrite.c b/test/core/json/json_rewrite.c
index 0c615a9..41090db 100644
--- a/test/core/json/json_rewrite.c
+++ b/test/core/json/json_rewrite.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,8 +38,8 @@
 #include <grpc/support/cmdline.h>
 #include <grpc/support/log.h>
 
-#include "src/core/json/json_reader.h"
-#include "src/core/json/json_writer.h"
+#include "src/core/lib/json/json_reader.h"
+#include "src/core/lib/json/json_writer.h"
 
 typedef struct json_writer_userdata { FILE *out; } json_writer_userdata;
 
diff --git a/test/core/json/json_rewrite_test.c b/test/core/json/json_rewrite_test.c
index d99cb0d..33fc98e 100644
--- a/test/core/json/json_rewrite_test.c
+++ b/test/core/json/json_rewrite_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,12 +35,12 @@
 #include <stdlib.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/useful.h>
 #include <grpc/support/log.h>
+#include <grpc/support/useful.h>
 #include "test/core/util/test_config.h"
 
-#include "src/core/json/json_reader.h"
-#include "src/core/json/json_writer.h"
+#include "src/core/lib/json/json_reader.h"
+#include "src/core/lib/json/json_writer.h"
 
 typedef struct json_writer_userdata { FILE *cmp; } json_writer_userdata;
 
diff --git a/test/core/json/json_stream_error_test.c b/test/core/json/json_stream_error_test.c
index 4007767..630e1b0 100644
--- a/test/core/json/json_stream_error_test.c
+++ b/test/core/json/json_stream_error_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,12 +35,12 @@
 #include <stdlib.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/useful.h>
 #include <grpc/support/log.h>
+#include <grpc/support/useful.h>
 #include "test/core/util/test_config.h"
 
-#include "src/core/json/json_reader.h"
-#include "src/core/json/json_writer.h"
+#include "src/core/lib/json/json_reader.h"
+#include "src/core/lib/json/json_writer.h"
 
 static int g_string_clear_once = 0;
 
diff --git a/test/core/json/json_test.c b/test/core/json/json_test.c
index 5add80d..13ee5bb 100644
--- a/test/core/json/json_test.c
+++ b/test/core/json/json_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,11 +34,11 @@
 #include <string.h>
 
 #include <grpc/support/alloc.h>
-#include <grpc/support/useful.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include "src/core/json/json.h"
-#include "src/core/support/string.h"
+#include <grpc/support/useful.h>
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/support/string.h"
 
 #include "test/core/util/test_config.h"
 
@@ -64,9 +64,10 @@
     /* Testing UTF-8 character "𝄞", U+11D1E. */
     {"\"\xf0\x9d\x84\x9e\"", "\"\\ud834\\udd1e\""},
     {"\"\\ud834\\udd1e\"", "\"\\ud834\\udd1e\""},
+    {"{\"\\ud834\\udd1e\":0}", "{\"\\ud834\\udd1e\":0}"},
     /* Testing nested empty containers. */
     {
-     " [ [ ] , { } , [ ] ] ", "[[],{},[]]",
+        " [ [ ] , { } , [ ] ] ", "[[],{},[]]",
     },
     /* Testing escapes and control chars in key strings. */
     {" { \"\\u007f\x7f\\n\\r\\\"\\f\\b\\\\a , b\": 1, \"\": 0 } ",
@@ -85,20 +86,31 @@
     /* Testing plain invalid things, exercising the state machine. */
     {"\\", NULL},
     {"nu ll", NULL},
+    {"{\"foo\": bar}", NULL},
+    {"{\"foo\": bar\"x\"}", NULL},
     {"fals", NULL},
     /* Testing unterminated string. */
     {"\"\\x", NULL},
     /* Testing invalid UTF-16 number. */
     {"\"\\u123x", NULL},
+    {"{\"\\u123x", NULL},
     /* Testing imbalanced surrogate pairs. */
     {"\"\\ud834f", NULL},
+    {"{\"\\ud834f\":0}", NULL},
     {"\"\\ud834\\n", NULL},
+    {"{\"\\ud834\\n\":0}", NULL},
     {"\"\\udd1ef", NULL},
+    {"{\"\\udd1ef\":0}", NULL},
     {"\"\\ud834\\ud834\"", NULL},
+    {"{\"\\ud834\\ud834\"\":0}", NULL},
     {"\"\\ud834\\u1234\"", NULL},
+    {"{\"\\ud834\\u1234\"\":0}", NULL},
     {"\"\\ud834]\"", NULL},
+    {"{\"\\ud834]\"\":0}", NULL},
     {"\"\\ud834 \"", NULL},
+    {"{\"\\ud834 \"\":0}", NULL},
     {"\"\\ud834\\\\\"", NULL},
+    {"{\"\\ud834\\\\\"\":0}", NULL},
     /* Testing embedded invalid whitechars. */
     {"\"\n\"", NULL},
     {"\"\t\"", NULL},
diff --git a/test/core/network_benchmarks/low_level_ping_pong.c b/test/core/network_benchmarks/low_level_ping_pong.c
index dd1544c..b8c6954 100644
--- a/test/core/network_benchmarks/low_level_ping_pong.c
+++ b/test/core/network_benchmarks/low_level_ping_pong.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -49,13 +49,13 @@
 #endif
 #include <sys/socket.h>
 
-#include "src/core/iomgr/socket_utils_posix.h"
 #include <grpc/support/cmdline.h>
 #include <grpc/support/histogram.h>
 #include <grpc/support/log.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/iomgr/socket_utils_posix.h"
 
 typedef struct fd_pair {
   int read_fd;
diff --git a/test/core/profiling/timers_test.c b/test/core/profiling/timers_test.c
index 7070fe4..a383119 100644
--- a/test/core/profiling/timers_test.c
+++ b/test/core/profiling/timers_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/profiling/timers.h"
+#include "src/core/lib/profiling/timers.h"
 #include <stdlib.h>
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/security/auth_context_test.c b/test/core/security/auth_context_test.c
index d091c7e..84d2afb 100644
--- a/test/core/security/auth_context_test.c
+++ b/test/core/security/auth_context_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,8 @@
 
 #include <string.h>
 
-#include "src/core/security/security_context.h"
-#include "src/core/support/string.h"
+#include "src/core/lib/security/security_context.h"
+#include "src/core/lib/support/string.h"
 #include "test/core/util/test_config.h"
 
 #include <grpc/support/log.h>
diff --git a/test/core/security/b64_test.c b/test/core/security/b64_test.c
index 772514e..ab15df2 100644
--- a/test/core/security/b64_test.c
+++ b/test/core/security/b64_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/security/b64.h"
+#include "src/core/lib/security/b64.h"
 
 #include <string.h>
 
diff --git a/test/core/security/create_jwt.c b/test/core/security/create_jwt.c
index 4c0cf43..3416de7 100644
--- a/test/core/security/create_jwt.c
+++ b/test/core/security/create_jwt.c
@@ -34,9 +34,9 @@
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/security/credentials.h"
-#include "src/core/security/json_token.h"
-#include "src/core/support/load_file.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/security/json_token.h"
+#include "src/core/lib/support/load_file.h"
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/cmdline.h>
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index 98133ef..e741e36 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -33,7 +33,7 @@
 
 #include <grpc/support/port_platform.h>
 
-#include "src/core/security/credentials.h"
+#include "src/core/lib/security/credentials.h"
 
 #include <openssl/rsa.h>
 #include <stdlib.h>
@@ -44,11 +44,11 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 
-#include "src/core/httpcli/httpcli.h"
-#include "src/core/security/json_token.h"
-#include "src/core/support/env.h"
-#include "src/core/support/tmpfile.h"
-#include "src/core/support/string.h"
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/security/json_token.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/support/tmpfile.h"
 #include "test/core/util/test_config.h"
 
 /* -- Mock channel credentials. -- */
@@ -536,12 +536,12 @@
   GPR_ASSERT(request->handshaker != &grpc_httpcli_ssl);
   GPR_ASSERT(strcmp(request->host, "metadata") == 0);
   GPR_ASSERT(
-      strcmp(request->path,
+      strcmp(request->http.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);
+  GPR_ASSERT(request->http.hdr_count == 1);
+  GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Metadata-Flavor") == 0);
+  GPR_ASSERT(strcmp(request->http.hdrs[0].value, "Google") == 0);
 }
 
 static int compute_engine_httpcli_get_success_override(
@@ -639,11 +639,12 @@
   gpr_free(expected_body);
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
   GPR_ASSERT(strcmp(request->host, GRPC_GOOGLE_OAUTH2_SERVICE_HOST) == 0);
-  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);
+      strcmp(request->http.path, GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH) == 0);
+  GPR_ASSERT(request->http.hdr_count == 1);
+  GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0);
+  GPR_ASSERT(strcmp(request->http.hdrs[0].value,
+                    "application/x-www-form-urlencoded") == 0);
 }
 
 static int refresh_token_httpcli_post_success(
@@ -898,12 +899,12 @@
     gpr_timespec deadline, grpc_httpcli_response_cb on_response,
     void *user_data) {
   grpc_httpcli_response response = http_response(200, "");
-  grpc_httpcli_header header;
+  grpc_http_header header;
   header.key = "Metadata-Flavor";
   header.value = "Google";
   response.hdr_count = 1;
   response.hdrs = &header;
-  GPR_ASSERT(strcmp(request->path, "/") == 0);
+  GPR_ASSERT(strcmp(request->http.path, "/") == 0);
   GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0);
   on_response(exec_ctx, user_data, &response);
   return 1;
@@ -961,7 +962,7 @@
     void *user_data) {
   /* No magic header. */
   grpc_httpcli_response response = http_response(200, "");
-  GPR_ASSERT(strcmp(request->path, "/") == 0);
+  GPR_ASSERT(strcmp(request->http.path, "/") == 0);
   GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0);
   on_response(exec_ctx, user_data, &response);
   return 1;
diff --git a/test/core/security/fetch_oauth2.c b/test/core/security/fetch_oauth2.c
index 87b54f1..1f4e180 100644
--- a/test/core/security/fetch_oauth2.c
+++ b/test/core/security/fetch_oauth2.c
@@ -42,8 +42,8 @@
 #include <grpc/support/slice.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/security/credentials.h"
-#include "src/core/support/load_file.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/support/load_file.h"
 #include "test/core/security/oauth2_utils.h"
 
 static grpc_call_credentials *create_refresh_token_creds(
diff --git a/test/core/security/json_token_test.c b/test/core/security/json_token_test.c
index 4d80c16..460d529 100644
--- a/test/core/security/json_token_test.c
+++ b/test/core/security/json_token_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/security/json_token.h"
+#include "src/core/lib/security/json_token.h"
 
 #include <openssl/evp.h>
 #include <string.h>
@@ -41,8 +41,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/slice.h>
 
-#include "src/core/json/json.h"
-#include "src/core/security/b64.h"
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/security/b64.h"
 #include "test/core/util/test_config.h"
 
 /* This JSON key was generated with the GCE console and revoked immediately.
diff --git a/test/core/security/jwt_verifier_test.c b/test/core/security/jwt_verifier_test.c
index f6ec9e1..c57f4d7 100644
--- a/test/core/security/jwt_verifier_test.c
+++ b/test/core/security/jwt_verifier_test.c
@@ -31,13 +31,13 @@
  *
  */
 
-#include "src/core/security/jwt_verifier.h"
+#include "src/core/lib/security/jwt_verifier.h"
 
 #include <string.h>
 
-#include "src/core/httpcli/httpcli.h"
-#include "src/core/security/b64.h"
-#include "src/core/security/json_token.h"
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/security/b64.h"
+#include "src/core/lib/security/json_token.h"
 #include "test/core/util/test_config.h"
 
 #include <grpc/support/alloc.h>
@@ -288,7 +288,7 @@
   grpc_httpcli_response response = http_response(200, good_google_email_keys());
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
   GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0);
-  GPR_ASSERT(strcmp(request->path,
+  GPR_ASSERT(strcmp(request->http.path,
                     "/robot/v1/metadata/x509/"
                     "777-abaslkan11hlb6nmim3bpspl31ud@developer."
                     "gserviceaccount.com") == 0);
@@ -336,7 +336,7 @@
   grpc_httpcli_response response = http_response(200, gpr_strdup(good_jwk_set));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
   GPR_ASSERT(strcmp(request->host, "keys.bar.com") == 0);
-  GPR_ASSERT(strcmp(request->path, "/jwk/foo@bar.com") == 0);
+  GPR_ASSERT(strcmp(request->http.path, "/jwk/foo@bar.com") == 0);
   on_response(exec_ctx, user_data, &response);
   gpr_free(response.body);
   return 1;
@@ -372,7 +372,7 @@
   grpc_httpcli_response response = http_response(200, gpr_strdup(good_jwk_set));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
   GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0);
-  GPR_ASSERT(strcmp(request->path, "/oauth2/v3/certs") == 0);
+  GPR_ASSERT(strcmp(request->http.path, "/oauth2/v3/certs") == 0);
   on_response(exec_ctx, user_data, &response);
   gpr_free(response.body);
   return 1;
@@ -387,7 +387,7 @@
       http_response(200, gpr_strdup(good_openid_config));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
   GPR_ASSERT(strcmp(request->host, "accounts.google.com") == 0);
-  GPR_ASSERT(strcmp(request->path, GRPC_OPENID_CONFIG_URL_SUFFIX) == 0);
+  GPR_ASSERT(strcmp(request->http.path, GRPC_OPENID_CONFIG_URL_SUFFIX) == 0);
   grpc_httpcli_set_override(httpcli_get_jwk_set,
                             httpcli_post_should_not_be_called);
   on_response(exec_ctx, user_data, &response);
diff --git a/test/core/security/oauth2_utils.c b/test/core/security/oauth2_utils.c
index 9b70aff..52259e6 100644
--- a/test/core/security/oauth2_utils.c
+++ b/test/core/security/oauth2_utils.c
@@ -42,7 +42,7 @@
 #include <grpc/support/slice.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/security/credentials.h"
+#include "src/core/lib/security/credentials.h"
 
 typedef struct {
   gpr_mu *mu;
diff --git a/test/core/security/oauth2_utils.h b/test/core/security/oauth2_utils.h
index b35fe79..5930f47 100644
--- a/test/core/security/oauth2_utils.h
+++ b/test/core/security/oauth2_utils.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,7 @@
 #ifndef GRPC_TEST_CORE_SECURITY_OAUTH2_UTILS_H
 #define GRPC_TEST_CORE_SECURITY_OAUTH2_UTILS_H
 
-#include "src/core/security/credentials.h"
+#include "src/core/lib/security/credentials.h"
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/test/core/security/print_google_default_creds_token.c b/test/core/security/print_google_default_creds_token.c
index 09673f3..49812f7 100644
--- a/test/core/security/print_google_default_creds_token.c
+++ b/test/core/security/print_google_default_creds_token.c
@@ -42,8 +42,8 @@
 #include <grpc/support/slice.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/security/credentials.h"
-#include "src/core/support/string.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/support/string.h"
 
 typedef struct {
   gpr_mu *mu;
diff --git a/test/core/security/secure_endpoint_test.c b/test/core/security/secure_endpoint_test.c
index 0e8c38a..f6884ec 100644
--- a/test/core/security/secure_endpoint_test.c
+++ b/test/core/security/secure_endpoint_test.c
@@ -39,10 +39,10 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include "src/core/iomgr/endpoint_pair.h"
-#include "src/core/iomgr/iomgr.h"
-#include "src/core/security/secure_endpoint.h"
-#include "src/core/tsi/fake_transport_security.h"
+#include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/security/secure_endpoint.h"
+#include "src/core/lib/tsi/fake_transport_security.h"
 #include "test/core/util/test_config.h"
 
 static gpr_mu *g_mu;
diff --git a/test/core/security/security_connector_test.c b/test/core/security/security_connector_test.c
index 420e3a4..b080343 100644
--- a/test/core/security/security_connector_test.c
+++ b/test/core/security/security_connector_test.c
@@ -40,13 +40,13 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/security/security_connector.h"
-#include "src/core/security/security_context.h"
-#include "src/core/support/env.h"
-#include "src/core/support/tmpfile.h"
-#include "src/core/support/string.h"
-#include "src/core/tsi/ssl_transport_security.h"
-#include "src/core/tsi/transport_security.h"
+#include "src/core/lib/security/security_connector.h"
+#include "src/core/lib/security/security_context.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/support/tmpfile.h"
+#include "src/core/lib/tsi/ssl_transport_security.h"
+#include "src/core/lib/tsi/transport_security.h"
 #include "test/core/util/test_config.h"
 
 static int check_transport_security_type(const grpc_auth_context *ctx) {
@@ -80,13 +80,14 @@
 
 static int check_ssl_peer_equivalence(const tsi_peer *original,
                                       const tsi_peer *reconstructed) {
-  /* The reconstructed peer only has CN and SAN properties. */
+  /* The reconstructed peer only has CN, SAN and pem cert properties. */
   size_t i;
   for (i = 0; i < original->property_count; i++) {
     const tsi_peer_property *prop = &original->properties[i];
     if ((strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) ||
         (strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) ==
-         0)) {
+         0) ||
+        (strcmp(prop->name, TSI_X509_PEM_CERT_PROPERTY) == 0)) {
       if (!check_peer_property(reconstructed, prop)) return 0;
     }
   }
@@ -164,24 +165,50 @@
   return 1;
 }
 
+static int check_x509_pem_cert(const grpc_auth_context *ctx,
+                               const char *expected_pem_cert) {
+  grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
+      ctx, GRPC_X509_PEM_CERT_PROPERTY_NAME);
+  const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it);
+  if (prop == NULL) {
+    gpr_log(GPR_ERROR, "Pem certificate property not found.");
+    return 0;
+  }
+  if (strncmp(prop->value, expected_pem_cert, prop->value_length) != 0) {
+    gpr_log(GPR_ERROR, "Expected pem cert %s and got %s", expected_pem_cert,
+            prop->value);
+    return 0;
+  }
+  if (grpc_auth_property_iterator_next(&it) != NULL) {
+    gpr_log(GPR_ERROR, "Expected only one property for pem cert.");
+    return 0;
+  }
+  return 1;
+}
+
 static void test_cn_only_ssl_peer_to_auth_context(void) {
   tsi_peer peer;
   tsi_peer rpeer;
   grpc_auth_context *ctx;
   const char *expected_cn = "cn1";
-  GPR_ASSERT(tsi_construct_peer(2, &peer) == TSI_OK);
+  const char *expected_pem_cert = "pem_cert1";
+  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_PEM_CERT_PROPERTY, expected_pem_cert,
+                 &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_CN_PROPERTY_NAME, &expected_cn, 1));
   GPR_ASSERT(check_transport_security_type(ctx));
   GPR_ASSERT(check_x509_cn(ctx, expected_cn));
+  GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert));
 
   rpeer = tsi_shallow_peer_from_ssl_auth_context(ctx);
   GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
@@ -197,7 +224,8 @@
   grpc_auth_context *ctx;
   const char *expected_cn = "cn1";
   const char *expected_san = "san1";
-  GPR_ASSERT(tsi_construct_peer(3, &peer) == TSI_OK);
+  const char *expected_pem_cert = "pem_cert1";
+  GPR_ASSERT(tsi_construct_peer(4, &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);
@@ -207,6 +235,9 @@
   GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
                  TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, expected_san,
                  &peer.properties[2]) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
+                 &peer.properties[3]) == TSI_OK);
   ctx = tsi_ssl_peer_to_auth_context(&peer);
   GPR_ASSERT(ctx != NULL);
   GPR_ASSERT(grpc_auth_context_peer_is_authenticated(ctx));
@@ -214,6 +245,7 @@
       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));
+  GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert));
 
   rpeer = tsi_shallow_peer_from_ssl_auth_context(ctx);
   GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
@@ -229,8 +261,9 @@
   grpc_auth_context *ctx;
   const char *expected_cn = "cn1";
   const char *expected_sans[] = {"san1", "san2", "san3"};
+  const char *expected_pem_cert = "pem_cert1";
   size_t i;
-  GPR_ASSERT(tsi_construct_peer(2 + GPR_ARRAY_SIZE(expected_sans), &peer) ==
+  GPR_ASSERT(tsi_construct_peer(3 + 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,
@@ -238,10 +271,13 @@
   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_PEM_CERT_PROPERTY, expected_pem_cert,
+                 &peer.properties[2]) == 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);
+                   expected_sans[i], &peer.properties[3 + i]) == TSI_OK);
   }
   ctx = tsi_ssl_peer_to_auth_context(&peer);
   GPR_ASSERT(ctx != NULL);
@@ -250,6 +286,7 @@
                             GPR_ARRAY_SIZE(expected_sans)));
   GPR_ASSERT(check_transport_security_type(ctx));
   GPR_ASSERT(check_x509_cn(ctx, expected_cn));
+  GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert));
 
   rpeer = tsi_shallow_peer_from_ssl_auth_context(ctx);
   GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
@@ -265,9 +302,10 @@
   tsi_peer rpeer;
   grpc_auth_context *ctx;
   const char *expected_cn = "cn1";
+  const char *expected_pem_cert = "pem_cert1";
   const char *expected_sans[] = {"san1", "san2", "san3"};
   size_t i;
-  GPR_ASSERT(tsi_construct_peer(4 + GPR_ARRAY_SIZE(expected_sans), &peer) ==
+  GPR_ASSERT(tsi_construct_peer(5 + 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,
@@ -279,10 +317,13 @@
                  &peer.properties[2]) == TSI_OK);
   GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
                  "chapi", "chapo", &peer.properties[3]) == TSI_OK);
+  GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
+                 TSI_X509_PEM_CERT_PROPERTY, expected_pem_cert,
+                 &peer.properties[4]) == 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);
+                   expected_sans[i], &peer.properties[5 + i]) == TSI_OK);
   }
   ctx = tsi_ssl_peer_to_auth_context(&peer);
   GPR_ASSERT(ctx != NULL);
@@ -291,6 +332,7 @@
                             GPR_ARRAY_SIZE(expected_sans)));
   GPR_ASSERT(check_transport_security_type(ctx));
   GPR_ASSERT(check_x509_cn(ctx, expected_cn));
+  GPR_ASSERT(check_x509_pem_cert(ctx, expected_pem_cert));
 
   rpeer = tsi_shallow_peer_from_ssl_auth_context(ctx);
   GPR_ASSERT(check_ssl_peer_equivalence(&peer, &rpeer));
diff --git a/test/core/security/verify_jwt.c b/test/core/security/verify_jwt.c
index eb86589..c08e03d 100644
--- a/test/core/security/verify_jwt.c
+++ b/test/core/security/verify_jwt.c
@@ -42,7 +42,7 @@
 #include <grpc/support/slice.h>
 #include <grpc/support/sync.h>
 
-#include "src/core/security/jwt_verifier.h"
+#include "src/core/lib/security/jwt_verifier.h"
 
 typedef struct {
   grpc_pollset *pollset;
diff --git a/test/core/statistics/census_log_tests.c b/test/core/statistics/census_log_tests.c
index 77cc57d..fef8e9e 100644
--- a/test/core/statistics/census_log_tests.c
+++ b/test/core/statistics/census_log_tests.c
@@ -31,10 +31,7 @@
  *
  */
 
-#include "src/core/statistics/census_log.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "src/core/lib/statistics/census_log.h"
 #include <grpc/support/cpu.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
@@ -42,6 +39,9 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include "test/core/util/test_config.h"
 
 /* Fills in 'record' of size 'size'. Each byte in record is filled in with the
diff --git a/test/core/statistics/census_stub_test.c b/test/core/statistics/census_stub_test.c
index 8e409a3..df5d25b 100644
--- a/test/core/statistics/census_stub_test.c
+++ b/test/core/statistics/census_stub_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,10 +34,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "src/core/statistics/census_interface.h"
-#include "src/core/statistics/census_rpc_stats.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include "src/core/lib/statistics/census_interface.h"
+#include "src/core/lib/statistics/census_rpc_stats.h"
 #include "test/core/util/test_config.h"
 
 /* Tests census noop stubs in a simulated rpc flow */
diff --git a/test/core/statistics/hash_table_test.c b/test/core/statistics/hash_table_test.c
index 3b119db..903d297 100644
--- a/test/core/statistics/hash_table_test.c
+++ b/test/core/statistics/hash_table_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,13 +35,13 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "src/core/statistics/hash_table.h"
+#include "src/core/lib/statistics/hash_table.h"
 
-#include "src/core/support/murmur_hash.h"
-#include "src/core/support/string.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
+#include "src/core/lib/support/murmur_hash.h"
+#include "src/core/lib/support/string.h"
 #include "test/core/util/test_config.h"
 
 static uint64_t hash64(const void *k) {
@@ -65,8 +65,8 @@
 static void test_create_table(void) {
   /* Create table with uint64 key type */
   census_ht *ht = NULL;
-  census_ht_option ht_options = {CENSUS_HT_UINT64, 1999, NULL, NULL, NULL,
-                                 NULL};
+  census_ht_option ht_options = {
+      CENSUS_HT_UINT64, 1999, NULL, NULL, NULL, NULL};
   ht = census_ht_create(&ht_options);
   GPR_ASSERT(ht != NULL);
   GPR_ASSERT(census_ht_get_size(ht) == 0);
@@ -120,8 +120,8 @@
 
 /* Test that there is no memory leak when keys and values are owned by table. */
 static void test_value_and_key_deleter(void) {
-  census_ht_option opt = {CENSUS_HT_POINTER, 7, &hash64, &cmp_str_keys,
-                          &free_data, &free_data};
+  census_ht_option opt = {CENSUS_HT_POINTER, 7,          &hash64,
+                          &cmp_str_keys,     &free_data, &free_data};
   census_ht *ht = census_ht_create(&opt);
   census_ht_key key;
   char *val = NULL;
@@ -185,8 +185,8 @@
 }
 
 static void test_insertion_and_deletion_with_high_collision_rate(void) {
-  census_ht_option opt = {CENSUS_HT_POINTER, 13, &force_collision,
-                          &cmp_str_keys, NULL, NULL};
+  census_ht_option opt = {CENSUS_HT_POINTER, 13,   &force_collision,
+                          &cmp_str_keys,     NULL, NULL};
   census_ht *ht = census_ht_create(&opt);
   char key_str[1000][GPR_LTOA_MIN_BUFSIZE];
   uint64_t val = 0;
@@ -209,12 +209,12 @@
 }
 
 static void test_table_with_string_key(void) {
-  census_ht_option opt = {CENSUS_HT_POINTER, 7, &hash64, &cmp_str_keys, NULL,
-                          NULL};
+  census_ht_option opt = {CENSUS_HT_POINTER, 7,    &hash64,
+                          &cmp_str_keys,     NULL, NULL};
   census_ht *ht = census_ht_create(&opt);
-  const char *keys[] = {"k1", "a", "000", "apple",
-                        "banana_a_long_long_long_banana", "%$", "111", "foo",
-                        "b"};
+  const char *keys[] = {
+      "k1", "a",   "000", "apple", "banana_a_long_long_long_banana",
+      "%$", "111", "foo", "b"};
   const int vals[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
   int i = 0;
   GPR_ASSERT(ht != NULL);
diff --git a/test/core/statistics/rpc_stats_test.c b/test/core/statistics/rpc_stats_test.c
index b1d8814..dc2f70b 100644
--- a/test/core/statistics/rpc_stats_test.c
+++ b/test/core/statistics/rpc_stats_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,15 +33,15 @@
 
 #include <string.h>
 
-#include "src/core/statistics/census_interface.h"
-#include "src/core/statistics/census_rpc_stats.h"
-#include "src/core/statistics/census_tracing.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
 #include <grpc/support/string.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include "src/core/lib/statistics/census_interface.h"
+#include "src/core/lib/statistics/census_rpc_stats.h"
+#include "src/core/lib/statistics/census_tracing.h"
 #include "test/core/util/test_config.h"
 
 /* Ensure all possible state transitions are called without causing problem */
diff --git a/test/core/statistics/trace_test.c b/test/core/statistics/trace_test.c
index 7590404..2cc3ddd 100644
--- a/test/core/statistics/trace_test.c
+++ b/test/core/statistics/trace_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,12 +31,9 @@
  *
  */
 
-#include <string.h>
 #include <stdio.h>
+#include <string.h>
 
-#include "src/core/statistics/census_interface.h"
-#include "src/core/statistics/census_tracing.h"
-#include "src/core/statistics/census_tracing.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
@@ -44,6 +41,9 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/statistics/census_interface.h"
+#include "src/core/lib/statistics/census_tracing.h"
+#include "src/core/lib/statistics/census_tracing.h"
 #include "test/core/util/test_config.h"
 
 /* Ensure all possible state transitions are called without causing problem */
diff --git a/test/core/statistics/window_stats_test.c b/test/core/statistics/window_stats_test.c
index 578138f..ed0d7bb 100644
--- a/test/core/statistics/window_stats_test.c
+++ b/test/core/statistics/window_stats_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,10 +31,10 @@
  *
  */
 
-#include "src/core/statistics/window_stats.h"
-#include <stdlib.h>
+#include "src/core/lib/statistics/window_stats.h"
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
+#include <stdlib.h>
 #include "test/core/util/test_config.h"
 
 typedef struct test_stat {
diff --git a/test/core/support/alloc_test.c b/test/core/support/alloc_test.c
index 6bdba8c..e2d0c16 100644
--- a/test/core/support/alloc_test.c
+++ b/test/core/support/alloc_test.c
@@ -31,8 +31,8 @@
  *
  */
 
-#include <grpc/support/log.h>
 #include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
 #include "test/core/util/test_config.h"
 
 static void *fake_malloc(size_t size) { return (void *)size; }
diff --git a/test/core/support/backoff_test.c b/test/core/support/backoff_test.c
new file mode 100644
index 0000000..13cba7d
--- /dev/null
+++ b/test/core/support/backoff_test.c
@@ -0,0 +1,107 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/support/backoff.h"
+
+#include <grpc/support/log.h>
+
+#include "test/core/util/test_config.h"
+
+static void test_constant_backoff(void) {
+  gpr_backoff backoff;
+  gpr_backoff_init(&backoff, 1.0, 0.0, 1000, 1000);
+
+  gpr_timespec now = gpr_time_0(GPR_TIMESPAN);
+  gpr_timespec next = gpr_backoff_begin(&backoff, now);
+  GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 1000);
+  for (int i = 0; i < 10000; i++) {
+    next = gpr_backoff_step(&backoff, now);
+    GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 1000);
+    now = next;
+  }
+}
+
+static void test_no_jitter_backoff(void) {
+  gpr_backoff backoff;
+  gpr_backoff_init(&backoff, 2.0, 0.0, 1, 513);
+
+  gpr_timespec now = gpr_time_0(GPR_TIMESPAN);
+  gpr_timespec next = gpr_backoff_begin(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(1, GPR_TIMESPAN), next) == 0);
+  now = next;
+  next = gpr_backoff_step(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(3, GPR_TIMESPAN), next) == 0);
+  now = next;
+  next = gpr_backoff_step(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(7, GPR_TIMESPAN), next) == 0);
+  now = next;
+  next = gpr_backoff_step(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(15, GPR_TIMESPAN), next) == 0);
+  now = next;
+  next = gpr_backoff_step(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(31, GPR_TIMESPAN), next) == 0);
+  now = next;
+  next = gpr_backoff_step(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(63, GPR_TIMESPAN), next) == 0);
+  now = next;
+  next = gpr_backoff_step(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(127, GPR_TIMESPAN), next) == 0);
+  now = next;
+  next = gpr_backoff_step(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(255, GPR_TIMESPAN), next) == 0);
+  now = next;
+  next = gpr_backoff_step(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(511, GPR_TIMESPAN), next) == 0);
+  now = next;
+  next = gpr_backoff_step(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(1023, GPR_TIMESPAN), next) == 0);
+  now = next;
+  next = gpr_backoff_step(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(1536, GPR_TIMESPAN), next) == 0);
+  now = next;
+  next = gpr_backoff_step(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(2049, GPR_TIMESPAN), next) == 0);
+  now = next;
+  next = gpr_backoff_step(&backoff, now);
+  GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(2562, GPR_TIMESPAN), next) == 0);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  gpr_time_init();
+
+  test_constant_backoff();
+  test_no_jitter_backoff();
+
+  return 0;
+}
diff --git a/test/core/support/env_test.c b/test/core/support/env_test.c
index 69aebcc..1ab86d6 100644
--- a/test/core/support/env_test.c
+++ b/test/core/support/env_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
-#include "src/core/support/env.h"
-#include "src/core/support/string.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
 #include "test/core/util/test_config.h"
 
 #define LOG_TEST_NAME(x) gpr_log(GPR_INFO, "%s", x)
diff --git a/test/core/support/load_file_test.c b/test/core/support/load_file_test.c
index e6ba617..6bc7b90 100644
--- a/test/core/support/load_file_test.c
+++ b/test/core/support/load_file_test.c
@@ -38,9 +38,9 @@
 #include <grpc/support/log.h>
 #include <grpc/support/slice.h>
 
-#include "src/core/support/load_file.h"
-#include "src/core/support/tmpfile.h"
-#include "src/core/support/string.h"
+#include "src/core/lib/support/load_file.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/support/tmpfile.h"
 #include "test/core/util/test_config.h"
 
 #define LOG_TEST_NAME(x) gpr_log(GPR_INFO, "%s", x)
@@ -135,33 +135,33 @@
   gpr_slice slice;
   int success;
   char *tmp_name;
-  unsigned char buffer[124631];
+  static const size_t buffer_size = 124631;
+  unsigned char *buffer = gpr_malloc(buffer_size);
   unsigned char *current;
   size_t i;
 
   LOG_TEST_NAME("test_load_big_file");
 
-  for (i = 0; i < sizeof(buffer); i++) {
-    buffer[i] = 42;
-  }
+  memset(buffer, 42, buffer_size);
 
   tmp = gpr_tmpfile(prefix, &tmp_name);
   GPR_ASSERT(tmp != NULL);
   GPR_ASSERT(tmp_name != NULL);
-  GPR_ASSERT(fwrite(buffer, 1, sizeof(buffer), tmp) == sizeof(buffer));
+  GPR_ASSERT(fwrite(buffer, 1, buffer_size, tmp) == buffer_size);
   fclose(tmp);
 
   slice = gpr_load_file(tmp_name, 0, &success);
   GPR_ASSERT(success == 1);
-  GPR_ASSERT(GPR_SLICE_LENGTH(slice) == sizeof(buffer));
+  GPR_ASSERT(GPR_SLICE_LENGTH(slice) == buffer_size);
   current = GPR_SLICE_START_PTR(slice);
-  for (i = 0; i < sizeof(buffer); i++) {
+  for (i = 0; i < buffer_size; i++) {
     GPR_ASSERT(current[i] == 42);
   }
 
   remove(tmp_name);
   gpr_free(tmp_name);
   gpr_slice_unref(slice);
+  gpr_free(buffer);
 }
 
 int main(int argc, char **argv) {
diff --git a/test/core/support/murmur_hash_test.c b/test/core/support/murmur_hash_test.c
index 562b956..c93efb4 100644
--- a/test/core/support/murmur_hash_test.c
+++ b/test/core/support/murmur_hash_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/support/murmur_hash.h"
+#include "src/core/lib/support/murmur_hash.h"
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.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
index 0f49e6f..13c8f3c 100644
--- a/test/core/support/stack_lockfree_test.c
+++ b/test/core/support/stack_lockfree_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/support/stack_lockfree.h"
+#include "src/core/lib/support/stack_lockfree.h"
 
 #include <stdlib.h>
 
diff --git a/test/core/support/string_test.c b/test/core/support/string_test.c
index c1d0f12..e5e474d 100644
--- a/test/core/support/string_test.c
+++ b/test/core/support/string_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/support/string.h"
+#include "src/core/lib/support/string.h"
 
 #include <limits.h>
 #include <stddef.h>
diff --git a/test/core/support/sync_test.c b/test/core/support/sync_test.c
index d311eb1..2121a4c 100644
--- a/test/core/support/sync_test.c
+++ b/test/core/support/sync_test.c
@@ -33,13 +33,13 @@
 
 /* Test of gpr synchronization support. */
 
-#include <stdio.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 <grpc/support/time.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include "test/core/util/test_config.h"
 
 /* ==================Example use of interface===================
diff --git a/test/core/support/thd_test.c b/test/core/support/thd_test.c
index f7807d2..771c510 100644
--- a/test/core/support/thd_test.c
+++ b/test/core/support/thd_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,14 +33,16 @@
 
 /* Test of gpr thread support. */
 
-#include <stdio.h>
-#include <stdlib.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include "test/core/util/test_config.h"
 
+#define NUM_THREADS 300
+
 struct test {
   gpr_mu mu;
   int n;
@@ -79,15 +81,14 @@
 static void test(void) {
   int i;
   gpr_thd_id thd;
-  gpr_thd_id thds[1000];
+  gpr_thd_id thds[NUM_THREADS];
   struct test t;
-  int n = 1000;
   gpr_thd_options options = gpr_thd_options_default();
   gpr_mu_init(&t.mu);
   gpr_cv_init(&t.done_cv);
-  t.n = n;
+  t.n = NUM_THREADS;
   t.is_done = 0;
-  for (i = 0; i != n; i++) {
+  for (i = 0; i < NUM_THREADS; i++) {
     GPR_ASSERT(gpr_thd_new(&thd, &thd_body, &t, NULL));
   }
   gpr_mu_lock(&t.mu);
@@ -97,10 +98,10 @@
   gpr_mu_unlock(&t.mu);
   GPR_ASSERT(t.n == 0);
   gpr_thd_options_set_joinable(&options);
-  for (i = 0; i < n; i++) {
+  for (i = 0; i < NUM_THREADS; i++) {
     GPR_ASSERT(gpr_thd_new(&thds[i], &thd_body_joinable, NULL, &options));
   }
-  for (i = 0; i < n; i++) {
+  for (i = 0; i < NUM_THREADS; i++) {
     gpr_thd_join(thds[i]);
   }
 }
diff --git a/test/core/support/time_test.c b/test/core/support/time_test.c
index 6cc3786..643e9ea 100644
--- a/test/core/support/time_test.c
+++ b/test/core/support/time_test.c
@@ -33,14 +33,14 @@
 
 /* Test of gpr time support. */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include "test/core/util/test_config.h"
 
 static void to_fp(void *arg, const char *buf, size_t len) {
diff --git a/test/core/support/tls_test.c b/test/core/support/tls_test.c
index c6fb1a4..7b73e5b 100644
--- a/test/core/support/tls_test.c
+++ b/test/core/support/tls_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,12 +33,12 @@
 
 /* Test of gpr thread local storage support. */
 
-#include <stdio.h>
-#include <stdlib.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/tls.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include "test/core/util/test_config.h"
 
 #define NUM_THREADS 100
diff --git a/test/core/support/useful_test.c b/test/core/support/useful_test.c
index 3665bbf..08a8cc9 100644
--- a/test/core/support/useful_test.c
+++ b/test/core/support/useful_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,9 +31,9 @@
  *
  */
 
-#include <grpc/support/useful.h>
-#include <grpc/support/port_platform.h>
 #include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/useful.h>
 #include "test/core/util/test_config.h"
 
 int main(int argc, char **argv) {
diff --git a/test/core/surface/byte_buffer_reader_test.c b/test/core/surface/byte_buffer_reader_test.c
index c87fbdc..629bce9 100644
--- a/test/core/surface/byte_buffer_reader_test.c
+++ b/test/core/surface/byte_buffer_reader_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,10 +31,10 @@
  *
  */
 
-#include <grpc/byte_buffer_reader.h>
 #include <grpc/byte_buffer.h>
-#include <grpc/support/slice.h>
+#include <grpc/byte_buffer_reader.h>
 #include <grpc/grpc.h>
+#include <grpc/support/slice.h>
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
@@ -42,7 +42,7 @@
 #include <grpc/support/time.h>
 #include "test/core/util/test_config.h"
 
-#include "src/core/compression/message_compress.h"
+#include "src/core/lib/compression/message_compress.h"
 
 #include <string.h>
 
diff --git a/test/core/surface/channel_create_test.c b/test/core/surface/channel_create_test.c
index 044e766..d5d7d1c 100644
--- a/test/core/surface/channel_create_test.c
+++ b/test/core/surface/channel_create_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,7 @@
 
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
-#include "src/core/client_config/resolver_registry.h"
+#include "src/core/lib/client_config/resolver_registry.h"
 #include "test/core/util/test_config.h"
 
 void test_unknown_scheme_target(void) {
diff --git a/test/core/surface/completion_queue_test.c b/test/core/surface/completion_queue_test.c
index ec49840..fa9b363 100644
--- a/test/core/surface/completion_queue_test.c
+++ b/test/core/surface/completion_queue_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,14 +31,14 @@
  *
  */
 
-#include "src/core/surface/completion_queue.h"
+#include "src/core/lib/surface/completion_queue.h"
 
-#include "src/core/iomgr/iomgr.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/lib/iomgr/iomgr.h"
 #include "test/core/util/test_config.h"
 
 #define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x)
diff --git a/test/core/surface/concurrent_connectivity_test.c b/test/core/surface/concurrent_connectivity_test.c
new file mode 100644
index 0000000..96761b0
--- /dev/null
+++ b/test/core/surface/concurrent_connectivity_test.c
@@ -0,0 +1,81 @@
+/*
+*
+* Copyright 2016, Google Inc.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*
+*     * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following disclaimer
+* in the documentation and/or other materials provided with the
+* distribution.
+*     * Neither the name of Google Inc. nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+#include <stdio.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+#include "test/core/util/test_config.h"
+
+#define NUM_THREADS 100
+#define NUM_OUTER_LOOPS 10
+#define NUM_INNER_LOOPS 10
+#define DELAY_MILLIS 10
+#define POLL_MILLIS 3000
+
+void create_loop_destroy(void* unused) {
+  for (int i = 0; i < NUM_OUTER_LOOPS; ++i) {
+    grpc_completion_queue* cq = grpc_completion_queue_create(NULL);
+    grpc_channel* chan = grpc_insecure_channel_create("localhost", NULL, NULL);
+
+    for (int j = 0; j < NUM_INNER_LOOPS; ++j) {
+      gpr_timespec later_time = GRPC_TIMEOUT_MILLIS_TO_DEADLINE(DELAY_MILLIS);
+      grpc_connectivity_state state =
+          grpc_channel_check_connectivity_state(chan, 1);
+      grpc_channel_watch_connectivity_state(chan, state, later_time, cq, NULL);
+      gpr_timespec poll_time = GRPC_TIMEOUT_MILLIS_TO_DEADLINE(POLL_MILLIS);
+      GPR_ASSERT(grpc_completion_queue_next(cq, poll_time, NULL).type ==
+                 GRPC_OP_COMPLETE);
+    }
+    grpc_channel_destroy(chan);
+    grpc_completion_queue_destroy(cq);
+  }
+}
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  grpc_init();
+  gpr_thd_id threads[NUM_THREADS];
+  for (size_t i = 0; i < NUM_THREADS; ++i) {
+    gpr_thd_options options = gpr_thd_options_default();
+    gpr_thd_options_set_joinable(&options);
+    gpr_thd_new(&threads[i], create_loop_destroy, NULL, &options);
+  }
+  for (size_t i = 0; i < NUM_THREADS; ++i) {
+    gpr_thd_join(threads[i]);
+  }
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/core/surface/lame_client_test.c b/test/core/surface/lame_client_test.c
index 79e53cb..310aa00 100644
--- a/test/core/surface/lame_client_test.c
+++ b/test/core/surface/lame_client_test.c
@@ -36,10 +36,10 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include "src/core/channel/channel_stack.h"
-#include "src/core/iomgr/closure.h"
-#include "src/core/surface/channel.h"
-#include "src/core/transport/transport.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/transport/transport.h"
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/surface/secure_channel_create_test.c b/test/core/surface/secure_channel_create_test.c
index f3e5fef..5c95390 100644
--- a/test/core/surface/secure_channel_create_test.c
+++ b/test/core/surface/secure_channel_create_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,10 +36,10 @@
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/log.h>
-#include "src/core/client_config/resolver_registry.h"
-#include "src/core/security/credentials.h"
-#include "src/core/security/security_connector.h"
-#include "src/core/surface/channel.h"
+#include "src/core/lib/client_config/resolver_registry.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/security/security_connector.h"
+#include "src/core/lib/surface/channel.h"
 #include "test/core/util/test_config.h"
 
 void test_unknown_scheme_target(void) {
diff --git a/test/core/surface/server_chttp2_test.c b/test/core/surface/server_chttp2_test.c
index 84b345b..14eb1ff 100644
--- a/test/core/surface/server_chttp2_test.c
+++ b/test/core/surface/server_chttp2_test.c
@@ -37,8 +37,8 @@
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include "src/core/security/credentials.h"
-#include "src/core/tsi/fake_transport_security.h"
+#include "src/core/lib/security/credentials.h"
+#include "src/core/lib/tsi/fake_transport_security.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/transport/chttp2/alpn_test.c b/test/core/transport/chttp2/alpn_test.c
index 9a7d5ef..13509c1 100644
--- a/test/core/transport/chttp2/alpn_test.c
+++ b/test/core/transport/chttp2/alpn_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/transport/chttp2/alpn.h"
+#include "src/core/ext/transport/chttp2/transport/alpn.h"
 
 #include <grpc/support/log.h>
 #include "test/core/util/test_config.h"
diff --git a/test/core/transport/chttp2/bin_encoder_test.c b/test/core/transport/chttp2/bin_encoder_test.c
index d183807..56b86e0 100644
--- a/test/core/transport/chttp2/bin_encoder_test.c
+++ b/test/core/transport/chttp2/bin_encoder_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/transport/chttp2/bin_encoder.h"
+#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
 
 #include <string.h>
 
@@ -39,9 +39,9 @@
  * TODO(murgatroid99): Remove this
  */
 #include <grpc/grpc.h>
-#include "src/core/support/string.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include "src/core/lib/support/string.h"
 
 static int all_ok = 1;
 
diff --git a/test/core/transport/chttp2/hpack_encoder_test.c b/test/core/transport/chttp2/hpack_encoder_test.c
index 4a9d143..818ce09 100644
--- a/test/core/transport/chttp2/hpack_encoder_test.c
+++ b/test/core/transport/chttp2/hpack_encoder_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,16 +31,16 @@
  *
  */
 
-#include "src/core/transport/chttp2/hpack_encoder.h"
+#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
 
 #include <stdio.h>
 
-#include "src/core/support/string.h"
-#include "src/core/transport/chttp2/hpack_parser.h"
-#include "src/core/transport/metadata.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
+#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/metadata.h"
 #include "test/core/util/parse_hexstring.h"
 #include "test/core/util/slice_splitter.h"
 #include "test/core/util/test_config.h"
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0141fcddc9807ee093313b2256f1306fbbdc6cda b/test/core/transport/chttp2/hpack_parser_corpus/0141fcddc9807ee093313b2256f1306fbbdc6cda
new file mode 100644
index 0000000..76b1250
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0141fcddc9807ee093313b2256f1306fbbdc6cda
@@ -0,0 +1 @@
+(?¤¤¤Û¤Ûð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0255050a9ccb25f46d6c1bf6a5a8a4c0c7635599 b/test/core/transport/chttp2/hpack_parser_corpus/0255050a9ccb25f46d6c1bf6a5a8a4c0c7635599
new file mode 100644
index 0000000..e28a586
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0255050a9ccb25f46d6c1bf6a5a8a4c0c7635599
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0320a995a8c76c64c8a0e0297f632b76d9bc92d6 b/test/core/transport/chttp2/hpack_parser_corpus/0320a995a8c76c64c8a0e0297f632b76d9bc92d6
new file mode 100644
index 0000000..0ea34c4
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0320a995a8c76c64c8a0e0297f632b76d9bc92d6
@@ -0,0 +1 @@
+¤!ƒÛð¤!ƒ¶Ûð*c
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/042091aeac4cc255506b96fa11c7354e699fde76 b/test/core/transport/chttp2/hpack_parser_corpus/042091aeac4cc255506b96fa11c7354e699fde76
new file mode 100644
index 0000000..ce65ec6
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/042091aeac4cc255506b96fa11c7354e699fde76
@@ -0,0 +1 @@
+¤¤ð¤-bin;?0c!(ðK	ð[N!‹c[:¤ð¤-\!õG!):[(!!¤
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0696e7bf7837d98de01c915d3c9d80e5d21b30d2 b/test/core/transport/chttp2/hpack_parser_corpus/0696e7bf7837d98de01c915d3c9d80e5d21b30d2
new file mode 100644
index 0000000..a7936f2
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0696e7bf7837d98de01c915d3c9d80e5d21b30d2
@@ -0,0 +1 @@
+ð[(-bin!	ð(!\	?* ¤®@:ð[
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/06995c2f3f01c7ec50547415dc324c64030b7a3e b/test/core/transport/chttp2/hpack_parser_corpus/06995c2f3f01c7ec50547415dc324c64030b7a3e
new file mode 100644
index 0000000..be20eb5
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/06995c2f3f01c7ec50547415dc324c64030b7a3e
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/06f7ce769fe07804fc842462d4be8c1aa2ba82c2 b/test/core/transport/chttp2/hpack_parser_corpus/06f7ce769fe07804fc842462d4be8c1aa2ba82c2
new file mode 100644
index 0000000..0edc9f9
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/06f7ce769fe07804fc842462d4be8c1aa2ba82c2
@@ -0,0 +1 @@
+®€¤ˆ(cc
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0781b055c85ab8fbd0a3d0080a32e394af8761c4 b/test/core/transport/chttp2/hpack_parser_corpus/0781b055c85ab8fbd0a3d0080a32e394af8761c4
new file mode 100644
index 0000000..ebb1e88
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0781b055c85ab8fbd0a3d0080a32e394af8761c4
@@ -0,0 +1 @@
+¤!ƒÛðð¤!ƒÛððc
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/080e1f19e6061c5bcac31add2095f87f6ce46129 b/test/core/transport/chttp2/hpack_parser_corpus/080e1f19e6061c5bcac31add2095f87f6ce46129
new file mode 100644
index 0000000..e880d55
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/080e1f19e6061c5bcac31add2095f87f6ce46129
@@ -0,0 +1 @@
+;?'cð[(!	ð[N!\	!åGý!*(!	!åGýA)(!)í!¼*)åGýI)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0828169ba82152a8907f1001e3d98804397d4610 b/test/core/transport/chttp2/hpack_parser_corpus/0828169ba82152a8907f1001e3d98804397d4610
new file mode 100644
index 0000000..af778fb
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0828169ba82152a8907f1001e3d98804397d4610
@@ -0,0 +1 @@
+¤¤Ûð!ð	cc'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/08ffc4a4160e9fe6f322c28870a89a41fd9c37d7 b/test/core/transport/chttp2/hpack_parser_corpus/08ffc4a4160e9fe6f322c28870a89a41fd9c37d7
new file mode 100644
index 0000000..e0c8806
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/08ffc4a4160e9fe6f322c28870a89a41fd9c37d7
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/090a7a758898a6e7c9108b7e8a1cb9cda383e707 b/test/core/transport/chttp2/hpack_parser_corpus/090a7a758898a6e7c9108b7e8a1cb9cda383e707
new file mode 100644
index 0000000..93f599d
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/090a7a758898a6e7c9108b7e8a1cb9cda383e707
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'bin	!!?¤Ûð!ð{(-binð	!\	!åé;?Gí[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0940663729501b750a18542e1041cc26385c6148 b/test/core/transport/chttp2/hpack_parser_corpus/0940663729501b750a18542e1041cc26385c6148
new file mode 100644
index 0000000..1e92896
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0940663729501b750a18542e1041cc26385c6148
@@ -0,0 +1 @@
+¤¤ð¤-bin‹äc[ò)('-bi.	*)!?¤Ûâ!ð{(-bi\n!	!	ðåé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0a10bd140c6c5fb109a0816ca061739688a6db9a b/test/core/transport/chttp2/hpack_parser_corpus/0a10bd140c6c5fb109a0816ca061739688a6db9a
new file mode 100644
index 0000000..94a6997
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0a10bd140c6c5fb109a0816ca061739688a6db9a
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0a4d3fda02cdcb7adad1daa80d65780c9c8d1464 b/test/core/transport/chttp2/hpack_parser_corpus/0a4d3fda02cdcb7adad1daa80d65780c9c8d1464
new file mode 100644
index 0000000..389f58b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0a4d3fda02cdcb7adad1daa80d65780c9c8d1464
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0ad812832efa33e086874fbf3496664d3f1b4dbe b/test/core/transport/chttp2/hpack_parser_corpus/0ad812832efa33e086874fbf3496664d3f1b4dbe
new file mode 100644
index 0000000..e4ec780
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0ad812832efa33e086874fbf3496664d3f1b4dbe
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0c9996d4fef87bacd7a001e99a515b3ba3d5788f b/test/core/transport/chttp2/hpack_parser_corpus/0c9996d4fef87bacd7a001e99a515b3ba3d5788f
new file mode 100644
index 0000000..229a890
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0c9996d4fef87bacd7a001e99a515b3ba3d5788f
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0d6210208831fe55951af56cdeee3d54a91a5361 b/test/core/transport/chttp2/hpack_parser_corpus/0d6210208831fe55951af56cdeee3d54a91a5361
new file mode 100644
index 0000000..001fd0b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0d6210208831fe55951af56cdeee3d54a91a5361
@@ -0,0 +1 @@
+f!(!!	i[Ñ!å
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0d784965b2262df7ed7a1eb57b92a718cc76bde8 b/test/core/transport/chttp2/hpack_parser_corpus/0d784965b2262df7ed7a1eb57b92a718cc76bde8
new file mode 100644
index 0000000..398077e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0d784965b2262df7ed7a1eb57b92a718cc76bde8
@@ -0,0 +1 @@
+¤Ê!ð	c'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0dc9e41eedf35ccedf4e2b0d230ead7c4d72fdb2 b/test/core/transport/chttp2/hpack_parser_corpus/0dc9e41eedf35ccedf4e2b0d230ead7c4d72fdb2
new file mode 100644
index 0000000..6019162
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0dc9e41eedf35ccedf4e2b0d230ead7c4d72fdb2
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0dd470c8939ed535de6b36f7b7bfb68aeace493e b/test/core/transport/chttp2/hpack_parser_corpus/0dd470c8939ed535de6b36f7b7bfb68aeace493e
new file mode 100644
index 0000000..ca7cbd0
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0dd470c8939ed535de6b36f7b7bfb68aeace493e
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)('-bh	*!!?¤Ûâ!ð{(-bi\n!	!	ðåé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0e61e471fa6d3405daef4276ee00cf5fc189f378 b/test/core/transport/chttp2/hpack_parser_corpus/0e61e471fa6d3405daef4276ee00cf5fc189f378
new file mode 100644
index 0000000..203837b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0e61e471fa6d3405daef4276ee00cf5fc189f378
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/0e9196f951874edbb5ed098739ea5c8b6c0751c2 b/test/core/transport/chttp2/hpack_parser_corpus/0e9196f951874edbb5ed098739ea5c8b6c0751c2
new file mode 100644
index 0000000..8a3ef9e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/0e9196f951874edbb5ed098739ea5c8b6c0751c2
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/11442d93a554b9e7f9ab02782bbf9443bf6e1ddc b/test/core/transport/chttp2/hpack_parser_corpus/11442d93a554b9e7f9ab02782bbf9443bf6e1ddc
new file mode 100644
index 0000000..fdeb10a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/11442d93a554b9e7f9ab02782bbf9443bf6e1ddc
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/11833b795d04eda5a3af56ef7b3c3a26a8ee3444 b/test/core/transport/chttp2/hpack_parser_corpus/11833b795d04eda5a3af56ef7b3c3a26a8ee3444
new file mode 100644
index 0000000..480a056
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/11833b795d04eda5a3af56ef7b3c3a26a8ee3444
@@ -0,0 +1 @@
+¤¤ð¤-bin‹)['(-cbin	!!?¤Ûð!ð{(-binð	!\	!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/141272316382b0f3e9ec841c735b84e7aa517c3e b/test/core/transport/chttp2/hpack_parser_corpus/141272316382b0f3e9ec841c735b84e7aa517c3e
new file mode 100644
index 0000000..f706bd9
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/141272316382b0f3e9ec841c735b84e7aa517c3e
@@ -0,0 +1 @@
+;?0c!(ðK	ð[N!\!õG![(!!	!åGýA)(!)í!*åG€¾ýA))Ù+©Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/15ae43369798e48c396dfe7d53a21878b96e66c8 b/test/core/transport/chttp2/hpack_parser_corpus/15ae43369798e48c396dfe7d53a21878b96e66c8
new file mode 100644
index 0000000..e4c217c
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/15ae43369798e48c396dfe7d53a21878b96e66c8
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/166bf1843c229d34a2880d234dd166c27bdc11fd b/test/core/transport/chttp2/hpack_parser_corpus/166bf1843c229d34a2880d234dd166c27bdc11fd
new file mode 100644
index 0000000..64fdd96
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/166bf1843c229d34a2880d234dd166c27bdc11fd
@@ -0,0 +1 @@
+¤¤ð¤-bin‹í¤-[c'!)¤bi
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/179e8ac763b4051a953a38b6b3b1f1e1f6cc6c9e b/test/core/transport/chttp2/hpack_parser_corpus/179e8ac763b4051a953a38b6b3b1f1e1f6cc6c9e
new file mode 100644
index 0000000..b576e9f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/179e8ac763b4051a953a38b6b3b1f1e1f6cc6c9e
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/17faf0ba8a491a835d35977a9007b90ab7d30d2a b/test/core/transport/chttp2/hpack_parser_corpus/17faf0ba8a491a835d35977a9007b90ab7d30d2a
new file mode 100644
index 0000000..4830972
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/17faf0ba8a491a835d35977a9007b90ab7d30d2a
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/188f6cf2470e95b228341de305ef839b27f01a5c b/test/core/transport/chttp2/hpack_parser_corpus/188f6cf2470e95b228341de305ef839b27f01a5c
new file mode 100644
index 0000000..75aa45a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/188f6cf2470e95b228341de305ef839b27f01a5c
@@ -0,0 +1 @@
+;?0cð[(!	ð[N!\	!åGý![(!!	!åGýA)(!)í!¼*)åGýA)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/1ab3e52adace335d02e2b5130eb4f7c918add7fd b/test/core/transport/chttp2/hpack_parser_corpus/1ab3e52adace335d02e2b5130eb4f7c918add7fd
new file mode 100644
index 0000000..914e443
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/1ab3e52adace335d02e2b5130eb4f7c918add7fd
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[')(-'bin	!!?¤Ûð!ð{(-banð	!\	!(åé–;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/1b5150514364e2c17f5a4edac1b7af99b936f55a b/test/core/transport/chttp2/hpack_parser_corpus/1b5150514364e2c17f5a4edac1b7af99b936f55a
new file mode 100644
index 0000000..fc2f5a5
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/1b5150514364e2c17f5a4edac1b7af99b936f55a
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/1e8befb98cbaba059d6771abd1680e19484e7723 b/test/core/transport/chttp2/hpack_parser_corpus/1e8befb98cbaba059d6771abd1680e19484e7723
new file mode 100644
index 0000000..6ae0cd1
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/1e8befb98cbaba059d6771abd1680e19484e7723
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/1e9b962969c359bc2ff766704c8ca8e25f5eccfc b/test/core/transport/chttp2/hpack_parser_corpus/1e9b962969c359bc2ff766704c8ca8e25f5eccfc
new file mode 100644
index 0000000..970a912
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/1e9b962969c359bc2ff766704c8ca8e25f5eccfc
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/1f80af104acf41b912bf4a48fb938267e3718719 b/test/core/transport/chttp2/hpack_parser_corpus/1f80af104acf41b912bf4a48fb938267e3718719
new file mode 100644
index 0000000..ae0ab51
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/1f80af104acf41b912bf4a48fb938267e3718719
@@ -0,0 +1 @@
+?*®@:[ðøc	(!!\þ;ð!~	ÛåG¤¤Ûðý!Ðam¤
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/1fcc4afd6f48e83d61ea74970df3ca9dcd8ec291 b/test/core/transport/chttp2/hpack_parser_corpus/1fcc4afd6f48e83d61ea74970df3ca9dcd8ec291
new file mode 100644
index 0000000..68b2d0e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/1fcc4afd6f48e83d61ea74970df3ca9dcd8ec291
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/213a734ccdb813b18ad9f2dd99b7f9967ee1460b b/test/core/transport/chttp2/hpack_parser_corpus/213a734ccdb813b18ad9f2dd99b7f9967ee1460b
new file mode 100644
index 0000000..64ab9ba
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/213a734ccdb813b18ad9f2dd99b7f9967ee1460b
@@ -0,0 +1 @@
+¤¤ð¤-bin‹™[)('-bin	!!?¤Ûð!ð{(-bi\n!	!	ðåé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/2151945f43991c27e123c45dc72b93752a47e65f b/test/core/transport/chttp2/hpack_parser_corpus/2151945f43991c27e123c45dc72b93752a47e65f
new file mode 100644
index 0000000..2715d4e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/2151945f43991c27e123c45dc72b93752a47e65f
@@ -0,0 +1 @@
+ð[(-bin!	ð(!\	!åGý:[(!'ð[(!!	ð[(*!	!å!ýGåGýA)([(	!!å
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/21545d998c27a5a1572a89a552937752432b1c14 b/test/core/transport/chttp2/hpack_parser_corpus/21545d998c27a5a1572a89a552937752432b1c14
new file mode 100644
index 0000000..ccb7d82
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/21545d998c27a5a1572a89a552937752432b1c14
@@ -0,0 +1 @@
+*¤ð¤-bén'ƒ'c)[ði(bn-!?¤Ûð!	ð(!\c
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/23c7443fa1ab713e7c34ec50222b1b8cceaedc65 b/test/core/transport/chttp2/hpack_parser_corpus/23c7443fa1ab713e7c34ec50222b1b8cceaedc65
new file mode 100644
index 0000000..2b22f5c
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/23c7443fa1ab713e7c34ec50222b1b8cceaedc65
@@ -0,0 +1 @@
+¤¤ð¤-bin‹-[c'()bin	!!?¤Ûð!;ð{(-binð	!\	!˜é;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/2445bb2c6779712dc9e14c01fecb7103f8732858 b/test/core/transport/chttp2/hpack_parser_corpus/2445bb2c6779712dc9e14c01fecb7103f8732858
new file mode 100644
index 0000000..7112c43
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/2445bb2c6779712dc9e14c01fecb7103f8732858
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/244b0a20500e31d3c538418800db816b07f4d210 b/test/core/transport/chttp2/hpack_parser_corpus/244b0a20500e31d3c538418800db816b07f4d210
new file mode 100644
index 0000000..f58d558
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/244b0a20500e31d3c538418800db816b07f4d210
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'bin	1!?¤Ûð!;*ð{(-binð	!\	!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/2461b9fa6b5bc4b6424dec5b9a18d4ec7c309112 b/test/core/transport/chttp2/hpack_parser_corpus/2461b9fa6b5bc4b6424dec5b9a18d4ec7c309112
new file mode 100644
index 0000000..bbd1dae
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/2461b9fa6b5bc4b6424dec5b9a18d4ec7c309112
@@ -0,0 +1 @@
+?* ¤®@:ð[øc	(;þ!!\ð	!~	ÛåGý!ðcm:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/24ec2f3e17d3850564788f3fed17a5c586c44658 b/test/core/transport/chttp2/hpack_parser_corpus/24ec2f3e17d3850564788f3fed17a5c586c44658
new file mode 100644
index 0000000..6b6a742
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/24ec2f3e17d3850564788f3fed17a5c586c44658
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/2537b8d6b902b8dfc6e17f194cf7d05ddecf74cf b/test/core/transport/chttp2/hpack_parser_corpus/2537b8d6b902b8dfc6e17f194cf7d05ddecf74cf
new file mode 100644
index 0000000..c0cee4f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/2537b8d6b902b8dfc6e17f194cf7d05ddecf74cf
@@ -0,0 +1 @@
+¤!ƒÛðФ!ƒ:[oððc
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/253ad01acea4b7038edc3f2a8c4a0c0f5c4dcd05 b/test/core/transport/chttp2/hpack_parser_corpus/253ad01acea4b7038edc3f2a8c4a0c0f5c4dcd05
new file mode 100644
index 0000000..cf1dac3
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/253ad01acea4b7038edc3f2a8c4a0c0f5c4dcd05
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'bin	!!?¤Ûð!ð{(-binð	!\	!å7é;?Gí([(!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/256d0bbdbed22f5867a6f503bf082011e61ee12b b/test/core/transport/chttp2/hpack_parser_corpus/256d0bbdbed22f5867a6f503bf082011e61ee12b
new file mode 100644
index 0000000..c5d69b5
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/256d0bbdbed22f5867a6f503bf082011e61ee12b
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/26f0e88adbd8f8cdf778131a35b33ecf8711fa49 b/test/core/transport/chttp2/hpack_parser_corpus/26f0e88adbd8f8cdf778131a35b33ecf8711fa49
new file mode 100644
index 0000000..598576b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/26f0e88adbd8f8cdf778131a35b33ecf8711fa49
@@ -0,0 +1 @@
+¤pƒÛðð¤!ƒÛ')ðc
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/2e5dd8fb9d2a31fad9d681eda697d085b647b57c b/test/core/transport/chttp2/hpack_parser_corpus/2e5dd8fb9d2a31fad9d681eda697d085b647b57c
new file mode 100644
index 0000000..689d7f2
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/2e5dd8fb9d2a31fad9d681eda697d085b647b57c
@@ -0,0 +1 @@
+¤!ƒðñ¤!ƒÛð±ðc
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/2fdfd2abf30c636ec8c841f1ac26594e25664f0f b/test/core/transport/chttp2/hpack_parser_corpus/2fdfd2abf30c636ec8c841f1ac26594e25664f0f
new file mode 100644
index 0000000..57727ac
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/2fdfd2abf30c636ec8c841f1ac26594e25664f0f
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/311dac5092e36134d3490f98aa4207425e0ee941 b/test/core/transport/chttp2/hpack_parser_corpus/311dac5092e36134d3490f98aa4207425e0ee941
new file mode 100644
index 0000000..6c900ea
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/311dac5092e36134d3490f98aa4207425e0ee941
@@ -0,0 +1 @@
+ð[(!	ð[(!\	!åGý:[(!![(	!åGýA)(!)í!¸*!!	)
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/320fe6224a5b691c0425e34b6b14e8c6fe9f9620 b/test/core/transport/chttp2/hpack_parser_corpus/320fe6224a5b691c0425e34b6b14e8c6fe9f9620
new file mode 100644
index 0000000..b706187
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/320fe6224a5b691c0425e34b6b14e8c6fe9f9620
@@ -0,0 +1 @@
+* ¤®@ð[:øc	8;'þ!!\ð	!~	ÛDGý!ðkm'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3255f1c7441a7150dc3c33022bfbe8c956c7b7b1 b/test/core/transport/chttp2/hpack_parser_corpus/3255f1c7441a7150dc3c33022bfbe8c956c7b7b1
new file mode 100644
index 0000000..b1c0905
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3255f1c7441a7150dc3c33022bfbe8c956c7b7b1
@@ -0,0 +1 @@
+;?'cð[(!	ð[N!\	!åEý!*(!!	!åGýA)(!)í!¼*)åGýI)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/33bc9db104eb72891fb096f34cbac191b3f9918d b/test/core/transport/chttp2/hpack_parser_corpus/33bc9db104eb72891fb096f34cbac191b3f9918d
new file mode 100644
index 0000000..21f59d4
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/33bc9db104eb72891fb096f34cbac191b3f9918d
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/342ff1db70a7616b4ef76c03a42802c6702c18cb b/test/core/transport/chttp2/hpack_parser_corpus/342ff1db70a7616b4ef76c03a42802c6702c18cb
new file mode 100644
index 0000000..d692193
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/342ff1db70a7616b4ef76c03a42802c6702c18cb
@@ -0,0 +1 @@
+):;!œÊ'ÒØ)*;}v)7IÏ!¤);–-M*±äâ!'d*Cu«‘X$0):ó*;:äÝ;;();:]ïæ@
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/344c011df992ccfc0ec682c14a1cb2d7959998c7 b/test/core/transport/chttp2/hpack_parser_corpus/344c011df992ccfc0ec682c14a1cb2d7959998c7
new file mode 100644
index 0000000..982af7b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/344c011df992ccfc0ec682c14a1cb2d7959998c7
@@ -0,0 +1 @@
+;¤¤ð¤-bin‹c*[)¤¤¤(ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/35775efb9d0d68fa07987b9a84934389b528e436 b/test/core/transport/chttp2/hpack_parser_corpus/35775efb9d0d68fa07987b9a84934389b528e436
new file mode 100644
index 0000000..cd20401
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/35775efb9d0d68fa07987b9a84934389b528e436
@@ -0,0 +1 @@
+?¤Óð!Üð	c'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3650168db6fe115fb1e73eed4b76cd224d977d01 b/test/core/transport/chttp2/hpack_parser_corpus/3650168db6fe115fb1e73eed4b76cd224d977d01
new file mode 100644
index 0000000..99507d2
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3650168db6fe115fb1e73eed4b76cd224d977d01
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c)(-'bin	!!?¤Ûð!ð{(-binð	!\	!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/38228bf98cdb50fd3fa830ba5a9d4c7399063dff b/test/core/transport/chttp2/hpack_parser_corpus/38228bf98cdb50fd3fa830ba5a9d4c7399063dff
new file mode 100644
index 0000000..6fdb662
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/38228bf98cdb50fd3fa830ba5a9d4c7399063dff
@@ -0,0 +1 @@
+* ¤®@:ð[(øc	(;þ!!\	!cåGý:
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/38717bee901151b22a10beb12c6623ccc844d3c2 b/test/core/transport/chttp2/hpack_parser_corpus/38717bee901151b22a10beb12c6623ccc844d3c2
new file mode 100644
index 0000000..164b22a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/38717bee901151b22a10beb12c6623ccc844d3c2
@@ -0,0 +1 @@
+;?.ð[(-bin!	ð(!¤\	!åGý:[(!'ð[(!'cð!	ðc[
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3a4bb427a85bdc5bf66ac71db073c99e0dc9f881 b/test/core/transport/chttp2/hpack_parser_corpus/3a4bb427a85bdc5bf66ac71db073c99e0dc9f881
new file mode 100644
index 0000000..54400a3
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3a4bb427a85bdc5bf66ac71db073c99e0dc9f881
@@ -0,0 +1 @@
+¤ð[('!	ð(!\	!åGý:(!'ð[(!!	¤[ð!ð	cð[(!!	!åGý!åGý'A)([(	'!!å
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3ab48621d9b8f075369099a8ec7517bd23fd6e70 b/test/core/transport/chttp2/hpack_parser_corpus/3ab48621d9b8f075369099a8ec7517bd23fd6e70
new file mode 100644
index 0000000..b243e62
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3ab48621d9b8f075369099a8ec7517bd23fd6e70
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'bin	A!!?¤Ûð!b{ði-(nð	!\	!åé;?Gí!!:[((\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3aec8d9311130dfbb6584fe6e619579c21992b5f b/test/core/transport/chttp2/hpack_parser_corpus/3aec8d9311130dfbb6584fe6e619579c21992b5f
new file mode 100644
index 0000000..345b8b2
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3aec8d9311130dfbb6584fe6e619579c21992b5f
@@ -0,0 +1 @@
+¤¤Ûð¤ƒ
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3b14837f22905dcb04f93aed2aa69bf95924fb9d b/test/core/transport/chttp2/hpack_parser_corpus/3b14837f22905dcb04f93aed2aa69bf95924fb9d
new file mode 100644
index 0000000..dceaf04
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3b14837f22905dcb04f93aed2aa69bf95924fb9d
@@ -0,0 +1 @@
+f*!(!!	i[Ñ!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3be63c163805927e04fd7f84d96122c48240e601 b/test/core/transport/chttp2/hpack_parser_corpus/3be63c163805927e04fd7f84d96122c48240e601
new file mode 100644
index 0000000..1e49a89
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3be63c163805927e04fd7f84d96122c48240e601
@@ -0,0 +1 @@
+¤¤ð¤-bin‹¤Ê!ð	c)[''(
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3bf2e349747c0f539181e0d4084a5fe506811a9e b/test/core/transport/chttp2/hpack_parser_corpus/3bf2e349747c0f539181e0d4084a5fe506811a9e
new file mode 100644
index 0000000..f1e7a8e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3bf2e349747c0f539181e0d4084a5fe506811a9e
@@ -0,0 +1 @@
+¤¤ð¤-bin?ð‹c[)(-'bin	!!?
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3c5af4d73e94d0e8ad5666b6acb340f929031e95 b/test/core/transport/chttp2/hpack_parser_corpus/3c5af4d73e94d0e8ad5666b6acb340f929031e95
new file mode 100644
index 0000000..6d2446a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3c5af4d73e94d0e8ad5666b6acb340f929031e95
@@ -0,0 +1 @@
+¤c
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3d2b25346a9671d83bd082d170a45eed739bae6b b/test/core/transport/chttp2/hpack_parser_corpus/3d2b25346a9671d83bd082d170a45eed739bae6b
new file mode 100644
index 0000000..98ff11f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3d2b25346a9671d83bd082d170a45eed739bae6b
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)¤(*¤;[('¤ð!(-	bni'!!/¤	Ûð!(
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3de7b860c3fba2bc55707fd6875dce276f2f249b b/test/core/transport/chttp2/hpack_parser_corpus/3de7b860c3fba2bc55707fd6875dce276f2f249b
new file mode 100644
index 0000000..7d875fe
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3de7b860c3fba2bc55707fd6875dce276f2f249b
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'bin	!!?¤Ûð!ð{(-binð	!\	!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3e2004ff9f40e398e0f41138a25a8b66e3d843d9 b/test/core/transport/chttp2/hpack_parser_corpus/3e2004ff9f40e398e0f41138a25a8b66e3d843d9
new file mode 100644
index 0000000..ddf6c7c
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3e2004ff9f40e398e0f41138a25a8b66e3d843d9
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/3f8983e457033cc85997c356935ba9c21460e86b b/test/core/transport/chttp2/hpack_parser_corpus/3f8983e457033cc85997c356935ba9c21460e86b
new file mode 100644
index 0000000..0350f5a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/3f8983e457033cc85997c356935ba9c21460e86b
@@ -0,0 +1 @@
+.:¤c
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/4105669086d83a20f8d991088553ba08202478cd b/test/core/transport/chttp2/hpack_parser_corpus/4105669086d83a20f8d991088553ba08202478cd
new file mode 100644
index 0000000..c72af1a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/4105669086d83a20f8d991088553ba08202478cd
@@ -0,0 +1 @@
+¤¤ð¤-bin‹¤Ûð!c[)('-bl	*!!?¤Ûâ!ðð{(-bin\	c!'	!	ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/4180619316eef7912d1cf52ffe85897242e1ae88 b/test/core/transport/chttp2/hpack_parser_corpus/4180619316eef7912d1cf52ffe85897242e1ae88
new file mode 100644
index 0000000..2bfbdf5
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/4180619316eef7912d1cf52ffe85897242e1ae88
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'bin	#!?¤Ûð!ð{(-binð	!\	!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/420291d7139d9246de747739fd98102434a742dd b/test/core/transport/chttp2/hpack_parser_corpus/420291d7139d9246de747739fd98102434a742dd
new file mode 100644
index 0000000..24f6a24
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/420291d7139d9246de747739fd98102434a742dd
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/4256437fc5897c0cd5d755816e4e68c7be326849 b/test/core/transport/chttp2/hpack_parser_corpus/4256437fc5897c0cd5d755816e4e68c7be326849
new file mode 100644
index 0000000..6eebe10
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/4256437fc5897c0cd5d755816e4e68c7be326849
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/42b25a5413c536478a3e63da5adef4250babf2f4 b/test/core/transport/chttp2/hpack_parser_corpus/42b25a5413c536478a3e63da5adef4250babf2f4
new file mode 100644
index 0000000..4616caf
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/42b25a5413c536478a3e63da5adef4250babf2f4
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/42bef44ae751a45c671d9da5b1231d2ac747a48d b/test/core/transport/chttp2/hpack_parser_corpus/42bef44ae751a45c671d9da5b1231d2ac747a48d
new file mode 100644
index 0000000..f9c4871
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/42bef44ae751a45c671d9da5b1231d2ac747a48d
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/438c3c9045c3cf7910aceec34f77b47a70ca4abd b/test/core/transport/chttp2/hpack_parser_corpus/438c3c9045c3cf7910aceec34f77b47a70ca4abd
new file mode 100644
index 0000000..c000da7
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/438c3c9045c3cf7910aceec34f77b47a70ca4abd
@@ -0,0 +1 @@
+ð[(-bin!	ð(!	!åGý:[(!'ð[(¤!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/43af96b4f65ed0ace7236427f2f8833c4835989e b/test/core/transport/chttp2/hpack_parser_corpus/43af96b4f65ed0ace7236427f2f8833c4835989e
new file mode 100644
index 0000000..9fd52af
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/43af96b4f65ed0ace7236427f2f8833c4835989e
@@ -0,0 +1 @@
+¤!ƒÛ*¤ð¤-bin¤¤ððÛðcc'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/44c6119bb91a452d6128ce0ea0d62938800779ea b/test/core/transport/chttp2/hpack_parser_corpus/44c6119bb91a452d6128ce0ea0d62938800779ea
new file mode 100644
index 0000000..3894ad5
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/44c6119bb91a452d6128ce0ea0d62938800779ea
@@ -0,0 +1 @@
+;?0c!(ðK	ð[N!\!åG![(!!	!åGýA)(!)í!*åG€¾ýA)(Ù;Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/46d595331689ae01d77aff387747a98ff3480096 b/test/core/transport/chttp2/hpack_parser_corpus/46d595331689ae01d77aff387747a98ff3480096
new file mode 100644
index 0000000..acb7629
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/46d595331689ae01d77aff387747a98ff3480096
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/471a307b81dc37459087d41532741c5c9d7ba836 b/test/core/transport/chttp2/hpack_parser_corpus/471a307b81dc37459087d41532741c5c9d7ba836
new file mode 100644
index 0000000..da07fc4
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/471a307b81dc37459087d41532741c5c9d7ba836
@@ -0,0 +1 @@
+¤
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/48900b4a5557530922ce45c15ad0d3b0a337520d b/test/core/transport/chttp2/hpack_parser_corpus/48900b4a5557530922ce45c15ad0d3b0a337520d
new file mode 100644
index 0000000..5d9d035
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/48900b4a5557530922ce45c15ad0d3b0a337520d
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/48bcce2c6487b18706ef0c609ca39c456215bac8 b/test/core/transport/chttp2/hpack_parser_corpus/48bcce2c6487b18706ef0c609ca39c456215bac8
new file mode 100644
index 0000000..49a5a11
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/48bcce2c6487b18706ef0c609ca39c456215bac8
@@ -0,0 +1 @@
+¤
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/49027bbd3f3f3cafa315843c8fe8280f86985273 b/test/core/transport/chttp2/hpack_parser_corpus/49027bbd3f3f3cafa315843c8fe8280f86985273
new file mode 100644
index 0000000..5b390fd
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/49027bbd3f3f3cafa315843c8fe8280f86985273
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/499376c5e291da2f9c25999abf4960fab5a92ec8 b/test/core/transport/chttp2/hpack_parser_corpus/499376c5e291da2f9c25999abf4960fab5a92ec8
new file mode 100644
index 0000000..22cebb5
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/499376c5e291da2f9c25999abf4960fab5a92ec8
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/4a3b7ce0cdf217963a0b692769e5d6f4befe73b8 b/test/core/transport/chttp2/hpack_parser_corpus/4a3b7ce0cdf217963a0b692769e5d6f4befe73b8
new file mode 100644
index 0000000..6b93c82
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/4a3b7ce0cdf217963a0b692769e5d6f4befe73b8
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/4a3fdb96bc8c80f1992f0f72f963f84856cbade8 b/test/core/transport/chttp2/hpack_parser_corpus/4a3fdb96bc8c80f1992f0f72f963f84856cbade8
new file mode 100644
index 0000000..3bf6b6e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/4a3fdb96bc8c80f1992f0f72f963f84856cbade8
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/4aae80e05793d7adb42a7e6e8a5283b677318777 b/test/core/transport/chttp2/hpack_parser_corpus/4aae80e05793d7adb42a7e6e8a5283b677318777
new file mode 100644
index 0000000..fc8bdd1
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/4aae80e05793d7adb42a7e6e8a5283b677318777
@@ -0,0 +1 @@
+(B¤:?ðc
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/4c7a034d3a3b4f29d99caf021a0e9bbb89706c2e b/test/core/transport/chttp2/hpack_parser_corpus/4c7a034d3a3b4f29d99caf021a0e9bbb89706c2e
new file mode 100644
index 0000000..778ecf7
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/4c7a034d3a3b4f29d99caf021a0e9bbb89706c2e
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/4ce8a43fb17a075627160812ad26c25210d8a82d b/test/core/transport/chttp2/hpack_parser_corpus/4ce8a43fb17a075627160812ad26c25210d8a82d
new file mode 100644
index 0000000..3a3c61a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/4ce8a43fb17a075627160812ad26c25210d8a82d
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c)(-'*in	!!?¤Ûð!!ð{(-binð	!\H!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/5032a75a98cd14d4dab75c1c5e2cd981abb19dcf b/test/core/transport/chttp2/hpack_parser_corpus/5032a75a98cd14d4dab75c1c5e2cd981abb19dcf
new file mode 100644
index 0000000..e5a06a1
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/5032a75a98cd14d4dab75c1c5e2cd981abb19dcf
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/50b3f4b6aed97f442496d27f3b4315a18ba76d5f b/test/core/transport/chttp2/hpack_parser_corpus/50b3f4b6aed97f442496d27f3b4315a18ba76d5f
new file mode 100644
index 0000000..e2e8f9b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/50b3f4b6aed97f442496d27f3b4315a18ba76d5f
@@ -0,0 +1 @@
+;;?
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/51064b88a98658d48a0da7f1545c2d1293ad9538 b/test/core/transport/chttp2/hpack_parser_corpus/51064b88a98658d48a0da7f1545c2d1293ad9538
new file mode 100644
index 0000000..1b08af8
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/51064b88a98658d48a0da7f1545c2d1293ad9538
@@ -0,0 +1 @@
+*¤ð¤-bin¤¤Û'(?¤ð;[('¤ð!	(
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/51752f12d59fadaaa0dc72e6370612b84ee1555b b/test/core/transport/chttp2/hpack_parser_corpus/51752f12d59fadaaa0dc72e6370612b84ee1555b
new file mode 100644
index 0000000..ebcc009
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/51752f12d59fadaaa0dc72e6370612b84ee1555b
@@ -0,0 +1 @@
+* ¤®@:ð[(øc	(;þ!!\'!cåGý:
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/51eff6fcbfe1a51ceb3f5f2140c01eea89b4313d b/test/core/transport/chttp2/hpack_parser_corpus/51eff6fcbfe1a51ceb3f5f2140c01eea89b4313d
new file mode 100644
index 0000000..b26118f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/51eff6fcbfe1a51ceb3f5f2140c01eea89b4313d
@@ -0,0 +1 @@
+¤¤Ûððƒcc'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/51f65f681cf3a1218d83ad58642c06deaea86210 b/test/core/transport/chttp2/hpack_parser_corpus/51f65f681cf3a1218d83ad58642c06deaea86210
new file mode 100644
index 0000000..103692a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/51f65f681cf3a1218d83ad58642c06deaea86210
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/521809903d36db80b1ccd707f354361f2bf05075 b/test/core/transport/chttp2/hpack_parser_corpus/521809903d36db80b1ccd707f354361f2bf05075
new file mode 100644
index 0000000..06858ed
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/521809903d36db80b1ccd707f354361f2bf05075
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/52fe8f0e1fa270ea16f66c93f2ffab265ce059e8 b/test/core/transport/chttp2/hpack_parser_corpus/52fe8f0e1fa270ea16f66c93f2ffab265ce059e8
new file mode 100644
index 0000000..fcec5d6
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/52fe8f0e1fa270ea16f66c93f2ffab265ce059e8
@@ -0,0 +1 @@
+;?'cð[(!	ð[N!\	bå3Gý!*(!!	BåGýA)(!)í!d*)åGýI)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/53de87ae94acdc8e58a369459c12a3240f1294fe b/test/core/transport/chttp2/hpack_parser_corpus/53de87ae94acdc8e58a369459c12a3240f1294fe
new file mode 100644
index 0000000..aaada4f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/53de87ae94acdc8e58a369459c12a3240f1294fe
@@ -0,0 +1 @@
+?* ¤®@ð:[øc	(;þ!!\ð	!~	ÛåGý!ðcm:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/54a2b3993c3483745f6314c870a038a8e58f97a7 b/test/core/transport/chttp2/hpack_parser_corpus/54a2b3993c3483745f6314c870a038a8e58f97a7
new file mode 100644
index 0000000..ac9c813
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/54a2b3993c3483745f6314c870a038a8e58f97a7
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/55d60c2e5040a38be8ca41de63e137e3fef892a4 b/test/core/transport/chttp2/hpack_parser_corpus/55d60c2e5040a38be8ca41de63e137e3fef892a4
new file mode 100644
index 0000000..c947224
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/55d60c2e5040a38be8ca41de63e137e3fef892a4
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[(*)? ¤®@:
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/5653c44a5b520bdf2bdc599b7966f1d7c44950b3 b/test/core/transport/chttp2/hpack_parser_corpus/5653c44a5b520bdf2bdc599b7966f1d7c44950b3
new file mode 100644
index 0000000..463f1a4
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/5653c44a5b520bdf2bdc599b7966f1d7c44950b3
@@ -0,0 +1 @@
+¤
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/5838b5a683229ebb6e6277e2810863e642b8afc2 b/test/core/transport/chttp2/hpack_parser_corpus/5838b5a683229ebb6e6277e2810863e642b8afc2
new file mode 100644
index 0000000..1bfc596
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/5838b5a683229ebb6e6277e2810863e642b8afc2
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/588d225784891ac88e30ac6eb5651d63fac34083 b/test/core/transport/chttp2/hpack_parser_corpus/588d225784891ac88e30ac6eb5651d63fac34083
new file mode 100644
index 0000000..48c1dfe
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/588d225784891ac88e30ac6eb5651d63fac34083
@@ -0,0 +1 @@
+¤¤ð¤-bin‹!c[)(-'bin	!!?¤Ûð!ð{(-binð	!\	!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/58d51c21a20b6549567a0ab8fee29d162dd3fc5a b/test/core/transport/chttp2/hpack_parser_corpus/58d51c21a20b6549567a0ab8fee29d162dd3fc5a
new file mode 100644
index 0000000..e7e115f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/58d51c21a20b6549567a0ab8fee29d162dd3fc5a
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(;-''bin	!!?¤Ûð!ð{(-binð	!\	!åé;:?íå[((!;!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/58f1036d8ff855841ec25b3c33e85a8fec0d94b7 b/test/core/transport/chttp2/hpack_parser_corpus/58f1036d8ff855841ec25b3c33e85a8fec0d94b7
new file mode 100644
index 0000000..c1c4166
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/58f1036d8ff855841ec25b3c33e85a8fec0d94b7
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)-'bin	1!?¤Ûð!;'*ð{(-binð	!\	!åé;?Gí:[((!!Lð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/5a99df42fb7bbafa2d55714ee235b1c46776b2ad b/test/core/transport/chttp2/hpack_parser_corpus/5a99df42fb7bbafa2d55714ee235b1c46776b2ad
new file mode 100644
index 0000000..198c062
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/5a99df42fb7bbafa2d55714ee235b1c46776b2ad
@@ -0,0 +1 @@
+¤[ð!ð	c'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/5b42793550699b2c015bed677cfcddc052f73513 b/test/core/transport/chttp2/hpack_parser_corpus/5b42793550699b2c015bed677cfcddc052f73513
new file mode 100644
index 0000000..144e68b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/5b42793550699b2c015bed677cfcddc052f73513
@@ -0,0 +1 @@
+¤pƒÛðð¤!ƒÛð)ðc
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/5b8ca72ba00231c38b19f582127e6a146eba4282 b/test/core/transport/chttp2/hpack_parser_corpus/5b8ca72ba00231c38b19f582127e6a146eba4282
new file mode 100644
index 0000000..eb49d1d
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/5b8ca72ba00231c38b19f582127e6a146eba4282
@@ -0,0 +1 @@
+;?'cð[(!	ð[N!\	!åGý!*(!	!ÔåGýA)(!)í!¼*)åGýI)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/5baa13dc95da05e7ba02bbe9583ea24517a29a1a b/test/core/transport/chttp2/hpack_parser_corpus/5baa13dc95da05e7ba02bbe9583ea24517a29a1a
new file mode 100644
index 0000000..4f5a887
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/5baa13dc95da05e7ba02bbe9583ea24517a29a1a
@@ -0,0 +1 @@
+¤¤ð¤-bin‹¤ð[c'!)¤bi
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/5bab61eb53176449e25c2c82f172b82cb13ffb9d b/test/core/transport/chttp2/hpack_parser_corpus/5bab61eb53176449e25c2c82f172b82cb13ffb9d
new file mode 100644
index 0000000..0d758c9
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/5bab61eb53176449e25c2c82f172b82cb13ffb9d
@@ -0,0 +1 @@
+?
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/5c6f6b6f7f3e7b435f060abb73c20d2b773a7f56 b/test/core/transport/chttp2/hpack_parser_corpus/5c6f6b6f7f3e7b435f060abb73c20d2b773a7f56
new file mode 100644
index 0000000..d8e3155
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/5c6f6b6f7f3e7b435f060abb73c20d2b773a7f56
@@ -0,0 +1 @@
+;?0c!(ðK	ð[N!\!åG![(!!	!åGýA)(!)í!*åG€¾A)(Ù;Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/5c9fd9cc7100feaeead1e0e45201945a6e76fd85 b/test/core/transport/chttp2/hpack_parser_corpus/5c9fd9cc7100feaeead1e0e45201945a6e76fd85
new file mode 100644
index 0000000..d38481c
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/5c9fd9cc7100feaeead1e0e45201945a6e76fd85
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/5ff49c9edc7361797a951585f3e180222c8dd95d b/test/core/transport/chttp2/hpack_parser_corpus/5ff49c9edc7361797a951585f3e180222c8dd95d
new file mode 100644
index 0000000..f0ce5a2
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/5ff49c9edc7361797a951585f3e180222c8dd95d
@@ -0,0 +1 @@
+?* ¤®@:ð[(øc	(;þ!!\ð	!c	åÛGý!ðcm:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/6129954942e26c2a9ec071b6659675745613cf3c b/test/core/transport/chttp2/hpack_parser_corpus/6129954942e26c2a9ec071b6659675745613cf3c
new file mode 100644
index 0000000..1ae539b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/6129954942e26c2a9ec071b6659675745613cf3c
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/61fa69b6b51b0ed91914fe48779173f8d26a1d54 b/test/core/transport/chttp2/hpack_parser_corpus/61fa69b6b51b0ed91914fe48779173f8d26a1d54
new file mode 100644
index 0000000..0759d5b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/61fa69b6b51b0ed91914fe48779173f8d26a1d54
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'bin	;!!?¤Ûð!ð{(-binð	!\	!åé;?Gí[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/6362ac61cfb6e964aff78f3cd648475dfd5fd4e9 b/test/core/transport/chttp2/hpack_parser_corpus/6362ac61cfb6e964aff78f3cd648475dfd5fd4e9
new file mode 100644
index 0000000..06af54d
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/6362ac61cfb6e964aff78f3cd648475dfd5fd4e9
@@ -0,0 +1 @@
+;?'cð[(!	ð[N!\	bå3Gý!*(!!	BåGýA)(!)í!¼*)åGýI)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/644deba51c79b6ebd470bd4367452941045d112a b/test/core/transport/chttp2/hpack_parser_corpus/644deba51c79b6ebd470bd4367452941045d112a
new file mode 100644
index 0000000..3357333
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/644deba51c79b6ebd470bd4367452941045d112a
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/64beae98e2276749b133e6368c9e0f19a79eba96 b/test/core/transport/chttp2/hpack_parser_corpus/64beae98e2276749b133e6368c9e0f19a79eba96
new file mode 100644
index 0000000..9aa7b9d
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/64beae98e2276749b133e6368c9e0f19a79eba96
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)¤(-	bni'!!/¤Ûð!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/64d7add9192301fd878854dc96f9fa9053f03992 b/test/core/transport/chttp2/hpack_parser_corpus/64d7add9192301fd878854dc96f9fa9053f03992
new file mode 100644
index 0000000..1203eb1
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/64d7add9192301fd878854dc96f9fa9053f03992
@@ -0,0 +1 @@
+¤!ƒÛððcc'_
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/65566df65e8f55428b6672cc351df414fa8f936c b/test/core/transport/chttp2/hpack_parser_corpus/65566df65e8f55428b6672cc351df414fa8f936c
new file mode 100644
index 0000000..a273e99
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/65566df65e8f55428b6672cc351df414fa8f936c
@@ -0,0 +1 @@
+'ð[(!!	ð[(!!	!åGý!åGýA)(!)í!¼)Ù:;‡Š*
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/65bb703af35d5afb824cd68c41d7a1aeb3848d35 b/test/core/transport/chttp2/hpack_parser_corpus/65bb703af35d5afb824cd68c41d7a1aeb3848d35
new file mode 100644
index 0000000..8ac4292
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/65bb703af35d5afb824cd68c41d7a1aeb3848d35
@@ -0,0 +1 @@
+[ð!ð	'(![(!!	!åGý!åGýA)(!)í!¼)Ù:;‡Š*
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/66c537bf59cb3667c037b3517be3d31245c9da8a b/test/core/transport/chttp2/hpack_parser_corpus/66c537bf59cb3667c037b3517be3d31245c9da8a
new file mode 100644
index 0000000..07cf3ef
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/66c537bf59cb3667c037b3517be3d31245c9da8a
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'bin)#!?¤Ûð!ð{(-binð	!\!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/66f576baeb0c9435a56eb7375dadc5b5d630ed87 b/test/core/transport/chttp2/hpack_parser_corpus/66f576baeb0c9435a56eb7375dadc5b5d630ed87
new file mode 100644
index 0000000..c5a8cc6
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/66f576baeb0c9435a56eb7375dadc5b5d630ed87
@@ -0,0 +1 @@
+?* ¤®P®€¤ˆ:ð[øc	8;þ!!\ð	!~(	ÛDGý!ðmc:c'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/67b4cec5183659aeae0f5bc71b3adf0542a11828 b/test/core/transport/chttp2/hpack_parser_corpus/67b4cec5183659aeae0f5bc71b3adf0542a11828
new file mode 100644
index 0000000..3ad7a92
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/67b4cec5183659aeae0f5bc71b3adf0542a11828
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/68c94721eda2f62481bff9f1d183df70498d0c5b b/test/core/transport/chttp2/hpack_parser_corpus/68c94721eda2f62481bff9f1d183df70498d0c5b
new file mode 100644
index 0000000..cfe8f60
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/68c94721eda2f62481bff9f1d183df70498d0c5b
@@ -0,0 +1 @@
+¤¤ð¤-b!n‹¤-[c'!)¤bi
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/68ee8169a65d58edb9fc1c752ea81dfec383203c b/test/core/transport/chttp2/hpack_parser_corpus/68ee8169a65d58edb9fc1c752ea81dfec383203c
new file mode 100644
index 0000000..2fb6e28
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/68ee8169a65d58edb9fc1c752ea81dfec383203c
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/6b203d49bbba6ee74def0d35c2266e06ad3c45d9 b/test/core/transport/chttp2/hpack_parser_corpus/6b203d49bbba6ee74def0d35c2266e06ad3c45d9
new file mode 100644
index 0000000..bb540ad
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/6b203d49bbba6ee74def0d35c2266e06ad3c45d9
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/6d580f28d785c0bf87ac351a31a89289449feadb b/test/core/transport/chttp2/hpack_parser_corpus/6d580f28d785c0bf87ac351a31a89289449feadb
new file mode 100644
index 0000000..56c98a4
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/6d580f28d785c0bf87ac351a31a89289449feadb
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)¨-.'bi*	!!(?¤Û!ð!:ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/6f231dec759eb2105e09263d53e171de19a92c74 b/test/core/transport/chttp2/hpack_parser_corpus/6f231dec759eb2105e09263d53e171de19a92c74
new file mode 100644
index 0000000..9f2955b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/6f231dec759eb2105e09263d53e171de19a92c74
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/70ff6621a09e4f641538cb1b27e8b382b2f56a94 b/test/core/transport/chttp2/hpack_parser_corpus/70ff6621a09e4f641538cb1b27e8b382b2f56a94
new file mode 100644
index 0000000..cc3c4dd
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/70ff6621a09e4f641538cb1b27e8b382b2f56a94
@@ -0,0 +1 @@
+¤!ƒÛ*¤ð¤-bin¤¦ððÛðcc'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/71981b55f27a1eb6274eda247048fa2c597f5004 b/test/core/transport/chttp2/hpack_parser_corpus/71981b55f27a1eb6274eda247048fa2c597f5004
new file mode 100644
index 0000000..b57b2aa
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/71981b55f27a1eb6274eda247048fa2c597f5004
@@ -0,0 +1 @@
+;?'cð[(!	ð[N!\	!åGý!*(!	!åGýA)(!!í!¼(*)åGýI)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/71c2b0bebf7f0e916e4ab7eb36d47ccca2b9101c b/test/core/transport/chttp2/hpack_parser_corpus/71c2b0bebf7f0e916e4ab7eb36d47ccca2b9101c
new file mode 100644
index 0000000..3a78289
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/71c2b0bebf7f0e916e4ab7eb36d47ccca2b9101c
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/74610e278a5b90aa12ce1beaf222c4306b02ed43 b/test/core/transport/chttp2/hpack_parser_corpus/74610e278a5b90aa12ce1beaf222c4306b02ed43
new file mode 100644
index 0000000..e87f23e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/74610e278a5b90aa12ce1beaf222c4306b02ed43
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[i¤(-'bin	!!?¤Ûð!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/748ee9817eba56ec9938601a0e380c74bad4563f b/test/core/transport/chttp2/hpack_parser_corpus/748ee9817eba56ec9938601a0e380c74bad4563f
new file mode 100644
index 0000000..d0a7c64
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/748ee9817eba56ec9938601a0e380c74bad4563f
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)('-bin	!!?¤Ûð!ð{(-bi\n!	!	ðåé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/7727e3eeb2a48c46bf5a678c300ff8a38b8ffe3a b/test/core/transport/chttp2/hpack_parser_corpus/7727e3eeb2a48c46bf5a678c300ff8a38b8ffe3a
new file mode 100644
index 0000000..5b7c52d
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/7727e3eeb2a48c46bf5a678c300ff8a38b8ffe3a
@@ -0,0 +1 @@
+?* ¤®P®€¤ˆ:ð[øc	8;þ!!\ð	!~(	ÛDGý!ðcmc:c'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/78176d80c1d74c4b1b820d386ae483ac4d1d92b7 b/test/core/transport/chttp2/hpack_parser_corpus/78176d80c1d74c4b1b820d386ae483ac4d1d92b7
new file mode 100644
index 0000000..e9dc85e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/78176d80c1d74c4b1b820d386ae483ac4d1d92b7
@@ -0,0 +1 @@
+(?¤›ð!	c
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/789abb571563a6795220046f76b7cf0ade90743c b/test/core/transport/chttp2/hpack_parser_corpus/789abb571563a6795220046f76b7cf0ade90743c
new file mode 100644
index 0000000..c901c4c
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/789abb571563a6795220046f76b7cf0ade90743c
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-.'bin	!!?¤Ûð!:ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/78f5ff40e5554aa9c31b45f79a7ae9699f93e7fd b/test/core/transport/chttp2/hpack_parser_corpus/78f5ff40e5554aa9c31b45f79a7ae9699f93e7fd
new file mode 100644
index 0000000..74d4392
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/78f5ff40e5554aa9c31b45f79a7ae9699f93e7fd
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/7a28fc2e9c72d51d29e87eed63ed405c9779b5e1 b/test/core/transport/chttp2/hpack_parser_corpus/7a28fc2e9c72d51d29e87eed63ed405c9779b5e1
new file mode 100644
index 0000000..ad5695b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/7a28fc2e9c72d51d29e87eed63ed405c9779b5e1
@@ -0,0 +1 @@
+¤¤Ûððƒ€cc'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/7a42083be21dce7f96edef1f3b3b2fea0bcaeb3f b/test/core/transport/chttp2/hpack_parser_corpus/7a42083be21dce7f96edef1f3b3b2fea0bcaeb3f
new file mode 100644
index 0000000..53ba7aa
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/7a42083be21dce7f96edef1f3b3b2fea0bcaeb3f
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'bin	«!?¤Ûð!;*ð{(-binð	!\	!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/7a51275b11ecb1efec9251390531681c8d6f2481 b/test/core/transport/chttp2/hpack_parser_corpus/7a51275b11ecb1efec9251390531681c8d6f2481
new file mode 100644
index 0000000..5529b96
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/7a51275b11ecb1efec9251390531681c8d6f2481
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/7b9682cd7a3984698f6eac034c59c0f91b4fb83d b/test/core/transport/chttp2/hpack_parser_corpus/7b9682cd7a3984698f6eac034c59c0f91b4fb83d
new file mode 100644
index 0000000..bf413be
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/7b9682cd7a3984698f6eac034c59c0f91b4fb83d
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/7ba7239a29d6183960e3986abc8f19cfb548b905 b/test/core/transport/chttp2/hpack_parser_corpus/7ba7239a29d6183960e3986abc8f19cfb548b905
new file mode 100644
index 0000000..8985a07
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/7ba7239a29d6183960e3986abc8f19cfb548b905
@@ -0,0 +1 @@
+¤!ƒÛððcc'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/7d3b3d5f23d0ede9f7e5dbd1115db58c8a54a213 b/test/core/transport/chttp2/hpack_parser_corpus/7d3b3d5f23d0ede9f7e5dbd1115db58c8a54a213
new file mode 100644
index 0000000..291a16d
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/7d3b3d5f23d0ede9f7e5dbd1115db58c8a54a213
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)¨-'bin	'!!?¤Ûð!ð{;?0c!(-b(inð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8035c81c95dedfc27c3649064f98f49e3e72c21f b/test/core/transport/chttp2/hpack_parser_corpus/8035c81c95dedfc27c3649064f98f49e3e72c21f
new file mode 100644
index 0000000..bf77deb
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8035c81c95dedfc27c3649064f98f49e3e72c21f
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/804e1052842ce4d44b9c775ade2b18fcb8ce7bcf b/test/core/transport/chttp2/hpack_parser_corpus/804e1052842ce4d44b9c775ade2b18fcb8ce7bcf
new file mode 100644
index 0000000..cda608f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/804e1052842ce4d44b9c775ade2b18fcb8ce7bcf
@@ -0,0 +1 @@
+¤¤ð¤-bin‹¤-[c'!)¦bi
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/80514b85933ea9bdd3462595f949c5af24409b87 b/test/core/transport/chttp2/hpack_parser_corpus/80514b85933ea9bdd3462595f949c5af24409b87
new file mode 100644
index 0000000..003033b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/80514b85933ea9bdd3462595f949c5af24409b87
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)¤'(­¤Ûð'ð(ƒcin	!!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8057c32b8bd28a5ec2105d62f2abe8cf69c9f5fc b/test/core/transport/chttp2/hpack_parser_corpus/8057c32b8bd28a5ec2105d62f2abe8cf69c9f5fc
new file mode 100644
index 0000000..a384358
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8057c32b8bd28a5ec2105d62f2abe8cf69c9f5fc
@@ -0,0 +1 @@
+f!(!!c'	i[Ñ!ð[(!!	ð[(!!	!åHý![(!!	!åGýåA)(!)í!¼*)åGýA)(Ù!)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/806a3bd4e078d91adeacedfd3e47ef8ae229244a b/test/core/transport/chttp2/hpack_parser_corpus/806a3bd4e078d91adeacedfd3e47ef8ae229244a
new file mode 100644
index 0000000..2760e03
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/806a3bd4e078d91adeacedfd3e47ef8ae229244a
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[):¤(-¤Ûð'ðbƒcin	!!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8090444f98218e65ff9594789ff22bbea3c0497c b/test/core/transport/chttp2/hpack_parser_corpus/8090444f98218e65ff9594789ff22bbea3c0497c
new file mode 100644
index 0000000..a9663a0
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8090444f98218e65ff9594789ff22bbea3c0497c
@@ -0,0 +1 @@
+Õðcª	Ûð'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/80e516692955d5f224706f268e247858858e16d8 b/test/core/transport/chttp2/hpack_parser_corpus/80e516692955d5f224706f268e247858858e16d8
new file mode 100644
index 0000000..6a23452
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/80e516692955d5f224706f268e247858858e16d8
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/810a1372fa97380265f5529c5043ae96f007f5bb b/test/core/transport/chttp2/hpack_parser_corpus/810a1372fa97380265f5529c5043ae96f007f5bb
new file mode 100644
index 0000000..d5a3aee
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/810a1372fa97380265f5529c5043ae96f007f5bb
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8127597d3c146b2a89579e44daef9d03a0f941ec b/test/core/transport/chttp2/hpack_parser_corpus/8127597d3c146b2a89579e44daef9d03a0f941ec
new file mode 100644
index 0000000..0f7035b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8127597d3c146b2a89579e44daef9d03a0f941ec
@@ -0,0 +1 @@
+*@®¤ :ð[(øc	(;þ!!\	!cå¤Gý:
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/82ed571f8922caa572d13b4cc9b5c5fabafaade9 b/test/core/transport/chttp2/hpack_parser_corpus/82ed571f8922caa572d13b4cc9b5c5fabafaade9
new file mode 100644
index 0000000..42b9598
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/82ed571f8922caa572d13b4cc9b5c5fabafaade9
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'bin	!!?¤!ðÛð{(öbénð	!	\!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8328e86178800f87a3bf6f80749984f45b0cd0e8 b/test/core/transport/chttp2/hpack_parser_corpus/8328e86178800f87a3bf6f80749984f45b0cd0e8
new file mode 100644
index 0000000..8fe5277
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8328e86178800f87a3bf6f80749984f45b0cd0e8
@@ -0,0 +1 @@
+(?*¤!ð¤hemeƒ¤'('¤ð!c	
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/84441efd7d8bdb0ce2fac28f218d3d5d4d77f1d4 b/test/core/transport/chttp2/hpack_parser_corpus/84441efd7d8bdb0ce2fac28f218d3d5d4d77f1d4
new file mode 100644
index 0000000..20ab849
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/84441efd7d8bdb0ce2fac28f218d3d5d4d77f1d4
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/84cbf70f45a64d5a01d1c96367b6d6160134f1ad b/test/core/transport/chttp2/hpack_parser_corpus/84cbf70f45a64d5a01d1c96367b6d6160134f1ad
new file mode 100644
index 0000000..65f4c69
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/84cbf70f45a64d5a01d1c96367b6d6160134f1ad
@@ -0,0 +1 @@
+;?0c!(ðK	ð[N!\!õG![(!!	!åGýA)(!)í!*åG€¾ýA)(Ù+)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/85eb0f4502a51e646dab4ae08eabd90613cdf8e1 b/test/core/transport/chttp2/hpack_parser_corpus/85eb0f4502a51e646dab4ae08eabd90613cdf8e1
new file mode 100644
index 0000000..4ede523
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/85eb0f4502a51e646dab4ae08eabd90613cdf8e1
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/86080f33e4eae21b37863c253ce61eaa13021a97 b/test/core/transport/chttp2/hpack_parser_corpus/86080f33e4eae21b37863c253ce61eaa13021a97
new file mode 100644
index 0000000..8f5c7a8
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/86080f33e4eae21b37863c253ce61eaa13021a97
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/862e3ccf601ee0f7fbd8b23e6811fd50485a118f b/test/core/transport/chttp2/hpack_parser_corpus/862e3ccf601ee0f7fbd8b23e6811fd50485a118f
new file mode 100644
index 0000000..bae722a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/862e3ccf601ee0f7fbd8b23e6811fd50485a118f
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'bin	!!?OÛð!ð{(-b	\ni!ð	!åé;?Gí[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/86bae059b18af8ae263e5ae0022b67da0cfc0fbe b/test/core/transport/chttp2/hpack_parser_corpus/86bae059b18af8ae263e5ae0022b67da0cfc0fbe
new file mode 100644
index 0000000..fc8f2ae
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/86bae059b18af8ae263e5ae0022b67da0cfc0fbe
@@ -0,0 +1 @@
+¤ÿ
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/870f9cc4bd89c6c04c6a51ceae1efa8634627cd6 b/test/core/transport/chttp2/hpack_parser_corpus/870f9cc4bd89c6c04c6a51ceae1efa8634627cd6
new file mode 100644
index 0000000..7d35cc8
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/870f9cc4bd89c6c04c6a51ceae1efa8634627cd6
@@ -0,0 +1 @@
+?*®@:[ðøc	(!!\þ;ð!~	ÛåGý!Ðam:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8762a523cdb78d2344d553fa52a229bd63c44e51 b/test/core/transport/chttp2/hpack_parser_corpus/8762a523cdb78d2344d553fa52a229bd63c44e51
new file mode 100644
index 0000000..e92f115
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8762a523cdb78d2344d553fa52a229bd63c44e51
@@ -0,0 +1 @@
+¤
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/894211571f9153c3c2ea4102541dac69be8aaa9c b/test/core/transport/chttp2/hpack_parser_corpus/894211571f9153c3c2ea4102541dac69be8aaa9c
new file mode 100644
index 0000000..ded03ee
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/894211571f9153c3c2ea4102541dac69be8aaa9c
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/894e9b7832c52acb04bfa994ef53c7105d8db206 b/test/core/transport/chttp2/hpack_parser_corpus/894e9b7832c52acb04bfa994ef53c7105d8db206
new file mode 100644
index 0000000..218bfa3
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/894e9b7832c52acb04bfa994ef53c7105d8db206
@@ -0,0 +1 @@
+?*®@:[ðøc	(!!\þ;ð!~	ÛåGý!Ðam'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8b0e12978b8e2eecf62346e438e47d0993845693 b/test/core/transport/chttp2/hpack_parser_corpus/8b0e12978b8e2eecf62346e438e47d0993845693
new file mode 100644
index 0000000..4cb5926
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8b0e12978b8e2eecf62346e438e47d0993845693
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)( ?¤-'bin	!!?¤:
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8b3fa0bd4f289eff6a04a5205e04baaeafbdf637 b/test/core/transport/chttp2/hpack_parser_corpus/8b3fa0bd4f289eff6a04a5205e04baaeafbdf637
new file mode 100644
index 0000000..573daa7
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8b3fa0bd4f289eff6a04a5205e04baaeafbdf637
@@ -0,0 +1 @@
+¤¤ð¤-bin‹()[c-'bin	!!?¤Ûð!ð{(-binð	!\	!åé;?Gí:[((#!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8d1deedd1e463f8c95129a6f839c380a7c83ab04 b/test/core/transport/chttp2/hpack_parser_corpus/8d1deedd1e463f8c95129a6f839c380a7c83ab04
new file mode 100644
index 0000000..11e43ba
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8d1deedd1e463f8c95129a6f839c380a7c83ab04
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c*[)¤(-¤Ûð'ðbƒcin	!!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8d1e029bd72381e382c87e61b4c5a9741d80d644 b/test/core/transport/chttp2/hpack_parser_corpus/8d1e029bd72381e382c87e61b4c5a9741d80d644
new file mode 100644
index 0000000..a4a1f3c
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8d1e029bd72381e382c87e61b4c5a9741d80d644
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8dd1983889b6632228d4897c365a1e6124d101e1 b/test/core/transport/chttp2/hpack_parser_corpus/8dd1983889b6632228d4897c365a1e6124d101e1
new file mode 100644
index 0000000..3a98220
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8dd1983889b6632228d4897c365a1e6124d101e1
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8dfc2183691385432f92957cff0b2538e5a0ebfa b/test/core/transport/chttp2/hpack_parser_corpus/8dfc2183691385432f92957cff0b2538e5a0ebfa
new file mode 100644
index 0000000..c7552c3
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8dfc2183691385432f92957cff0b2538e5a0ebfa
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8eb9b86b4f0aa79b8ef84b44e1fb03094e7bb426 b/test/core/transport/chttp2/hpack_parser_corpus/8eb9b86b4f0aa79b8ef84b44e1fb03094e7bb426
new file mode 100644
index 0000000..5c87575
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8eb9b86b4f0aa79b8ef84b44e1fb03094e7bb426
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8ec540c36da3814e93da765bf2ff0825b59c1bd0 b/test/core/transport/chttp2/hpack_parser_corpus/8ec540c36da3814e93da765bf2ff0825b59c1bd0
new file mode 100644
index 0000000..828e12f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8ec540c36da3814e93da765bf2ff0825b59c1bd0
@@ -0,0 +1 @@
+¤¤ð¤-binc[)(-'bin	!!?¤Ûð!ð{(-binð	!\	!åŸé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8f1bec32f4b8e64062f5405a096543e61d771076 b/test/core/transport/chttp2/hpack_parser_corpus/8f1bec32f4b8e64062f5405a096543e61d771076
new file mode 100644
index 0000000..24e9fc4
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8f1bec32f4b8e64062f5405a096543e61d771076
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8f3e48c49d0794909f6e8e61e5a4312edf484c33 b/test/core/transport/chttp2/hpack_parser_corpus/8f3e48c49d0794909f6e8e61e5a4312edf484c33
new file mode 100644
index 0000000..3378b55
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8f3e48c49d0794909f6e8e61e5a4312edf484c33
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/8fbbf3c0eaa25b64d0a97a8ee08006539e649199 b/test/core/transport/chttp2/hpack_parser_corpus/8fbbf3c0eaa25b64d0a97a8ee08006539e649199
new file mode 100644
index 0000000..532ee69
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/8fbbf3c0eaa25b64d0a97a8ee08006539e649199
@@ -0,0 +1 @@
+¤c
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/907d0021d42d0fdc867fd02d3609cdce13c8a055 b/test/core/transport/chttp2/hpack_parser_corpus/907d0021d42d0fdc867fd02d3609cdce13c8a055
new file mode 100644
index 0000000..4bff0ff
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/907d0021d42d0fdc867fd02d3609cdce13c8a055
@@ -0,0 +1 @@
+®ð[(€¤-bdin!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/919511c217a3427c22cad4a71aae31a6cd47b193 b/test/core/transport/chttp2/hpack_parser_corpus/919511c217a3427c22cad4a71aae31a6cd47b193
new file mode 100644
index 0000000..fcaef32
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/919511c217a3427c22cad4a71aae31a6cd47b193
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/9267c81c3283da8193c198de05e05fa30631a453 b/test/core/transport/chttp2/hpack_parser_corpus/9267c81c3283da8193c198de05e05fa30631a453
new file mode 100644
index 0000000..34951fe
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/9267c81c3283da8193c198de05e05fa30631a453
@@ -0,0 +1 @@
+?* ¤®@:ð[øc	(!!\þ;ð	!~	ÛåGý!Ðcm:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/92e80997a4237d76f10b70dae2870b7255c97435 b/test/core/transport/chttp2/hpack_parser_corpus/92e80997a4237d76f10b70dae2870b7255c97435
new file mode 100644
index 0000000..0e176e3
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/92e80997a4237d76f10b70dae2870b7255c97435
@@ -0,0 +1 @@
+?* ¤®@:ð[(nc	(;þ!;\ð	!c	ÛåGý!ðcm:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/935322db76f5d4c74c2dc68fc4631915b8e24323 b/test/core/transport/chttp2/hpack_parser_corpus/935322db76f5d4c74c2dc68fc4631915b8e24323
new file mode 100644
index 0000000..cbf58cf
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/935322db76f5d4c74c2dc68fc4631915b8e24323
@@ -0,0 +1 @@
+¤¤Ûð¤1ƒ
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/939f2627ef6263d0176566de267ff3eb910e6a60 b/test/core/transport/chttp2/hpack_parser_corpus/939f2627ef6263d0176566de267ff3eb910e6a60
new file mode 100644
index 0000000..0efdf47
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/939f2627ef6263d0176566de267ff3eb910e6a60
@@ -0,0 +1 @@
+¤¤ð¤-bin‹)['(=cbin	a!?¤Ûð!ð{(-bin¤ð¤Û
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/94adea6a0d9a44bee6f5e88adcee57be9e9e3597 b/test/core/transport/chttp2/hpack_parser_corpus/94adea6a0d9a44bee6f5e88adcee57be9e9e3597
new file mode 100644
index 0000000..78e29a4
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/94adea6a0d9a44bee6f5e88adcee57be9e9e3597
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/94dcbe0d3352bd9b230096b8dce9c6d8d63f9d51 b/test/core/transport/chttp2/hpack_parser_corpus/94dcbe0d3352bd9b230096b8dce9c6d8d63f9d51
new file mode 100644
index 0000000..449c0da
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/94dcbe0d3352bd9b230096b8dce9c6d8d63f9d51
@@ -0,0 +1 @@
+(?8¤¤¤Û!×Ûð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/95dad738f60e3e5eb0f1cdafd91ad461f4418e8f b/test/core/transport/chttp2/hpack_parser_corpus/95dad738f60e3e5eb0f1cdafd91ad461f4418e8f
new file mode 100644
index 0000000..38402df
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/95dad738f60e3e5eb0f1cdafd91ad461f4418e8f
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/960c0a21c9e5c1a61b93b34da3189b0de1c264df b/test/core/transport/chttp2/hpack_parser_corpus/960c0a21c9e5c1a61b93b34da3189b0de1c264df
new file mode 100644
index 0000000..9265e2f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/960c0a21c9e5c1a61b93b34da3189b0de1c264df
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/96903512b1f1dec08206123f024b62d0e31cd4dc b/test/core/transport/chttp2/hpack_parser_corpus/96903512b1f1dec08206123f024b62d0e31cd4dc
new file mode 100644
index 0000000..b8c71bd
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/96903512b1f1dec08206123f024b62d0e31cd4dc
@@ -0,0 +1 @@
+cð[(!	ð[(!\	!åGý![(!!	!åGýA)(!)í!¸*)åGýA)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/96a89c005e8d9992e34cc149b0be096ad0051446 b/test/core/transport/chttp2/hpack_parser_corpus/96a89c005e8d9992e34cc149b0be096ad0051446
new file mode 100644
index 0000000..2ac2d76
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/96a89c005e8d9992e34cc149b0be096ad0051446
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/97db8a66dd513eea47a5a25115508f4e59984854 b/test/core/transport/chttp2/hpack_parser_corpus/97db8a66dd513eea47a5a25115508f4e59984854
new file mode 100644
index 0000000..941f553
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/97db8a66dd513eea47a5a25115508f4e59984854
@@ -0,0 +1 @@
+¤(* ¤®@:ð[(?¤;:('¤ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/98f2cb84ad89550cf56ee54e11f1448ae7287247 b/test/core/transport/chttp2/hpack_parser_corpus/98f2cb84ad89550cf56ee54e11f1448ae7287247
new file mode 100644
index 0000000..252816d
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/98f2cb84ad89550cf56ee54e11f1448ae7287247
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/993497422a59b7f9f0f6db8c867339b5c9e4c978 b/test/core/transport/chttp2/hpack_parser_corpus/993497422a59b7f9f0f6db8c867339b5c9e4c978
new file mode 100644
index 0000000..d1028f3
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/993497422a59b7f9f0f6db8c867339b5c9e4c978
@@ -0,0 +1 @@
+¤¤¤ð-bin‹c[)Î@®?*¤ :
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/999821e3750a7f2c9db663d2d100b4404c225040 b/test/core/transport/chttp2/hpack_parser_corpus/999821e3750a7f2c9db663d2d100b4404c225040
new file mode 100644
index 0000000..eafc765
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/999821e3750a7f2c9db663d2d100b4404c225040
@@ -0,0 +1 @@
+[(!!	![ð!å
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/99b2ed83be40cab431d1940e8de2dc3ebfe9352f b/test/core/transport/chttp2/hpack_parser_corpus/99b2ed83be40cab431d1940e8de2dc3ebfe9352f
new file mode 100644
index 0000000..168a215
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/99b2ed83be40cab431d1940e8de2dc3ebfe9352f
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/99e888b7372b29256dbefd476855ff73584cc00f b/test/core/transport/chttp2/hpack_parser_corpus/99e888b7372b29256dbefd476855ff73584cc00f
new file mode 100644
index 0000000..5173bb4
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/99e888b7372b29256dbefd476855ff73584cc00f
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/9b18087deb3cfafa1b964aa65d8ee980bc61404e b/test/core/transport/chttp2/hpack_parser_corpus/9b18087deb3cfafa1b964aa65d8ee980bc61404e
new file mode 100644
index 0000000..838d0d2
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/9b18087deb3cfafa1b964aa65d8ee980bc61404e
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/9b3c745ea3e313909a228a07b49aae110b02ae4a b/test/core/transport/chttp2/hpack_parser_corpus/9b3c745ea3e313909a228a07b49aae110b02ae4a
new file mode 100644
index 0000000..b7855d7
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/9b3c745ea3e313909a228a07b49aae110b02ae4a
@@ -0,0 +1 @@
+¤pƒÛðð¤!ƒ[ðc
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/9be1ce0ba77758928ff5e9c45139b1624cbe9c2d b/test/core/transport/chttp2/hpack_parser_corpus/9be1ce0ba77758928ff5e9c45139b1624cbe9c2d
new file mode 100644
index 0000000..f10b76b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/9be1ce0ba77758928ff5e9c45139b1624cbe9c2d
@@ -0,0 +1 @@
+¤¤ð¤-bin‹¤-[c'!)¤bi
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/9c703141efd69eb8f32a58133c8035fb585e0f4c b/test/core/transport/chttp2/hpack_parser_corpus/9c703141efd69eb8f32a58133c8035fb585e0f4c
new file mode 100644
index 0000000..e1d551a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/9c703141efd69eb8f32a58133c8035fb585e0f4c
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/9c7f77981677499f0426a0ffb5cb79d5fe55dcb2 b/test/core/transport/chttp2/hpack_parser_corpus/9c7f77981677499f0426a0ffb5cb79d5fe55dcb2
new file mode 100644
index 0000000..dec67b6
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/9c7f77981677499f0426a0ffb5cb79d5fe55dcb2
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'b)n	#!?¤Ûð!ð{(-binð	!\	!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/9ca59e6cadaa5be9af30dfe5620d1bcd70f442e5 b/test/core/transport/chttp2/hpack_parser_corpus/9ca59e6cadaa5be9af30dfe5620d1bcd70f442e5
new file mode 100644
index 0000000..0855a4d
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/9ca59e6cadaa5be9af30dfe5620d1bcd70f442e5
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c*[)¤[((¤-Ûð'ðb!ƒcin	!!	!![ð!å
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/9d139835d91474e8d8361d65698a31b8b38c4f7b b/test/core/transport/chttp2/hpack_parser_corpus/9d139835d91474e8d8361d65698a31b8b38c4f7b
new file mode 100644
index 0000000..4781557
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/9d139835d91474e8d8361d65698a31b8b38c4f7b
@@ -0,0 +1 @@
+?¤Ûð!𤤐ð	c'¤-bin‹¤ò[c'!)¤bi
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/9e2179564a99e96e179c96f28802a0a2759b581c b/test/core/transport/chttp2/hpack_parser_corpus/9e2179564a99e96e179c96f28802a0a2759b581c
new file mode 100644
index 0000000..c60f729
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/9e2179564a99e96e179c96f28802a0a2759b581c
@@ -0,0 +1 @@
+(* ¤®@:ð[(?¤;[('¤ð!	(øc	(;þ!!\	!cråGý:
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/9e56bb3b68d2e2617cb2d2f0f3941f7fc832e462 b/test/core/transport/chttp2/hpack_parser_corpus/9e56bb3b68d2e2617cb2d2f0f3941f7fc832e462
new file mode 100644
index 0000000..ac44166
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/9e56bb3b68d2e2617cb2d2f0f3941f7fc832e462
@@ -0,0 +1 @@
+c'ð[(!!	ð[(!!	!åGý![(!!	!åGýA)(!)í!¼*)åGýA)(Ù!)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/9f318b2c2ff9cf4615bd06ba13bdd086b4ad08c6 b/test/core/transport/chttp2/hpack_parser_corpus/9f318b2c2ff9cf4615bd06ba13bdd086b4ad08c6
new file mode 100644
index 0000000..40a6ab5
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/9f318b2c2ff9cf4615bd06ba13bdd086b4ad08c6
@@ -0,0 +1 @@
+?* ¤®@:ð[øc	(!!\þ;ð!~	ÛåGý!Ðim:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/9f8d90b1480989fc46ea2f1c66cf687638994587 b/test/core/transport/chttp2/hpack_parser_corpus/9f8d90b1480989fc46ea2f1c66cf687638994587
new file mode 100644
index 0000000..6c655aa
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/9f8d90b1480989fc46ea2f1c66cf687638994587
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/a09db5715f0bc3879a0e18e4db5a6b5640b254a3 b/test/core/transport/chttp2/hpack_parser_corpus/a09db5715f0bc3879a0e18e4db5a6b5640b254a3
new file mode 100644
index 0000000..7fff586
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/a09db5715f0bc3879a0e18e4db5a6b5640b254a3
@@ -0,0 +1 @@
+;?0c!(òK	ð[NÔ\	!åG![(!!	!åGýA)(!)í!*å¼G€ýA)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/a0c59a090818bca29d76ccf9843f7e2faf330ddf b/test/core/transport/chttp2/hpack_parser_corpus/a0c59a090818bca29d76ccf9843f7e2faf330ddf
new file mode 100644
index 0000000..d6a316b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/a0c59a090818bca29d76ccf9843f7e2faf330ddf
@@ -0,0 +1 @@
+*¤ð¤-bin¤¤Ûð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/a1cf10478e5e01a0d951c743a3dd45aa5fc409f2 b/test/core/transport/chttp2/hpack_parser_corpus/a1cf10478e5e01a0d951c743a3dd45aa5fc409f2
new file mode 100644
index 0000000..45cce54
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/a1cf10478e5e01a0d951c743a3dd45aa5fc409f2
@@ -0,0 +1 @@
+¤!ƒßðð¤!ƒÛ¤ä
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/a22c0f03f8c005a4612a9dcbcd6a643334c35d2f b/test/core/transport/chttp2/hpack_parser_corpus/a22c0f03f8c005a4612a9dcbcd6a643334c35d2f
new file mode 100644
index 0000000..6a28aa1
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/a22c0f03f8c005a4612a9dcbcd6a643334c35d2f
@@ -0,0 +1 @@
+;?0c!(ðK	ð[NÔ\	!åG![(!!	!åGýA)(!)í!*å¼G€ýA)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/a3154b8ed26b3461f2b091c732da00b63ce8bed3 b/test/core/transport/chttp2/hpack_parser_corpus/a3154b8ed26b3461f2b091c732da00b63ce8bed3
new file mode 100644
index 0000000..cba4e44
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/a3154b8ed26b3461f2b091c732da00b63ce8bed3
@@ -0,0 +1 @@
+¤¤ð¤-bin‹¤-[c'ù)¤bi
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/a84a1ed1a24e753a27adfd3ba806f06fc44f899f b/test/core/transport/chttp2/hpack_parser_corpus/a84a1ed1a24e753a27adfd3ba806f06fc44f899f
new file mode 100644
index 0000000..ba1a5db
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/a84a1ed1a24e753a27adfd3ba806f06fc44f899f
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/a871e7ce66afd4f57702cd1299de06cd08995561 b/test/core/transport/chttp2/hpack_parser_corpus/a871e7ce66afd4f57702cd1299de06cd08995561
new file mode 100644
index 0000000..59295ac
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/a871e7ce66afd4f57702cd1299de06cd08995561
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/a8dc736ea964586b7dcbf2bc065ec4675d1daba3 b/test/core/transport/chttp2/hpack_parser_corpus/a8dc736ea964586b7dcbf2bc065ec4675d1daba3
new file mode 100644
index 0000000..039af40
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/a8dc736ea964586b7dcbf2bc065ec4675d1daba3
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)¤(-'bin	!!?¤Ûð!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/a91a835836c72217824f0b63491d9b623130502a b/test/core/transport/chttp2/hpack_parser_corpus/a91a835836c72217824f0b63491d9b623130502a
new file mode 100644
index 0000000..a61dd28
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/a91a835836c72217824f0b63491d9b623130502a
@@ -0,0 +1 @@
+?* ¤®@:ð[(øc	(;þ!!\ð	!c	ÛåGý!ðcm:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ab97c1f6033dc7d96f69b9e1461fd594c16f4ebf b/test/core/transport/chttp2/hpack_parser_corpus/ab97c1f6033dc7d96f69b9e1461fd594c16f4ebf
new file mode 100644
index 0000000..e359cb7
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ab97c1f6033dc7d96f69b9e1461fd594c16f4ebf
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ac8a8c23acd8c290a11dc7828f7f397957fa6400 b/test/core/transport/chttp2/hpack_parser_corpus/ac8a8c23acd8c290a11dc7828f7f397957fa6400
new file mode 100644
index 0000000..39985fb
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ac8a8c23acd8c290a11dc7828f7f397957fa6400
@@ -0,0 +1 @@
+?* ¦®@:ð[øc	(!!\þ;ð!~	Gý!Ðim:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ac94b2788f5252f9e2e8502c7c75e04bef4c0b76 b/test/core/transport/chttp2/hpack_parser_corpus/ac94b2788f5252f9e2e8502c7c75e04bef4c0b76
new file mode 100644
index 0000000..71cc57a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ac94b2788f5252f9e2e8502c7c75e04bef4c0b76
@@ -0,0 +1 @@
+¤?
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ad03b4f58470c43db6593a35be48989486d754f9 b/test/core/transport/chttp2/hpack_parser_corpus/ad03b4f58470c43db6593a35be48989486d754f9
new file mode 100644
index 0000000..7691001
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ad03b4f58470c43db6593a35be48989486d754f9
@@ -0,0 +1 @@
+¤pƒÛðð¤!ƒÛððc
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/af417c83e831a96fda1bdde99a1af6509ef2df3d b/test/core/transport/chttp2/hpack_parser_corpus/af417c83e831a96fda1bdde99a1af6509ef2df3d
new file mode 100644
index 0000000..3217162
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/af417c83e831a96fda1bdde99a1af6509ef2df3d
@@ -0,0 +1 @@
+(?¤¤¤ÛÛð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/affd292cd2ce3306b4651cc7ec0ec0524cbbae3d b/test/core/transport/chttp2/hpack_parser_corpus/affd292cd2ce3306b4651cc7ec0ec0524cbbae3d
new file mode 100644
index 0000000..4ea1b6b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/affd292cd2ce3306b4651cc7ec0ec0524cbbae3d
@@ -0,0 +1 @@
+¤¤ð¤£bin‹äc[ò)'-bi.	*)!?¤Ûâð{(-bi\n!	!	ðåé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/b0587e6e319f4b56d877e7ed46bc7da9b1e7249c b/test/core/transport/chttp2/hpack_parser_corpus/b0587e6e319f4b56d877e7ed46bc7da9b1e7249c
new file mode 100644
index 0000000..3261071
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/b0587e6e319f4b56d877e7ed46bc7da9b1e7249c
@@ -0,0 +1 @@
+¤):;!œÊ'ÒØ)*;}v)7IÏ!¤);–-M*±äâ!'d*Cu«‘X$0):ó*;:äÝ;;();:]ïæ@
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/b166aa66b5b3ad178bc38aee5768226c8adc082f b/test/core/transport/chttp2/hpack_parser_corpus/b166aa66b5b3ad178bc38aee5768226c8adc082f
new file mode 100644
index 0000000..691e650
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/b166aa66b5b3ad178bc38aee5768226c8adc082f
@@ -0,0 +1 @@
+¤pƒÛð¤!ƒÛðc
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/b1ade0571262c6e5f1d72f6d25ebb513d2055bc9 b/test/core/transport/chttp2/hpack_parser_corpus/b1ade0571262c6e5f1d72f6d25ebb513d2055bc9
new file mode 100644
index 0000000..cc073f4
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/b1ade0571262c6e5f1d72f6d25ebb513d2055bc9
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)('-bi.	*!!?¤Ûâ!ð{(-bi\n!	!	ðåé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/b244c690157ff21d073940ef8c77d1898f37cf8e b/test/core/transport/chttp2/hpack_parser_corpus/b244c690157ff21d073940ef8c77d1898f37cf8e
new file mode 100644
index 0000000..e93670e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/b244c690157ff21d073940ef8c77d1898f37cf8e
@@ -0,0 +1 @@
+¤¤Ûðð	cc'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/b523091ee4f17d20f51f9b5cf82293465cf61780 b/test/core/transport/chttp2/hpack_parser_corpus/b523091ee4f17d20f51f9b5cf82293465cf61780
new file mode 100644
index 0000000..6d66d37
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/b523091ee4f17d20f51f9b5cf82293465cf61780
@@ -0,0 +1 @@
+?* ¤®@ð:[øc	(;þ!!\ð	#~	Ûårý!ðcm:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/b7d4d49ac2c530eb8444a449feb689ee50fd210d b/test/core/transport/chttp2/hpack_parser_corpus/b7d4d49ac2c530eb8444a449feb689ee50fd210d
new file mode 100644
index 0000000..d2cbccc
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/b7d4d49ac2c530eb8444a449feb689ee50fd210d
@@ -0,0 +1 @@
+;?'cð[(!	ð[N!\	#åGý!*(!!	!åGýA)(!)í!¼*)åGýI)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/b855c161121bfa29c6fb22d3c0236fae4af6984e b/test/core/transport/chttp2/hpack_parser_corpus/b855c161121bfa29c6fb22d3c0236fae4af6984e
new file mode 100644
index 0000000..2a4856a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/b855c161121bfa29c6fb22d3c0236fae4af6984e
@@ -0,0 +1 @@
+;?0c!(ðK	ð[N!\;åG![(!!	!åGýA)(!)í!*åG€¾A)(Ù;Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/bcaa71abf23b2e5130e0cc464755fe769bf4aaa7 b/test/core/transport/chttp2/hpack_parser_corpus/bcaa71abf23b2e5130e0cc464755fe769bf4aaa7
new file mode 100644
index 0000000..81d87fa
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/bcaa71abf23b2e5130e0cc464755fe769bf4aaa7
@@ -0,0 +1 @@
+¤¤ð¤-bin‹‰c[)¤(-'bin	!!?¤Ûð!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/bcf4684ce097faa7e9d99b6e93cc2de24f57aee3 b/test/core/transport/chttp2/hpack_parser_corpus/bcf4684ce097faa7e9d99b6e93cc2de24f57aee3
new file mode 100644
index 0000000..3c7fb6e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/bcf4684ce097faa7e9d99b6e93cc2de24f57aee3
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/bdca6504d2ee7925f62e176355bb481344772075 b/test/core/transport/chttp2/hpack_parser_corpus/bdca6504d2ee7925f62e176355bb481344772075
new file mode 100644
index 0000000..de4be31
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/bdca6504d2ee7925f62e176355bb481344772075
@@ -0,0 +1 @@
+;?'cð[(!	ð[N!\	!åGý!*(!!	!åGýA)(!)í!¼*)åGýI)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/beb208fd8675ba7de2ecb12998d2d628d579ca7c b/test/core/transport/chttp2/hpack_parser_corpus/beb208fd8675ba7de2ecb12998d2d628d579ca7c
new file mode 100644
index 0000000..704e797
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/beb208fd8675ba7de2ecb12998d2d628d579ca7c
@@ -0,0 +1 @@
+?* ¤®@:ð[øc	8;þ!!\ð	!~	ÛDGý!ðcm:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/bf0c98689ab81fc32787023300caf9a4175583dc b/test/core/transport/chttp2/hpack_parser_corpus/bf0c98689ab81fc32787023300caf9a4175583dc
new file mode 100644
index 0000000..4f0cbfb
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/bf0c98689ab81fc32787023300caf9a4175583dc
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/bf479e97b39b697e715663de6a1e78dd58d64122 b/test/core/transport/chttp2/hpack_parser_corpus/bf479e97b39b697e715663de6a1e78dd58d64122
new file mode 100644
index 0000000..fb6b7bd
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/bf479e97b39b697e715663de6a1e78dd58d64122
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c*[)¤(¤-Ûð'ðbƒcin	!!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/bf826c96be94d1b42eea0666f7239cc5f699a375 b/test/core/transport/chttp2/hpack_parser_corpus/bf826c96be94d1b42eea0666f7239cc5f699a375
new file mode 100644
index 0000000..cb679b9
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/bf826c96be94d1b42eea0666f7239cc5f699a375
@@ -0,0 +1 @@
+ð[(-bin¤¤ð¤-bin‹c[)(-'bin	!!?¤Ûð!ð{(-binð!	ð(	!!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c17650d19ae4a48abb36739c83d8979453f5705f b/test/core/transport/chttp2/hpack_parser_corpus/c17650d19ae4a48abb36739c83d8979453f5705f
new file mode 100644
index 0000000..482d7db
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c17650d19ae4a48abb36739c83d8979453f5705f
@@ -0,0 +1 @@
+;?0c!(ðK	ð[N!\	!åG![(!!	!åGýA)(!)í!*å¼G€ýA)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c1e5307d88feda2c3b15fc221cba92bcf41622bf b/test/core/transport/chttp2/hpack_parser_corpus/c1e5307d88feda2c3b15fc221cba92bcf41622bf
new file mode 100644
index 0000000..6553242
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c1e5307d88feda2c3b15fc221cba92bcf41622bf
@@ -0,0 +1 @@
+(?*¤ð¤-binƒ¤;[('¤ð!c	
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c249f408c552a0408eab3fe1d1cbeca95cd537c1 b/test/core/transport/chttp2/hpack_parser_corpus/c249f408c552a0408eab3fe1d1cbeca95cd537c1
new file mode 100644
index 0000000..52f518b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c249f408c552a0408eab3fe1d1cbeca95cd537c1
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-b¤¤ð¤-bin‹c[)('-bi.	*!!?¤Ûâ
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c26b460aebc9082c519539069f7e060042989696 b/test/core/transport/chttp2/hpack_parser_corpus/c26b460aebc9082c519539069f7e060042989696
new file mode 100644
index 0000000..7c9ca45
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c26b460aebc9082c519539069f7e060042989696
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(-'bni	!%?¤Ûð!ð{(-binð	!\!åé;?G[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c2eae71daad0d3561ab4d09b8b85372b8d790bc1 b/test/core/transport/chttp2/hpack_parser_corpus/c2eae71daad0d3561ab4d09b8b85372b8d790bc1
new file mode 100644
index 0000000..120b74b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c2eae71daad0d3561ab4d09b8b85372b8d790bc1
@@ -0,0 +1 @@
+;?0c!'ðK	ð[N!\!åG![(!!	!åGýA)(!)í!*åG€¾A)(Ù;Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c37fda8d02e99132a1de99f959596c784ab8a53c b/test/core/transport/chttp2/hpack_parser_corpus/c37fda8d02e99132a1de99f959596c784ab8a53c
new file mode 100644
index 0000000..ced68eb
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c37fda8d02e99132a1de99f959596c784ab8a53c
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c4836760377a7091fb20f4afa9c712875792b9a7 b/test/core/transport/chttp2/hpack_parser_corpus/c4836760377a7091fb20f4afa9c712875792b9a7
new file mode 100644
index 0000000..2d3d63a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c4836760377a7091fb20f4afa9c712875792b9a7
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c48caad597176404f776d532d4baf9faf7655ee2 b/test/core/transport/chttp2/hpack_parser_corpus/c48caad597176404f776d532d4baf9faf7655ee2
new file mode 100644
index 0000000..2c7912f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c48caad597176404f776d532d4baf9faf7655ee2
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c4eff0f59986fc5ab09d5bd95f394292f2882659 b/test/core/transport/chttp2/hpack_parser_corpus/c4eff0f59986fc5ab09d5bd95f394292f2882659
new file mode 100644
index 0000000..5b704f8
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c4eff0f59986fc5ab09d5bd95f394292f2882659
@@ -0,0 +1 @@
+¤¤ð¤-bin)c[)-'bin	1¤¤!?¤Ûð!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c5fc2086d167c8c3a7d9ec778db69c5fa14a59fe b/test/core/transport/chttp2/hpack_parser_corpus/c5fc2086d167c8c3a7d9ec778db69c5fa14a59fe
new file mode 100644
index 0000000..3e28333
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c5fc2086d167c8c3a7d9ec778db69c5fa14a59fe
@@ -0,0 +1 @@
+?* ¤®@:ð_øc	(!!\þ;ð!~	!ÛåGý!Ð;m:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c600877ce547166eb1b9d83afbe128d98767f8a3 b/test/core/transport/chttp2/hpack_parser_corpus/c600877ce547166eb1b9d83afbe128d98767f8a3
new file mode 100644
index 0000000..7e26216
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c600877ce547166eb1b9d83afbe128d98767f8a3
@@ -0,0 +1 @@
+¤¤ð¤-binƒc)-bi	(n'!!?¤Û!ðð{(-binð	!\	!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c6a98fdaf6de78e59e1a149a43f3e42222d650b7 b/test/core/transport/chttp2/hpack_parser_corpus/c6a98fdaf6de78e59e1a149a43f3e42222d650b7
new file mode 100644
index 0000000..efcad33
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c6a98fdaf6de78e59e1a149a43f3e42222d650b7
@@ -0,0 +1 @@
+?* ¬®@ð:[øc	(;þ!\!ð	!~	Û-binåGý!ðcm:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c8d22f7fb4f37f2d8cc7953fa2d599d38d899aec b/test/core/transport/chttp2/hpack_parser_corpus/c8d22f7fb4f37f2d8cc7953fa2d599d38d899aec
new file mode 100644
index 0000000..104ab47
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c8d22f7fb4f37f2d8cc7953fa2d599d38d899aec
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c90951c19b24bac84296e3ec32cdeafe99e99cfb b/test/core/transport/chttp2/hpack_parser_corpus/c90951c19b24bac84296e3ec32cdeafe99e99cfb
new file mode 100644
index 0000000..d43c094
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c90951c19b24bac84296e3ec32cdeafe99e99cfb
@@ -0,0 +1 @@
+?* ¤®@:ð[øc	(!!\þ;ð!~	ÛåGý!Ðam:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/c95ff2a172626efb50e94aa6781feba609820076 b/test/core/transport/chttp2/hpack_parser_corpus/c95ff2a172626efb50e94aa6781feba609820076
new file mode 100644
index 0000000..0a104c7
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/c95ff2a172626efb50e94aa6781feba609820076
@@ -0,0 +1 @@
+ð[(-bin!	ð(!\	!åGý¤!:[(!'ð[(!!	ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ca6c557afb9c571de62e9b65ca6469a6133760da b/test/core/transport/chttp2/hpack_parser_corpus/ca6c557afb9c571de62e9b65ca6469a6133760da
new file mode 100644
index 0000000..4d95be6
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ca6c557afb9c571de62e9b65ca6469a6133760da
@@ -0,0 +1 @@
+?!cð	ß}'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/cb2d0fb23f66c968af2e80d59f71d4c1aed96fbd b/test/core/transport/chttp2/hpack_parser_corpus/cb2d0fb23f66c968af2e80d59f71d4c1aed96fbd
new file mode 100644
index 0000000..1cbb336
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/cb2d0fb23f66c968af2e80d59f71d4c1aed96fbd
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)¤(-¤Ûð'ðbƒcin	!!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/cc60a642cc2037ad3c459a57381b8f65d8d7aa35 b/test/core/transport/chttp2/hpack_parser_corpus/cc60a642cc2037ad3c459a57381b8f65d8d7aa35
new file mode 100644
index 0000000..b2d3847
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/cc60a642cc2037ad3c459a57381b8f65d8d7aa35
@@ -0,0 +1 @@
+?* ¤®@:ð[øã	4;þ!!\ð	!~	ÛDGýðcm:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ccd3b8aa26c52f6d9c607c26ebdf621142aff745 b/test/core/transport/chttp2/hpack_parser_corpus/ccd3b8aa26c52f6d9c607c26ebdf621142aff745
new file mode 100644
index 0000000..fa972a4
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ccd3b8aa26c52f6d9c607c26ebdf621142aff745
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ccdfd1354997eb117bd76b75440a7e4ff20bf564 b/test/core/transport/chttp2/hpack_parser_corpus/ccdfd1354997eb117bd76b75440a7e4ff20bf564
new file mode 100644
index 0000000..718a9e5
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ccdfd1354997eb117bd76b75440a7e4ff20bf564
@@ -0,0 +1 @@
++¤¤ð¤-bin9c[)(-b¤¤ð¤
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/cd7a7b8f08c189e95ae3e2ea44b9015000e823f3 b/test/core/transport/chttp2/hpack_parser_corpus/cd7a7b8f08c189e95ae3e2ea44b9015000e823f3
new file mode 100644
index 0000000..4d63ccb
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/cd7a7b8f08c189e95ae3e2ea44b9015000e823f3
@@ -0,0 +1 @@
+¤¤ð¤-bin‹#Z)¤(-¤b¤	ð¤-bin?ð‹c[)(-ni''bin!!	!/¤!?'ð!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ce05678d812a5f8ae8e115938410116ce9169456 b/test/core/transport/chttp2/hpack_parser_corpus/ce05678d812a5f8ae8e115938410116ce9169456
new file mode 100644
index 0000000..6caf38a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ce05678d812a5f8ae8e115938410116ce9169456
@@ -0,0 +1 @@
+;?0c!(ðK	ð[N!\!åG![(!!	!åGýA)(!)í!*åG€¾ýA)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ce6b642b81373f05baa2a6fe6e9d5d1387046285 b/test/core/transport/chttp2/hpack_parser_corpus/ce6b642b81373f05baa2a6fe6e9d5d1387046285
new file mode 100644
index 0000000..a311265
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ce6b642b81373f05baa2a6fe6e9d5d1387046285
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/cf84d06e4dddb997a79a41f9b6122bf620bbdb4b b/test/core/transport/chttp2/hpack_parser_corpus/cf84d06e4dddb997a79a41f9b6122bf620bbdb4b
new file mode 100644
index 0000000..350c941
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/cf84d06e4dddb997a79a41f9b6122bf620bbdb4b
@@ -0,0 +1 @@
+;?'cð[)!	ð[N!Ü	bå4Gý!*(!!	BåGýA)!)í!¼*)åGýI)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/cfbcc3e8cd65aa8b654688145ade34b8789468a6 b/test/core/transport/chttp2/hpack_parser_corpus/cfbcc3e8cd65aa8b654688145ade34b8789468a6
new file mode 100644
index 0000000..4d7ff3e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/cfbcc3e8cd65aa8b654688145ade34b8789468a6
@@ -0,0 +1 @@
+'?0c!(ðK	ð[N!\!åG![(!!	!åG)Aý(!)å!*åG€A¾)(Ù;;Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/d000502f32ca5620d7745f39ff6be3b547e26a6d b/test/core/transport/chttp2/hpack_parser_corpus/d000502f32ca5620d7745f39ff6be3b547e26a6d
new file mode 100644
index 0000000..a422dc4
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/d000502f32ca5620d7745f39ff6be3b547e26a6d
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/d131f83ee73450ff45565d0c638be7d8beeb30d9 b/test/core/transport/chttp2/hpack_parser_corpus/d131f83ee73450ff45565d0c638be7d8beeb30d9
new file mode 100644
index 0000000..c0404ba
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/d131f83ee73450ff45565d0c638be7d8beeb30d9
@@ -0,0 +1 @@
+¤¤ð¤-bin‹) ¤['(=cbin	a!?äÛð!ð{(-bin¤ð¤
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/d2817b89d7aaa7fa880c077b1a67168ec2f4f0f7 b/test/core/transport/chttp2/hpack_parser_corpus/d2817b89d7aaa7fa880c077b1a67168ec2f4f0f7
new file mode 100644
index 0000000..272be74
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/d2817b89d7aaa7fa880c077b1a67168ec2f4f0f7
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/d3ccd7039dd34baef465c4b78baa7a30312a8f07 b/test/core/transport/chttp2/hpack_parser_corpus/d3ccd7039dd34baef465c4b78baa7a30312a8f07
new file mode 100644
index 0000000..e9cb788
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/d3ccd7039dd34baef465c4b78baa7a30312a8f07
@@ -0,0 +1 @@
+?* ¤®@:ð[(øc	(3þ!!\ð	!c	(ÛåGý!ðcm:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/d4cfaf3b59b22b654d7af80ee6715ce5015bfdc0 b/test/core/transport/chttp2/hpack_parser_corpus/d4cfaf3b59b22b654d7af80ee6715ce5015bfdc0
new file mode 100644
index 0000000..be8b804
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/d4cfaf3b59b22b654d7af80ee6715ce5015bfdc0
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/d5670827c8e8d4c95ac0f738c0790c19916c0336 b/test/core/transport/chttp2/hpack_parser_corpus/d5670827c8e8d4c95ac0f738c0790c19916c0336
new file mode 100644
index 0000000..8c906c5
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/d5670827c8e8d4c95ac0f738c0790c19916c0336
@@ -0,0 +1 @@
+*¤ð¤-bin¤¤¤¸ð¤-Û'(?¤ð;[(
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/d59d7e94863f1ed89cacfbaabf7bc59946036c8f b/test/core/transport/chttp2/hpack_parser_corpus/d59d7e94863f1ed89cacfbaabf7bc59946036c8f
new file mode 100644
index 0000000..ed929eb
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/d59d7e94863f1ed89cacfbaabf7bc59946036c8f
@@ -0,0 +1 @@
+*¤ð¤-binƒ(€'[ði(bn-!? 
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/d76d0c7f24ae3cc3f530d5306b8dcc15290c7ff2 b/test/core/transport/chttp2/hpack_parser_corpus/d76d0c7f24ae3cc3f530d5306b8dcc15290c7ff2
new file mode 100644
index 0000000..81cc0fc
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/d76d0c7f24ae3cc3f530d5306b8dcc15290c7ff2
@@ -0,0 +1 @@
+¤ä—
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/d8b15e9e555ad9900ba4be8cc9f87bef75725b24 b/test/core/transport/chttp2/hpack_parser_corpus/d8b15e9e555ad9900ba4be8cc9f87bef75725b24
new file mode 100644
index 0000000..9ed0c80
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/d8b15e9e555ad9900ba4be8cc9f87bef75725b24
@@ -0,0 +1 @@
+?* ¤®@:ð[øc	(!!\þ;ð!~	ÛåGý!Ðim:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/d9748abd540810c2449c3dd39a0ebb62754e520f b/test/core/transport/chttp2/hpack_parser_corpus/d9748abd540810c2449c3dd39a0ebb62754e520f
new file mode 100644
index 0000000..e55083f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/d9748abd540810c2449c3dd39a0ebb62754e520f
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/da9fc821f0c1e00728b139b36269bc3d21c0a8cc b/test/core/transport/chttp2/hpack_parser_corpus/da9fc821f0c1e00728b139b36269bc3d21c0a8cc
new file mode 100644
index 0000000..e752baf
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/da9fc821f0c1e00728b139b36269bc3d21c0a8cc
@@ -0,0 +1 @@
+¤¤ð¤rbin‹c[)(-'bin	!!?¤Ûð!ð{(-binð	!\	!åé;?G[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/dcd1bd94ad97b4e67fd7e12ff1bf7c039eb17f66 b/test/core/transport/chttp2/hpack_parser_corpus/dcd1bd94ad97b4e67fd7e12ff1bf7c039eb17f66
new file mode 100644
index 0000000..cb9bf61
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/dcd1bd94ad97b4e67fd7e12ff1bf7c039eb17f66
@@ -0,0 +1 @@
+¤¤Û)€ððŽcc'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/dd3ba9b139e13324fc76cd62af84b00ca8b87205 b/test/core/transport/chttp2/hpack_parser_corpus/dd3ba9b139e13324fc76cd62af84b00ca8b87205
new file mode 100644
index 0000000..bad7f60
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/dd3ba9b139e13324fc76cd62af84b00ca8b87205
@@ -0,0 +1 @@
+¤pƒÛðð¤!ƒËTð*
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/de0a9dce0ea4e4bfdcb13f788ae728bf979fed25 b/test/core/transport/chttp2/hpack_parser_corpus/de0a9dce0ea4e4bfdcb13f788ae728bf979fed25
new file mode 100644
index 0000000..5a2a027
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/de0a9dce0ea4e4bfdcb13f788ae728bf979fed25
@@ -0,0 +1 @@
+¤¤ð¤-bin‹#Z)¤(-¤¤	bð¤-bin?ð‹c[)(-ni''bin!;	!/¤!?'ð!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/deb6f9a930d9b31586ede19fd8fd3caae0e5b1f2 b/test/core/transport/chttp2/hpack_parser_corpus/deb6f9a930d9b31586ede19fd8fd3caae0e5b1f2
new file mode 100644
index 0000000..1ceb559
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/deb6f9a930d9b31586ede19fd8fd3caae0e5b1f2
@@ -0,0 +1 @@
+¤¤ð¤-bin‹)['(;-cbin	!!?¤Ûð!ð{(-binð	!\	!åé;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/dee95e0280b70681eddfb68e3b418126c5661e18 b/test/core/transport/chttp2/hpack_parser_corpus/dee95e0280b70681eddfb68e3b418126c5661e18
new file mode 100644
index 0000000..713d178
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/dee95e0280b70681eddfb68e3b418126c5661e18
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/df01203edfa2dfe9e108ddde786ae48235624fef b/test/core/transport/chttp2/hpack_parser_corpus/df01203edfa2dfe9e108ddde786ae48235624fef
new file mode 100644
index 0000000..a4520fb
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/df01203edfa2dfe9e108ddde786ae48235624fef
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/df0adbe2523508e9afb42a58d98c2657710d6033 b/test/core/transport/chttp2/hpack_parser_corpus/df0adbe2523508e9afb42a58d98c2657710d6033
new file mode 100644
index 0000000..10b7a9f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/df0adbe2523508e9afb42a58d98c2657710d6033
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e05fcba1b22f658c8bd6f3c330b2b3c9faebf977 b/test/core/transport/chttp2/hpack_parser_corpus/e05fcba1b22f658c8bd6f3c330b2b3c9faebf977
new file mode 100644
index 0000000..6e31189
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e05fcba1b22f658c8bd6f3c330b2b3c9faebf977
@@ -0,0 +1 @@
+ð[(-`in¤¤ð¤-Þin‹c[)(:'bin	!!)?¤Ûð!ð{(:-binð!	ð(	!!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e145caa75d73e3d819a9cb4b6217f1f53112f3f8 b/test/core/transport/chttp2/hpack_parser_corpus/e145caa75d73e3d819a9cb4b6217f1f53112f3f8
new file mode 100644
index 0000000..df57477
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e145caa75d73e3d819a9cb4b6217f1f53112f3f8
@@ -0,0 +1 @@
+¤!ƒßð¤!ƒÛ¤ð¤¤-binƒc[-'bä:nð	!?¤Ûð!(!\ð	c
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e1d86c0094657386197d191855b5645ac1dd5936 b/test/core/transport/chttp2/hpack_parser_corpus/e1d86c0094657386197d191855b5645ac1dd5936
new file mode 100644
index 0000000..eb157d3
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e1d86c0094657386197d191855b5645ac1dd5936
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e25adf8de44f5978d00b7e8c52aee89c5cd1fe93 b/test/core/transport/chttp2/hpack_parser_corpus/e25adf8de44f5978d00b7e8c52aee89c5cd1fe93
new file mode 100644
index 0000000..bc92a9f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e25adf8de44f5978d00b7e8c52aee89c5cd1fe93
@@ -0,0 +1 @@
+?¤Ûð!ð	c'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e29f05162e3d96d5549f96aa4a54c868535b2847 b/test/core/transport/chttp2/hpack_parser_corpus/e29f05162e3d96d5549f96aa4a54c868535b2847
new file mode 100644
index 0000000..d00c6b4
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e29f05162e3d96d5549f96aa4a54c868535b2847
@@ -0,0 +1 @@
+¤¤Ûððƒcc'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e3a970ac8636d29da3ded328b876ed3550cb3209 b/test/core/transport/chttp2/hpack_parser_corpus/e3a970ac8636d29da3ded328b876ed3550cb3209
new file mode 100644
index 0000000..c989830
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e3a970ac8636d29da3ded328b876ed3550cb3209
@@ -0,0 +1 @@
+¤¤ð¤-bin‹-[c*()bin	!!?¤Ûð!;ð{(-binð	!\	!*é;?Gí:[((!!\ð
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e3cfdc862187b4ec28bd4fb2ced5094bb5b09909 b/test/core/transport/chttp2/hpack_parser_corpus/e3cfdc862187b4ec28bd4fb2ced5094bb5b09909
new file mode 100644
index 0000000..9296f0e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e3cfdc862187b4ec28bd4fb2ced5094bb5b09909
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e4ce52007d001806fc9368b62c124dfc56e8471c b/test/core/transport/chttp2/hpack_parser_corpus/e4ce52007d001806fc9368b62c124dfc56e8471c
new file mode 100644
index 0000000..34de7ad
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e4ce52007d001806fc9368b62c124dfc56e8471c
@@ -0,0 +1 @@
+):;!œÊ'ÒØ)*;}v-7IÏ!¤)–-M*±äâ!'d*Cu«X$0):ó*;:äÝ;;();:]ïæ@
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e52173f0bc3325629046e85e2dc41acc6ba7d1c3 b/test/core/transport/chttp2/hpack_parser_corpus/e52173f0bc3325629046e85e2dc41acc6ba7d1c3
new file mode 100644
index 0000000..84f4753
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e52173f0bc3325629046e85e2dc41acc6ba7d1c3
@@ -0,0 +1 @@
+¤¤ð¤-binc([)¤(¤-Û
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e6589006e3bda4c57247ad66fcd73ac00ee2cbe2 b/test/core/transport/chttp2/hpack_parser_corpus/e6589006e3bda4c57247ad66fcd73ac00ee2cbe2
new file mode 100644
index 0000000..274e09d
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e6589006e3bda4c57247ad66fcd73ac00ee2cbe2
@@ -0,0 +1 @@
+;'cð[(!	ð[N!\‡!åGý!*(!	!åGýA)(!)í!¼*)åGýI)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e6fab7572fb2a1c6e107b6f83cffd103a233d021 b/test/core/transport/chttp2/hpack_parser_corpus/e6fab7572fb2a1c6e107b6f83cffd103a233d021
new file mode 100644
index 0000000..720a576
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e6fab7572fb2a1c6e107b6f83cffd103a233d021
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e790f5d312957dbfd20abdefe4b1735779ff9689 b/test/core/transport/chttp2/hpack_parser_corpus/e790f5d312957dbfd20abdefe4b1735779ff9689
new file mode 100644
index 0000000..b818778
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e790f5d312957dbfd20abdefe4b1735779ff9689
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e8809017a4cf6c1e80a93f661166ead961f26bb4 b/test/core/transport/chttp2/hpack_parser_corpus/e8809017a4cf6c1e80a93f661166ead961f26bb4
new file mode 100644
index 0000000..fce39c6
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e8809017a4cf6c1e80a93f661166ead961f26bb4
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/e9733e973c33b38c2087b7f1deb36688b3b14259 b/test/core/transport/chttp2/hpack_parser_corpus/e9733e973c33b38c2087b7f1deb36688b3b14259
new file mode 100644
index 0000000..b87a36f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/e9733e973c33b38c2087b7f1deb36688b3b14259
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c*[)¤(* ¤®@:ð[(?¤;[('¤ð(-¤Û!	ð'ðb
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ea8134769855d574f6673bf0301eb2e24632c6eb b/test/core/transport/chttp2/hpack_parser_corpus/ea8134769855d574f6673bf0301eb2e24632c6eb
new file mode 100644
index 0000000..0a16a74
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ea8134769855d574f6673bf0301eb2e24632c6eb
@@ -0,0 +1 @@
+ð[(-bin¤¤ð¤-bin‹c[)(-'bin	!!?¤Ûð!ð{(-binð!	ð(	!!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/eb489536e4e5589a93a17cd36669475b8f2a5e1b b/test/core/transport/chttp2/hpack_parser_corpus/eb489536e4e5589a93a17cd36669475b8f2a5e1b
new file mode 100644
index 0000000..ffa9431
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/eb489536e4e5589a93a17cd36669475b8f2a5e1b
@@ -0,0 +1 @@
+¤¤ð¤-bin‹#Z)¤(-¤	b¤ð¤-bin?ð‹c[)(-ni''bin!!	!/¤!?Ûð!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/eb48ebd4d01e5623dd16ae61938b3333fab3ce78 b/test/core/transport/chttp2/hpack_parser_corpus/eb48ebd4d01e5623dd16ae61938b3333fab3ce78
new file mode 100644
index 0000000..b92817b
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/eb48ebd4d01e5623dd16ae61938b3333fab3ce78
@@ -0,0 +1 @@
+¤¤ÛððÜcc'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/eb6ca7624384239c7f7e0d83edb7cc334b7926d7 b/test/core/transport/chttp2/hpack_parser_corpus/eb6ca7624384239c7f7e0d83edb7cc334b7926d7
new file mode 100644
index 0000000..cb68dfd
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/eb6ca7624384239c7f7e0d83edb7cc334b7926d7
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ec9457ad41ed745ea9377ffdb16ad09f981daa7f b/test/core/transport/chttp2/hpack_parser_corpus/ec9457ad41ed745ea9377ffdb16ad09f981daa7f
new file mode 100644
index 0000000..9b15875
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ec9457ad41ed745ea9377ffdb16ad09f981daa7f
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/edff5256a2d60d0e51caef25dc1d6f1643dad6d5 b/test/core/transport/chttp2/hpack_parser_corpus/edff5256a2d60d0e51caef25dc1d6f1643dad6d5
new file mode 100644
index 0000000..5ef662d
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/edff5256a2d60d0e51caef25dc1d6f1643dad6d5
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ee4d9c5d22512da42726f47213ff56404d1d81d1 b/test/core/transport/chttp2/hpack_parser_corpus/ee4d9c5d22512da42726f47213ff56404d1d81d1
new file mode 100644
index 0000000..cd45daf
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ee4d9c5d22512da42726f47213ff56404d1d81d1
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/eef2f30b5e2ecd98ebefb12d57aba8b4ad52d904 b/test/core/transport/chttp2/hpack_parser_corpus/eef2f30b5e2ecd98ebefb12d57aba8b4ad52d904
new file mode 100644
index 0000000..9c27b38
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/eef2f30b5e2ecd98ebefb12d57aba8b4ad52d904
@@ -0,0 +1 @@
+?ð	Û!ðcm'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ef23911de1a27d03d2d4983ca1527e17d6a7092b b/test/core/transport/chttp2/hpack_parser_corpus/ef23911de1a27d03d2d4983ca1527e17d6a7092b
new file mode 100644
index 0000000..4535127
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ef23911de1a27d03d2d4983ca1527e17d6a7092b
@@ -0,0 +1 @@
+0c'ð[(!	ð[(!\	!åGý![(!!	!åGýA)(!)í!¼*)åGýA)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ef5b7fc62a2daecf1e8f928b1fa3ebd028413a41 b/test/core/transport/chttp2/hpack_parser_corpus/ef5b7fc62a2daecf1e8f928b1fa3ebd028413a41
new file mode 100644
index 0000000..c3c6d73
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ef5b7fc62a2daecf1e8f928b1fa3ebd028413a41
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ef718258ca1870198e91a2fbc1eaa90b620673fb b/test/core/transport/chttp2/hpack_parser_corpus/ef718258ca1870198e91a2fbc1eaa90b620673fb
new file mode 100644
index 0000000..be01d46
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ef718258ca1870198e91a2fbc1eaa90b620673fb
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)²(-'bin¤
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/efb46deb37a78f41dd760f6b7203b20956eb114e b/test/core/transport/chttp2/hpack_parser_corpus/efb46deb37a78f41dd760f6b7203b20956eb114e
new file mode 100644
index 0000000..58cc22f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/efb46deb37a78f41dd760f6b7203b20956eb114e
@@ -0,0 +1 @@
+;?0c!(ðK	ðNÔ\	!åG![(!!	!åGýA)(:)í!*å¼G€ýA)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/efdd6824bd2456e3e408e0e84369c4fa3aa14f41 b/test/core/transport/chttp2/hpack_parser_corpus/efdd6824bd2456e3e408e0e84369c4fa3aa14f41
new file mode 100644
index 0000000..0926c63
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/efdd6824bd2456e3e408e0e84369c4fa3aa14f41
@@ -0,0 +1 @@
+0cð[(!	ð[(!\	!åGý![(!!	!åGýA)(!)í!¼*)åGýA)(Ù;)Š
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/efec040a5de1969df5e37e4bc50a0a8f0de341d8 b/test/core/transport/chttp2/hpack_parser_corpus/efec040a5de1969df5e37e4bc50a0a8f0de341d8
new file mode 100644
index 0000000..9e21c0e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/efec040a5de1969df5e37e4bc50a0a8f0de341d8
@@ -0,0 +1 @@
+(?¤:›ð!	c
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/f1e30464c24dc1d7cec7ec1dd2adec8512232b43 b/test/core/transport/chttp2/hpack_parser_corpus/f1e30464c24dc1d7cec7ec1dd2adec8512232b43
new file mode 100644
index 0000000..a217e4f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/f1e30464c24dc1d7cec7ec1dd2adec8512232b43
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/f27a617b936814476770a3b31a5afb80d0f3b423 b/test/core/transport/chttp2/hpack_parser_corpus/f27a617b936814476770a3b31a5afb80d0f3b423
new file mode 100644
index 0000000..ee6ac4e
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/f27a617b936814476770a3b31a5afb80d0f3b423
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/f3f0d99ac2962f8fddb25c65fb4c8c6eb63518a9 b/test/core/transport/chttp2/hpack_parser_corpus/f3f0d99ac2962f8fddb25c65fb4c8c6eb63518a9
new file mode 100644
index 0000000..9b0d16f
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/f3f0d99ac2962f8fddb25c65fb4c8c6eb63518a9
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[)(?* ¤®@:
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/f4628084cf46f139babb886a782b4ab5977d5d2e b/test/core/transport/chttp2/hpack_parser_corpus/f4628084cf46f139babb886a782b4ab5977d5d2e
new file mode 100644
index 0000000..8926de3
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/f4628084cf46f139babb886a782b4ab5977d5d2e
@@ -0,0 +1 @@
+(?¤;[('¤ð!	(
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/f4753e8881e4b3c71f2728149be7d04cc648f6a6 b/test/core/transport/chttp2/hpack_parser_corpus/f4753e8881e4b3c71f2728149be7d04cc648f6a6
new file mode 100644
index 0000000..0c8d290
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/f4753e8881e4b3c71f2728149be7d04cc648f6a6
@@ -0,0 +1 @@
+?* ¤®@Znð:(c	(;þ!(c!	;\	ÛäGý!ðcm:'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/f4d6ff635ae4fda497221da4bfa3e593df59a44e b/test/core/transport/chttp2/hpack_parser_corpus/f4d6ff635ae4fda497221da4bfa3e593df59a44e
new file mode 100644
index 0000000..a7c841c
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/f4d6ff635ae4fda497221da4bfa3e593df59a44e
@@ -0,0 +1 @@
+¤¤ð¤-b)n‹c[)(:* ¤®@1:
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/f52f4d51aaaed0f9c3a20936cf5efd25d0692f67 b/test/core/transport/chttp2/hpack_parser_corpus/f52f4d51aaaed0f9c3a20936cf5efd25d0692f67
new file mode 100644
index 0000000..1ab7be3
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/f52f4d51aaaed0f9c3a20936cf5efd25d0692f67
@@ -0,0 +1 @@
+¤pƒÛðð¤!ƒÛðTð*
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/f7cf30724ab740918eee6e4a6b6658ae3d7706e8 b/test/core/transport/chttp2/hpack_parser_corpus/f7cf30724ab740918eee6e4a6b6658ae3d7706e8
new file mode 100644
index 0000000..669e4a8
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/f7cf30724ab740918eee6e4a6b6658ae3d7706e8
@@ -0,0 +1 @@
+¤c
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/f823828ffd2a60efee36f1de52cb0f024ac5b4bb b/test/core/transport/chttp2/hpack_parser_corpus/f823828ffd2a60efee36f1de52cb0f024ac5b4bb
new file mode 100644
index 0000000..0fee687
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/f823828ffd2a60efee36f1de52cb0f024ac5b4bb
@@ -0,0 +1 @@
+¤Ûð!ð	c'
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/f8760761bd5ab7b47376bfbc5a44e16b2d5ca800 b/test/core/transport/chttp2/hpack_parser_corpus/f8760761bd5ab7b47376bfbc5a44e16b2d5ca800
new file mode 100644
index 0000000..667c246
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/f8760761bd5ab7b47376bfbc5a44e16b2d5ca800
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c[''(-'bin	!!?¤¤cÛð!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/fb15042c268625089ef6c8aa3d8a6f12d1d02c74 b/test/core/transport/chttp2/hpack_parser_corpus/fb15042c268625089ef6c8aa3d8a6f12d1d02c74
new file mode 100644
index 0000000..67f84c5
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/fb15042c268625089ef6c8aa3d8a6f12d1d02c74
@@ -0,0 +1 @@
+ð[(!	ð(!\	!åGý:[(!'ð[(!!	ð[(!!	!åGý!åGýA)([(	!!å
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/fc3dd4292d6884a770199596f5e9cbc1e869e5fb b/test/core/transport/chttp2/hpack_parser_corpus/fc3dd4292d6884a770199596f5e9cbc1e869e5fb
new file mode 100644
index 0000000..99d90a0
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/fc3dd4292d6884a770199596f5e9cbc1e869e5fb
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/fd34ec90fe8f9218fd25c3eac151aec998cff6d8 b/test/core/transport/chttp2/hpack_parser_corpus/fd34ec90fe8f9218fd25c3eac151aec998cff6d8
new file mode 100644
index 0000000..c5005c7
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/fd34ec90fe8f9218fd25c3eac151aec998cff6d8
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/fdf548cde981fab4fb17bd63a124b75eddc5c836 b/test/core/transport/chttp2/hpack_parser_corpus/fdf548cde981fab4fb17bd63a124b75eddc5c836
new file mode 100644
index 0000000..fcae5ce
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/fdf548cde981fab4fb17bd63a124b75eddc5c836
@@ -0,0 +1 @@
+¤¤ð¤-bin‹Ê!ð	c(?¤)['›ð!	c'(
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/fe47fb18b064e26479c3c3140082bd01065e897a b/test/core/transport/chttp2/hpack_parser_corpus/fe47fb18b064e26479c3c3140082bd01065e897a
new file mode 100644
index 0000000..4ed844a
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/fe47fb18b064e26479c3c3140082bd01065e897a
@@ -0,0 +1 @@
+(??;[(¤('?¤
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ff2097734bd7bb8451aece13c9336c4624735170 b/test/core/transport/chttp2/hpack_parser_corpus/ff2097734bd7bb8451aece13c9336c4624735170
new file mode 100644
index 0000000..e8e30c8
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ff2097734bd7bb8451aece13c9336c4624735170
Binary files differ
diff --git a/test/core/transport/chttp2/hpack_parser_corpus/ff7d6ff060e63355701b2e655c802902338497de b/test/core/transport/chttp2/hpack_parser_corpus/ff7d6ff060e63355701b2e655c802902338497de
new file mode 100644
index 0000000..58337fb
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_corpus/ff7d6ff060e63355701b2e655c802902338497de
@@ -0,0 +1 @@
+¤¤ð¤-bin‹c—*[)¤(-¤Ûð'ð!bƒcin	;!!
\ No newline at end of file
diff --git a/test/core/transport/chttp2/hpack_parser_fuzzer_test.c b/test/core/transport/chttp2/hpack_parser_fuzzer_test.c
new file mode 100644
index 0000000..6f77fa0
--- /dev/null
+++ b/test/core/transport/chttp2/hpack_parser_fuzzer_test.c
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+
+#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
+
+static void onhdr(void *ud, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); }
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  grpc_test_only_set_metadata_hash_seed(0);
+  grpc_init();
+  grpc_chttp2_hpack_parser parser;
+  grpc_chttp2_hpack_parser_init(&parser);
+  parser.on_header = onhdr;
+  grpc_chttp2_hpack_parser_parse(&parser, data, data + size);
+  grpc_chttp2_hpack_parser_destroy(&parser);
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/core/transport/chttp2/hpack_parser_test.c b/test/core/transport/chttp2/hpack_parser_test.c
index 4456e19..1ec4797 100644
--- a/test/core/transport/chttp2/hpack_parser_test.c
+++ b/test/core/transport/chttp2/hpack_parser_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/transport/chttp2/hpack_parser.h"
+#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
 
 #include <stdarg.h>
 
diff --git a/test/core/transport/chttp2/hpack_table_test.c b/test/core/transport/chttp2/hpack_table_test.c
index 3c5f2e4..6a2dadf 100644
--- a/test/core/transport/chttp2/hpack_table_test.c
+++ b/test/core/transport/chttp2/hpack_table_test.c
@@ -31,17 +31,17 @@
  *
  */
 
-#include "src/core/transport/chttp2/hpack_table.h"
+#include "src/core/ext/transport/chttp2/transport/hpack_table.h"
 
-#include <string.h>
 #include <stdio.h>
+#include <string.h>
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/support/string.h"
+#include "src/core/lib/support/string.h"
 #include "test/core/util/test_config.h"
 
 #define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x)
diff --git a/test/core/transport/chttp2/status_conversion_test.c b/test/core/transport/chttp2/status_conversion_test.c
index e2729a0..8f39ff3 100644
--- a/test/core/transport/chttp2/status_conversion_test.c
+++ b/test/core/transport/chttp2/status_conversion_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/transport/chttp2/status_conversion.h"
+#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
 #include <grpc/support/log.h>
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/transport/chttp2/stream_map_test.c b/test/core/transport/chttp2/stream_map_test.c
index 527d2fe..c514814 100644
--- a/test/core/transport/chttp2/stream_map_test.c
+++ b/test/core/transport/chttp2/stream_map_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/transport/chttp2/stream_map.h"
+#include "src/core/ext/transport/chttp2/transport/stream_map.h"
 #include <grpc/support/log.h>
 #include "test/core/util/test_config.h"
 
diff --git a/test/core/transport/chttp2/timeout_encoding_test.c b/test/core/transport/chttp2/timeout_encoding_test.c
index 483e79f..7cc698e 100644
--- a/test/core/transport/chttp2/timeout_encoding_test.c
+++ b/test/core/transport/chttp2/timeout_encoding_test.c
@@ -31,16 +31,16 @@
  *
  */
 
-#include "src/core/transport/chttp2/timeout_encoding.h"
+#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
 
 #include <stdio.h>
 #include <string.h>
 
-#include "src/core/support/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/lib/support/string.h"
 #include "test/core/util/test_config.h"
 
 #define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x)
@@ -128,11 +128,10 @@
   decode_suite('H', gpr_time_from_hours);
   assert_decodes_as("1000000000S",
                     gpr_time_from_seconds(1000 * 1000 * 1000, GPR_TIMESPAN));
-  assert_decodes_as("1000000000000000000000u",
-                    gpr_inf_future(GPR_CLOCK_REALTIME));
-  assert_decodes_as("1000000001S", gpr_inf_future(GPR_CLOCK_REALTIME));
-  assert_decodes_as("2000000001S", gpr_inf_future(GPR_CLOCK_REALTIME));
-  assert_decodes_as("9999999999S", gpr_inf_future(GPR_CLOCK_REALTIME));
+  assert_decodes_as("1000000000000000000000u", gpr_inf_future(GPR_TIMESPAN));
+  assert_decodes_as("1000000001S", gpr_inf_future(GPR_TIMESPAN));
+  assert_decodes_as("2000000001S", gpr_inf_future(GPR_TIMESPAN));
+  assert_decodes_as("9999999999S", gpr_inf_future(GPR_TIMESPAN));
 }
 
 void test_decoding_fails(void) {
diff --git a/test/core/transport/chttp2/varint_test.c b/test/core/transport/chttp2/varint_test.c
index f06116a..85c6c84 100644
--- a/test/core/transport/chttp2/varint_test.c
+++ b/test/core/transport/chttp2/varint_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/transport/chttp2/varint.h"
+#include "src/core/ext/transport/chttp2/transport/varint.h"
 
 #include <grpc/support/log.h>
 #include <grpc/support/slice.h>
diff --git a/test/core/transport/connectivity_state_test.c b/test/core/transport/connectivity_state_test.c
index 4b2d0aa..b310d4d 100644
--- a/test/core/transport/connectivity_state_test.c
+++ b/test/core/transport/connectivity_state_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/transport/connectivity_state.h"
+#include "src/core/lib/transport/connectivity_state.h"
 
 #include <string.h>
 
diff --git a/test/core/transport/metadata_test.c b/test/core/transport/metadata_test.c
index 928fba7..836b503 100644
--- a/test/core/transport/metadata_test.c
+++ b/test/core/transport/metadata_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/transport/metadata.h"
+#include "src/core/lib/transport/metadata.h"
 
 #include <stdio.h>
 
@@ -40,8 +40,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/support/string.h"
-#include "src/core/transport/chttp2/bin_encoder.h"
+#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
+#include "src/core/lib/support/string.h"
 #include "test/core/util/test_config.h"
 
 #define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x)
diff --git a/test/core/tsi/transport_security_test.c b/test/core/tsi/transport_security_test.c
index 7ce3439..49b5b8b 100644
--- a/test/core/tsi/transport_security_test.c
+++ b/test/core/tsi/transport_security_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/tsi/transport_security.h"
+#include "src/core/lib/tsi/transport_security.h"
 
 #include <string.h>
 
@@ -42,9 +42,9 @@
 
 #include <openssl/crypto.h>
 
-#include "src/core/support/string.h"
-#include "src/core/tsi/fake_transport_security.h"
-#include "src/core/tsi/ssl_transport_security.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/tsi/fake_transport_security.h"
+#include "src/core/lib/tsi/ssl_transport_security.h"
 #include "test/core/util/test_config.h"
 
 typedef struct {
@@ -61,35 +61,37 @@
      of '#' will be replaced with a null character before processing. */
   const char *dns_names;
 
+  /* Comma separated list of IP SANs to match aggainst */
+  const char *ip_names;
 } cert_name_test_entry;
 
 /* Largely inspired from:
    chromium/src/net/cert/x509_certificate_unittest.cc.
    TODO(jboeuf) uncomment test cases as we fix tsi_ssl_peer_matches_name. */
 const cert_name_test_entry cert_name_test_entries[] = {
-    {1, "foo.com", "foo.com", NULL},
-    {1, "f", "f", NULL},
-    {0, "h", "i", NULL},
-    {1, "bar.foo.com", "*.foo.com", NULL},
+    {1, "foo.com", "foo.com", NULL, NULL},
+    {1, "f", "f", NULL, NULL},
+    {0, "h", "i", NULL, NULL},
+    {1, "bar.foo.com", "*.foo.com", NULL, NULL},
     {1, "www.test.fr", "common.name",
-     "*.test.com,*.test.co.uk,*.test.de,*.test.fr"},
+     "*.test.com,*.test.co.uk,*.test.de,*.test.fr", NULL},
     /*
        {1, "wwW.tESt.fr", "common.name", ",*.*,*.test.de,*.test.FR,www"},
      */
-    {0, "f.uk", ".uk", NULL},
-    {0, "w.bar.foo.com", "?.bar.foo.com", NULL},
-    {0, "www.foo.com", "(www|ftp).foo.com", NULL},
-    {0, "www.foo.com", "www.foo.com#", NULL}, /* # = null char. */
-    {0, "www.foo.com", "", "www.foo.com#*.foo.com,#,#"},
-    {0, "www.house.example", "ww.house.example", NULL},
-    {0, "test.org", "", "www.test.org,*.test.org,*.org"},
-    {0, "w.bar.foo.com", "w*.bar.foo.com", NULL},
-    {0, "www.bar.foo.com", "ww*ww.bar.foo.com", NULL},
-    {0, "wwww.bar.foo.com", "ww*ww.bar.foo.com", NULL},
-    {0, "wwww.bar.foo.com", "w*w.bar.foo.com", NULL},
-    {0, "wwww.bar.foo.com", "w*w.bar.foo.c0m", NULL},
-    {0, "WALLY.bar.foo.com", "wa*.bar.foo.com", NULL},
-    {0, "wally.bar.foo.com", "*Ly.bar.foo.com", NULL},
+    {0, "f.uk", ".uk", NULL, NULL},
+    {0, "w.bar.foo.com", "?.bar.foo.com", NULL, NULL},
+    {0, "www.foo.com", "(www|ftp).foo.com", NULL, NULL},
+    {0, "www.foo.com", "www.foo.com#", NULL, NULL}, /* # = null char. */
+    {0, "www.foo.com", "", "www.foo.com#*.foo.com,#,#", NULL},
+    {0, "www.house.example", "ww.house.example", NULL, NULL},
+    {0, "test.org", "", "www.test.org,*.test.org,*.org", NULL},
+    {0, "w.bar.foo.com", "w*.bar.foo.com", NULL, NULL},
+    {0, "www.bar.foo.com", "ww*ww.bar.foo.com", NULL, NULL},
+    {0, "wwww.bar.foo.com", "ww*ww.bar.foo.com", NULL, NULL},
+    {0, "wwww.bar.foo.com", "w*w.bar.foo.com", NULL, NULL},
+    {0, "wwww.bar.foo.com", "w*w.bar.foo.c0m", NULL, NULL},
+    {0, "WALLY.bar.foo.com", "wa*.bar.foo.com", NULL, NULL},
+    {0, "wally.bar.foo.com", "*Ly.bar.foo.com", NULL, NULL},
     /*
        {1, "ww%57.foo.com", "", "www.foo.com"},
        {1, "www&.foo.com", "www%26.foo.com", NULL},
@@ -97,94 +99,108 @@
 
     /* Common name must not be used if subject alternative name was provided. */
     {0, "www.test.co.jp", "www.test.co.jp",
-     "*.test.de,*.jp,www.test.co.uk,www.*.co.jp"},
+     "*.test.de,*.jp,www.test.co.uk,www.*.co.jp", NULL},
     {0, "www.bar.foo.com", "www.bar.foo.com",
-     "*.foo.com,*.*.foo.com,*.*.bar.foo.com,*..bar.foo.com,"},
+     "*.foo.com,*.*.foo.com,*.*.bar.foo.com,*..bar.foo.com,", NULL},
 
     /* IDN tests */
-    {1, "xn--poema-9qae5a.com.br", "xn--poema-9qae5a.com.br", NULL},
-    {1, "www.xn--poema-9qae5a.com.br", "*.xn--poema-9qae5a.com.br", NULL},
+    {1, "xn--poema-9qae5a.com.br", "xn--poema-9qae5a.com.br", NULL, NULL},
+    {1, "www.xn--poema-9qae5a.com.br", "*.xn--poema-9qae5a.com.br", NULL, NULL},
     {0, "xn--poema-9qae5a.com.br", "",
      "*.xn--poema-9qae5a.com.br,"
      "xn--poema-*.com.br,"
      "xn--*-9qae5a.com.br,"
-     "*--poema-9qae5a.com.br"},
+     "*--poema-9qae5a.com.br",
+     NULL},
 
     /* The following are adapted from the  examples quoted from
        http://tools.ietf.org/html/rfc6125#section-6.4.3
        (e.g., *.example.com would match foo.example.com but
        not bar.foo.example.com or example.com). */
-    {1, "foo.example.com", "*.example.com", NULL},
-    {0, "bar.foo.example.com", "*.example.com", NULL},
-    {0, "example.com", "*.example.com", NULL},
+    {1, "foo.example.com", "*.example.com", NULL, NULL},
+    {0, "bar.foo.example.com", "*.example.com", NULL, NULL},
+    {0, "example.com", "*.example.com", NULL, NULL},
 
     /* Partial wildcards are disallowed, though RFC 2818 rules allow them.
        That is, forms such as baz*.example.net, *baz.example.net, and
        b*z.example.net should NOT match domains. Instead, the wildcard must
        always be the left-most label, and only a single label. */
-    {0, "baz1.example.net", "baz*.example.net", NULL},
-    {0, "foobaz.example.net", "*baz.example.net", NULL},
-    {0, "buzz.example.net", "b*z.example.net", NULL},
-    {0, "www.test.example.net", "www.*.example.net", NULL},
+    {0, "baz1.example.net", "baz*.example.net", NULL, NULL},
+    {0, "foobaz.example.net", "*baz.example.net", NULL, NULL},
+    {0, "buzz.example.net", "b*z.example.net", NULL, NULL},
+    {0, "www.test.example.net", "www.*.example.net", NULL, NULL},
 
     /* Wildcards should not be valid for public registry controlled domains,
        and unknown/unrecognized domains, at least three domain components must
        be present. */
-    {1, "www.test.example", "*.test.example", NULL},
-    {1, "test.example.co.uk", "*.example.co.uk", NULL},
-    {0, "test.example", "*.example", NULL},
+    {1, "www.test.example", "*.test.example", NULL, NULL},
+    {1, "test.example.co.uk", "*.example.co.uk", NULL, NULL},
+    {0, "test.example", "*.example", NULL, NULL},
     /*
        {0, "example.co.uk", "*.co.uk", NULL},
      */
-    {0, "foo.com", "*.com", NULL},
-    {0, "foo.us", "*.us", NULL},
-    {0, "foo", "*", NULL},
+    {0, "foo.com", "*.com", NULL, NULL},
+    {0, "foo.us", "*.us", NULL, NULL},
+    {0, "foo", "*", NULL, NULL},
 
     /* IDN variants of wildcards and registry controlled domains. */
-    {1, "www.xn--poema-9qae5a.com.br", "*.xn--poema-9qae5a.com.br", NULL},
-    {1, "test.example.xn--mgbaam7a8h", "*.example.xn--mgbaam7a8h", NULL},
+    {1, "www.xn--poema-9qae5a.com.br", "*.xn--poema-9qae5a.com.br", NULL, NULL},
+    {1, "test.example.xn--mgbaam7a8h", "*.example.xn--mgbaam7a8h", NULL, NULL},
     /*
        {0, "xn--poema-9qae5a.com.br", "*.com.br", NULL},
      */
-    {0, "example.xn--mgbaam7a8h", "*.xn--mgbaam7a8h", NULL},
+    {0, "example.xn--mgbaam7a8h", "*.xn--mgbaam7a8h", NULL, NULL},
 
     /* Wildcards should be permissible for 'private' registry controlled
        domains. */
-    {1, "www.appspot.com", "*.appspot.com", NULL},
-    {1, "foo.s3.amazonaws.com", "*.s3.amazonaws.com", NULL},
+    {1, "www.appspot.com", "*.appspot.com", NULL, NULL},
+    {1, "foo.s3.amazonaws.com", "*.s3.amazonaws.com", NULL, NULL},
 
     /* Multiple wildcards are not valid. */
-    {0, "foo.example.com", "*.*.com", NULL},
-    {0, "foo.bar.example.com", "*.bar.*.com", NULL},
+    {0, "foo.example.com", "*.*.com", NULL, NULL},
+    {0, "foo.bar.example.com", "*.bar.*.com", NULL, NULL},
 
     /* Absolute vs relative DNS name tests. Although not explicitly specified
        in RFC 6125, absolute reference names (those ending in a .) should
        match either absolute or relative presented names. */
-    {1, "foo.com", "foo.com.", NULL},
-    {1, "foo.com.", "foo.com", NULL},
-    {1, "foo.com.", "foo.com.", NULL},
-    {1, "f", "f.", NULL},
-    {1, "f.", "f", NULL},
-    {1, "f.", "f.", NULL},
-    {1, "www-3.bar.foo.com", "*.bar.foo.com.", NULL},
-    {1, "www-3.bar.foo.com.", "*.bar.foo.com", NULL},
-    {1, "www-3.bar.foo.com.", "*.bar.foo.com.", NULL},
-    {0, ".", ".", NULL},
-    {0, "example.com", "*.com.", NULL},
-    {0, "example.com.", "*.com", NULL},
-    {0, "example.com.", "*.com.", NULL},
-    {0, "foo.", "*.", NULL},
-    {0, "foo", "*.", NULL},
+    {1, "foo.com", "foo.com.", NULL, NULL},
+    {1, "foo.com.", "foo.com", NULL, NULL},
+    {1, "foo.com.", "foo.com.", NULL, NULL},
+    {1, "f", "f.", NULL, NULL},
+    {1, "f.", "f", NULL, NULL},
+    {1, "f.", "f.", NULL, NULL},
+    {1, "www-3.bar.foo.com", "*.bar.foo.com.", NULL, NULL},
+    {1, "www-3.bar.foo.com.", "*.bar.foo.com", NULL, NULL},
+    {1, "www-3.bar.foo.com.", "*.bar.foo.com.", NULL, NULL},
+    {0, ".", ".", NULL, NULL},
+    {0, "example.com", "*.com.", NULL, NULL},
+    {0, "example.com.", "*.com", NULL, NULL},
+    {0, "example.com.", "*.com.", NULL, NULL},
+    {0, "foo.", "*.", NULL, NULL},
+    {0, "foo", "*.", NULL, NULL},
     /*
        {0, "foo.co.uk", "*.co.uk.", NULL},
        {0, "foo.co.uk.", "*.co.uk.", NULL},
      */
 
     /* An empty CN is OK. */
-    {1, "test.foo.com", "", "test.foo.com"},
+    {1, "test.foo.com", "", "test.foo.com", NULL},
 
     /* An IP should not be used for the CN. */
-    {0, "173.194.195.139", "173.194.195.139", NULL},
+    {0, "173.194.195.139", "173.194.195.139", NULL, NULL},
+    /* An IP can be used if the SAN IP is present */
+    {1, "173.194.195.139", "foo.example.com", NULL, "173.194.195.139"},
+    {0, "173.194.195.139", "foo.example.com", NULL, "8.8.8.8"},
+    {0, "173.194.195.139", "foo.example.com", NULL, "8.8.8.8,8.8.4.4"},
+    {1, "173.194.195.139", "foo.example.com", NULL, "8.8.8.8,173.194.195.139"},
+    {0, "173.194.195.139", "foo.example.com", NULL, "173.194.195.13"},
+    {0, "2001:db8:a0b:12f0::1", "foo.example.com", NULL, "173.194.195.13"},
+    {1, "2001:db8:a0b:12f0::1", "foo.example.com", NULL,
+     "2001:db8:a0b:12f0::1"},
+    {0, "2001:db8:a0b:12f0::1", "foo.example.com", NULL,
+     "2001:db8:a0b:12f0::2"},
+    {1, "2001:db8:a0b:12f0::1", "foo.example.com", NULL,
+     "2001:db8:a0b:12f0::2,2001:db8:a0b:12f0::1,8.8.8.8"},
 };
 
 typedef struct name_list {
@@ -196,7 +212,7 @@
   size_t name_count;
   char *buffer;
   name_list *names;
-} parsed_dns_names;
+} parsed_names;
 
 name_list *name_list_add(const char *n) {
   name_list *result = gpr_malloc(sizeof(name_list));
@@ -205,18 +221,18 @@
   return result;
 }
 
-static parsed_dns_names parse_dns_names(const char *dns_names_str) {
-  parsed_dns_names result;
+static parsed_names parse_names(const char *names_str) {
+  parsed_names result;
   name_list *current_nl;
   size_t i;
-  memset(&result, 0, sizeof(parsed_dns_names));
-  if (dns_names_str == 0) return result;
+  memset(&result, 0, sizeof(parsed_names));
+  if (names_str == 0) return result;
   result.name_count = 1;
-  result.buffer = gpr_strdup(dns_names_str);
+  result.buffer = gpr_strdup(names_str);
   result.names = name_list_add(result.buffer);
   current_nl = result.names;
-  for (i = 0; i < strlen(dns_names_str); i++) {
-    if (dns_names_str[i] == ',') {
+  for (i = 0; i < strlen(names_str); i++) {
+    if (names_str[i] == ',') {
       result.buffer[i] = '\0';
       result.name_count++;
       i++;
@@ -227,7 +243,7 @@
   return result;
 }
 
-static void destruct_parsed_dns_names(parsed_dns_names *pdn) {
+static void destruct_parsed_names(parsed_names *pdn) {
   name_list *nl = pdn->names;
   if (pdn->buffer != NULL) gpr_free(pdn->buffer);
   while (nl != NULL) {
@@ -237,8 +253,8 @@
   }
 }
 
-static char *processed_dns_name(const char *dns_name) {
-  char *result = gpr_strdup(dns_name);
+static char *processed_name(const char *name) {
+  char *result = gpr_strdup(name);
   size_t i;
   for (i = 0; i < strlen(result); i++) {
     if (result[i] == '#') {
@@ -253,31 +269,48 @@
   size_t i;
   tsi_peer peer;
   name_list *nl;
-  parsed_dns_names dns_entries = parse_dns_names(entry->dns_names);
+  parsed_names dns_entries = parse_names(entry->dns_names);
+  parsed_names ip_entries = parse_names(entry->ip_names);
   nl = dns_entries.names;
-  GPR_ASSERT(tsi_construct_peer(1 + dns_entries.name_count, &peer) == TSI_OK);
+  GPR_ASSERT(tsi_construct_peer(
+                 1 + dns_entries.name_count + ip_entries.name_count, &peer) ==
+             TSI_OK);
   GPR_ASSERT(tsi_construct_string_peer_property_from_cstring(
                  TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, entry->common_name,
                  &peer.properties[0]) == TSI_OK);
   i = 1;
   while (nl != NULL) {
-    char *processed = processed_dns_name(nl->name);
+    char *processed = processed_name(nl->name);
     GPR_ASSERT(tsi_construct_string_peer_property(
                    TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, processed,
                    strlen(nl->name), &peer.properties[i++]) == TSI_OK);
     nl = nl->next;
     gpr_free(processed);
   }
-  destruct_parsed_dns_names(&dns_entries);
+
+  nl = ip_entries.names;
+  while (nl != NULL) {
+    char *processed = processed_name(nl->name);
+    GPR_ASSERT(tsi_construct_string_peer_property(
+                   TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, processed,
+                   strlen(nl->name), &peer.properties[i++]) == TSI_OK);
+    nl = nl->next;
+    gpr_free(processed);
+  }
+  destruct_parsed_names(&dns_entries);
+  destruct_parsed_names(&ip_entries);
   return peer;
 }
 
 char *cert_name_test_entry_to_string(const cert_name_test_entry *entry) {
   char *s;
-  gpr_asprintf(
-      &s, "{ success = %s, host_name = %s, common_name = %s, dns_names = %s}",
-      entry->expected ? "true" : "false", entry->host_name, entry->common_name,
-      entry->dns_names != NULL ? entry->dns_names : "");
+  gpr_asprintf(&s,
+               "{ success = %s, host_name = %s, common_name = %s, dns_names = "
+               "%s, ip_names = %s}",
+               entry->expected ? "true" : "false", entry->host_name,
+               entry->common_name,
+               entry->dns_names != NULL ? entry->dns_names : "",
+               entry->ip_names != NULL ? entry->ip_names : "");
   return s;
 }
 
diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c
index ba382d2..fea7e52 100644
--- a/test/core/util/port_posix.c
+++ b/test/core/util/port_posix.c
@@ -38,7 +38,6 @@
 #include "test/core/util/port.h"
 
 #include <errno.h>
-#include <math.h>
 #include <netinet/in.h>
 #include <stdio.h>
 #include <string.h>
@@ -50,8 +49,9 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/httpcli/httpcli.h"
-#include "src/core/support/env.h"
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/support/env.h"
+#include "test/core/util/port_server_client.h"
 
 #define NUM_RANDOM_PORTS_TO_PICK 100
 
@@ -68,76 +68,12 @@
   return 0;
 }
 
-typedef struct freereq {
-  gpr_mu *mu;
-  grpc_pollset *pollset;
-  int done;
-} freereq;
-
-static void destroy_pollset_and_shutdown(grpc_exec_ctx *exec_ctx, void *p,
-                                         bool success) {
-  grpc_pollset_destroy(p);
-  grpc_shutdown();
-}
-
-static void freed_port_from_server(grpc_exec_ctx *exec_ctx, void *arg,
-                                   const grpc_httpcli_response *response) {
-  freereq *pr = arg;
-  gpr_mu_lock(pr->mu);
-  pr->done = 1;
-  grpc_pollset_kick(pr->pollset, NULL);
-  gpr_mu_unlock(pr->mu);
-}
-
-static void free_port_using_server(char *server, int port) {
-  grpc_httpcli_context context;
-  grpc_httpcli_request req;
-  freereq pr;
-  char *path;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_closure shutdown_closure;
-
-  grpc_init();
-
-  memset(&pr, 0, sizeof(pr));
-  memset(&req, 0, sizeof(req));
-
-  pr.pollset = gpr_malloc(grpc_pollset_size());
-  grpc_pollset_init(pr.pollset, &pr.mu);
-  grpc_closure_init(&shutdown_closure, destroy_pollset_and_shutdown,
-                    pr.pollset);
-
-  req.host = server;
-  gpr_asprintf(&path, "/drop/%d", port);
-  req.path = path;
-
-  grpc_httpcli_context_init(&context);
-  grpc_httpcli_get(&exec_ctx, &context, pr.pollset, &req,
-                   GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), freed_port_from_server,
-                   &pr);
-  gpr_mu_lock(pr.mu);
-  while (!pr.done) {
-    grpc_pollset_worker *worker = NULL;
-    grpc_pollset_work(&exec_ctx, pr.pollset, &worker,
-                      gpr_now(GPR_CLOCK_MONOTONIC),
-                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1));
-  }
-  gpr_mu_unlock(pr.mu);
-
-  grpc_httpcli_context_destroy(&context);
-  grpc_exec_ctx_finish(&exec_ctx);
-  grpc_pollset_shutdown(&exec_ctx, pr.pollset, &shutdown_closure);
-  grpc_exec_ctx_finish(&exec_ctx);
-  gpr_free(pr.pollset);
-  gpr_free(path);
-}
-
-static void free_chosen_ports() {
+static void free_chosen_ports(void) {
   char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
   if (env != NULL) {
     size_t i;
     for (i = 0; i < num_chosen_ports; i++) {
-      free_port_using_server(env, chosen_ports[i]);
+      grpc_free_port_using_server(env, chosen_ports[i]);
     }
     gpr_free(env);
   }
@@ -205,102 +141,6 @@
   return 1;
 }
 
-typedef struct portreq {
-  gpr_mu *mu;
-  grpc_pollset *pollset;
-  int port;
-  int retries;
-  char *server;
-  grpc_httpcli_context *ctx;
-} portreq;
-
-static void got_port_from_server(grpc_exec_ctx *exec_ctx, void *arg,
-                                 const grpc_httpcli_response *response) {
-  size_t i;
-  int port = 0;
-  portreq *pr = arg;
-  int failed = 0;
-
-  if (!response) {
-    failed = 1;
-    gpr_log(GPR_DEBUG,
-            "failed port pick from server: retrying [response=NULL]");
-  } else if (response->status != 200) {
-    failed = 1;
-    gpr_log(GPR_DEBUG, "failed port pick from server: status=%d",
-            response->status);
-  }
-
-  if (failed) {
-    grpc_httpcli_request req;
-    memset(&req, 0, sizeof(req));
-    GPR_ASSERT(pr->retries < 10);
-    sleep(1 + (unsigned)(pow(1.3, pr->retries) * rand() / RAND_MAX));
-    pr->retries++;
-    req.host = pr->server;
-    req.path = "/get";
-    grpc_httpcli_get(exec_ctx, pr->ctx, pr->pollset, &req,
-                     GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), got_port_from_server,
-                     pr);
-    return;
-  }
-  GPR_ASSERT(response);
-  GPR_ASSERT(response->status == 200);
-  for (i = 0; i < response->body_length; i++) {
-    GPR_ASSERT(response->body[i] >= '0' && response->body[i] <= '9');
-    port = port * 10 + response->body[i] - '0';
-  }
-  GPR_ASSERT(port > 1024);
-  gpr_mu_lock(pr->mu);
-  pr->port = port;
-  grpc_pollset_kick(pr->pollset, NULL);
-  gpr_mu_unlock(pr->mu);
-}
-
-static int pick_port_using_server(char *server) {
-  grpc_httpcli_context context;
-  grpc_httpcli_request req;
-  portreq pr;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_closure shutdown_closure;
-
-  grpc_init();
-
-  memset(&pr, 0, sizeof(pr));
-  memset(&req, 0, sizeof(req));
-  pr.pollset = gpr_malloc(grpc_pollset_size());
-  grpc_pollset_init(pr.pollset, &pr.mu);
-  grpc_closure_init(&shutdown_closure, destroy_pollset_and_shutdown,
-                    pr.pollset);
-  pr.port = -1;
-  pr.server = server;
-  pr.ctx = &context;
-
-  req.host = server;
-  req.path = "/get";
-
-  grpc_httpcli_context_init(&context);
-  grpc_httpcli_get(&exec_ctx, &context, pr.pollset, &req,
-                   GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), got_port_from_server,
-                   &pr);
-  grpc_exec_ctx_finish(&exec_ctx);
-  gpr_mu_lock(pr.mu);
-  while (pr.port == -1) {
-    grpc_pollset_worker *worker = NULL;
-    grpc_pollset_work(&exec_ctx, pr.pollset, &worker,
-                      gpr_now(GPR_CLOCK_MONOTONIC),
-                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1));
-  }
-  gpr_mu_unlock(pr.mu);
-
-  grpc_httpcli_context_destroy(&context);
-  grpc_pollset_shutdown(&exec_ctx, pr.pollset, &shutdown_closure);
-  grpc_exec_ctx_finish(&exec_ctx);
-  gpr_free(pr.pollset);
-
-  return pr.port;
-}
-
 int grpc_pick_unused_port(void) {
   /* We repeatedly pick a port and then see whether or not it is
      available for use both as a TCP socket and a UDP socket.  First, we
@@ -320,7 +160,7 @@
 
   char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
   if (env) {
-    int port = pick_port_using_server(env);
+    int port = grpc_pick_port_using_server(env);
     gpr_free(env);
     if (port != 0) {
       chose_port(port);
diff --git a/test/core/util/port_server_client.c b/test/core/util/port_server_client.c
new file mode 100644
index 0000000..ea01b46
--- /dev/null
+++ b/test/core/util/port_server_client.c
@@ -0,0 +1,215 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+#include "test/core/util/test_config.h"
+
+#ifdef GRPC_TEST_PICK_PORT
+#include "test/core/util/port_server_client.h"
+
+#include <math.h>
+#include <string.h>
+
+#include <grpc/grpc.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/time.h>
+
+#include "src/core/lib/http/httpcli.h"
+
+typedef struct freereq {
+  gpr_mu *mu;
+  grpc_pollset *pollset;
+  int done;
+} freereq;
+
+static void destroy_pollset_and_shutdown(grpc_exec_ctx *exec_ctx, void *p,
+                                         bool success) {
+  grpc_pollset_destroy(p);
+  gpr_free(p);
+  grpc_shutdown();
+}
+
+static void freed_port_from_server(grpc_exec_ctx *exec_ctx, void *arg,
+                                   const grpc_httpcli_response *response) {
+  freereq *pr = arg;
+  gpr_mu_lock(pr->mu);
+  pr->done = 1;
+  grpc_pollset_kick(pr->pollset, NULL);
+  gpr_mu_unlock(pr->mu);
+}
+
+void grpc_free_port_using_server(char *server, int port) {
+  grpc_httpcli_context context;
+  grpc_httpcli_request req;
+  freereq pr;
+  char *path;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_closure *shutdown_closure;
+
+  grpc_init();
+
+  memset(&pr, 0, sizeof(pr));
+  memset(&req, 0, sizeof(req));
+
+  pr.pollset = gpr_malloc(grpc_pollset_size());
+  grpc_pollset_init(pr.pollset, &pr.mu);
+  shutdown_closure =
+      grpc_closure_create(destroy_pollset_and_shutdown, pr.pollset);
+
+  req.host = server;
+  gpr_asprintf(&path, "/drop/%d", port);
+  req.http.path = path;
+
+  grpc_httpcli_context_init(&context);
+  grpc_httpcli_get(&exec_ctx, &context, pr.pollset, &req,
+                   GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), freed_port_from_server,
+                   &pr);
+  gpr_mu_lock(pr.mu);
+  while (!pr.done) {
+    grpc_pollset_worker *worker = NULL;
+    grpc_pollset_work(&exec_ctx, pr.pollset, &worker,
+                      gpr_now(GPR_CLOCK_MONOTONIC),
+                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1));
+  }
+  gpr_mu_unlock(pr.mu);
+
+  grpc_httpcli_context_destroy(&context);
+  grpc_exec_ctx_finish(&exec_ctx);
+  grpc_pollset_shutdown(&exec_ctx, pr.pollset, shutdown_closure);
+  grpc_exec_ctx_finish(&exec_ctx);
+  gpr_free(path);
+}
+
+typedef struct portreq {
+  gpr_mu *mu;
+  grpc_pollset *pollset;
+  int port;
+  int retries;
+  char *server;
+  grpc_httpcli_context *ctx;
+} portreq;
+
+static void got_port_from_server(grpc_exec_ctx *exec_ctx, void *arg,
+                                 const grpc_httpcli_response *response) {
+  size_t i;
+  int port = 0;
+  portreq *pr = arg;
+  int failed = 0;
+
+  if (!response) {
+    failed = 1;
+    gpr_log(GPR_DEBUG,
+            "failed port pick from server: retrying [response=NULL]");
+  } else if (response->status != 200) {
+    failed = 1;
+    gpr_log(GPR_DEBUG, "failed port pick from server: status=%d",
+            response->status);
+  }
+
+  if (failed) {
+    grpc_httpcli_request req;
+    memset(&req, 0, sizeof(req));
+    GPR_ASSERT(pr->retries < 10);
+    gpr_sleep_until(gpr_time_add(
+        gpr_now(GPR_CLOCK_REALTIME),
+        gpr_time_from_millis(
+            (int64_t)(1000.0 * (1 + pow(1.3, pr->retries) * rand() / RAND_MAX)),
+            GPR_TIMESPAN)));
+    pr->retries++;
+    req.host = pr->server;
+    req.http.path = "/get";
+    grpc_httpcli_get(exec_ctx, pr->ctx, pr->pollset, &req,
+                     GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), got_port_from_server,
+                     pr);
+    return;
+  }
+  GPR_ASSERT(response);
+  GPR_ASSERT(response->status == 200);
+  for (i = 0; i < response->body_length; i++) {
+    GPR_ASSERT(response->body[i] >= '0' && response->body[i] <= '9');
+    port = port * 10 + response->body[i] - '0';
+  }
+  GPR_ASSERT(port > 1024);
+  gpr_mu_lock(pr->mu);
+  pr->port = port;
+  grpc_pollset_kick(pr->pollset, NULL);
+  gpr_mu_unlock(pr->mu);
+}
+
+int grpc_pick_port_using_server(char *server) {
+  grpc_httpcli_context context;
+  grpc_httpcli_request req;
+  portreq pr;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_closure *shutdown_closure;
+
+  grpc_init();
+
+  memset(&pr, 0, sizeof(pr));
+  memset(&req, 0, sizeof(req));
+  pr.pollset = gpr_malloc(grpc_pollset_size());
+  grpc_pollset_init(pr.pollset, &pr.mu);
+  shutdown_closure =
+      grpc_closure_create(destroy_pollset_and_shutdown, pr.pollset);
+  pr.port = -1;
+  pr.server = server;
+  pr.ctx = &context;
+
+  req.host = server;
+  req.http.path = "/get";
+
+  grpc_httpcli_context_init(&context);
+  grpc_httpcli_get(&exec_ctx, &context, pr.pollset, &req,
+                   GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), got_port_from_server,
+                   &pr);
+  grpc_exec_ctx_finish(&exec_ctx);
+  gpr_mu_lock(pr.mu);
+  while (pr.port == -1) {
+    grpc_pollset_worker *worker = NULL;
+    grpc_pollset_work(&exec_ctx, pr.pollset, &worker,
+                      gpr_now(GPR_CLOCK_MONOTONIC),
+                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1));
+  }
+  gpr_mu_unlock(pr.mu);
+
+  grpc_httpcli_context_destroy(&context);
+  grpc_pollset_shutdown(&exec_ctx, pr.pollset, shutdown_closure);
+  grpc_exec_ctx_finish(&exec_ctx);
+
+  return pr.port;
+}
+
+#endif  // GRPC_TEST_PICK_PORT
diff --git a/test/core/util/port_server_client.h b/test/core/util/port_server_client.h
new file mode 100644
index 0000000..fc209cd
--- /dev/null
+++ b/test/core/util/port_server_client.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_TEST_CORE_UTIL_PORT_SERVER_CLIENT_H
+#define GRPC_TEST_CORE_UTIL_PORT_SERVER_CLIENT_H
+
+// C interface to port_server.py
+
+int grpc_pick_port_using_server(char *server);
+void grpc_free_port_using_server(char *server, int port);
+
+#endif  // GRPC_TEST_CORE_UTIL_PORT_SERVER_CLIENT_H
diff --git a/test/core/util/port_windows.c b/test/core/util/port_windows.c
index 3b20aeb..081782d 100644
--- a/test/core/util/port_windows.c
+++ b/test/core/util/port_windows.c
@@ -37,18 +37,19 @@
 
 #include "test/core/util/port.h"
 
+#include <errno.h>
 #include <process.h>
 #include <stdio.h>
-#include <errno.h>
 #include <string.h>
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
-#include "src/core/support/env.h"
-#include "src/core/httpcli/httpcli.h"
-#include "src/core/iomgr/sockaddr_utils.h"
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/support/env.h"
+#include "test/core/util/port_server_client.h"
 
 #define NUM_RANDOM_PORTS_TO_PICK 100
 
@@ -65,7 +66,18 @@
   return 0;
 }
 
-static void free_chosen_ports(void) { gpr_free(chosen_ports); }
+static void free_chosen_ports(void) {
+  char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
+  if (env != NULL) {
+    size_t i;
+    for (i = 0; i < num_chosen_ports; i++) {
+      grpc_free_port_using_server(env, chosen_ports[i]);
+    }
+    gpr_free(env);
+  }
+
+  gpr_free(chosen_ports);
+}
 
 static void chose_port(int port) {
   if (chosen_ports == NULL) {
@@ -128,80 +140,6 @@
   return 1;
 }
 
-typedef struct portreq {
-  grpc_pollset *pollset;
-  gpr_mu *mu;
-  int port;
-} portreq;
-
-static void got_port_from_server(grpc_exec_ctx *exec_ctx, void *arg,
-                                 const grpc_httpcli_response *response) {
-  size_t i;
-  int port = 0;
-  portreq *pr = arg;
-  GPR_ASSERT(response);
-  GPR_ASSERT(response->status == 200);
-  for (i = 0; i < response->body_length; i++) {
-    GPR_ASSERT(response->body[i] >= '0' && response->body[i] <= '9');
-    port = port * 10 + response->body[i] - '0';
-  }
-  GPR_ASSERT(port > 1024);
-  gpr_mu_lock(pr->mu);
-  pr->port = port;
-  grpc_pollset_kick(pr->pollset, NULL);
-  gpr_mu_unlock(pr->mu);
-}
-
-static void destroy_pollset_and_shutdown(grpc_exec_ctx *exec_ctx, void *p,
-                                         bool success) {
-  grpc_pollset_destroy(p);
-  grpc_shutdown();
-}
-
-static int pick_port_using_server(char *server) {
-  grpc_httpcli_context context;
-  grpc_httpcli_request req;
-  portreq pr;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_closure destroy_pollset_closure;
-
-  grpc_init();
-
-  memset(&pr, 0, sizeof(pr));
-  memset(&req, 0, sizeof(req));
-  pr.pollset = gpr_malloc(grpc_pollset_size());
-  grpc_pollset_init(pr.pollset, &pr.mu);
-  pr.port = -1;
-
-  req.host = server;
-  req.path = "/get";
-
-  grpc_httpcli_context_init(&context);
-  grpc_httpcli_get(&exec_ctx, &context, pr.pollset, &req,
-                   GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), got_port_from_server,
-                   &pr);
-  gpr_mu_lock(pr.mu);
-  while (pr.port == -1) {
-    grpc_pollset_worker *worker = NULL;
-    grpc_pollset_work(&exec_ctx, pr.pollset, &worker,
-                      gpr_now(GPR_CLOCK_MONOTONIC),
-                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1));
-    gpr_mu_unlock(pr.mu);
-    grpc_exec_ctx_flush(&exec_ctx);
-    gpr_mu_lock(pr.mu);
-  }
-  gpr_mu_unlock(pr.mu);
-
-  grpc_httpcli_context_destroy(&context);
-  grpc_closure_init(&destroy_pollset_closure, destroy_pollset_and_shutdown,
-                    &pr.pollset);
-  grpc_pollset_shutdown(&exec_ctx, pr.pollset, &destroy_pollset_closure);
-  gpr_free(pr.pollset);
-
-  grpc_exec_ctx_finish(&exec_ctx);
-  return pr.port;
-}
-
 int grpc_pick_unused_port(void) {
   /* We repeatedly pick a port and then see whether or not it is
      available for use both as a TCP socket and a UDP socket.  First, we
@@ -221,7 +159,7 @@
 
   char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
   if (env) {
-    int port = pick_port_using_server(env);
+    int port = grpc_pick_port_using_server(env);
     gpr_free(env);
     if (port != 0) {
       return port;
diff --git a/test/core/util/reconnect_server.c b/test/core/util/reconnect_server.c
index 57225aa..0e7a486 100644
--- a/test/core/util/reconnect_server.c
+++ b/test/core/util/reconnect_server.c
@@ -40,9 +40,9 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 #include <string.h>
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/iomgr/sockaddr.h"
-#include "src/core/iomgr/tcp_server.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/tcp_server.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_tcp_server.h"
 
diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c
index 14bfc95..7ffaa6f 100644
--- a/test/core/util/test_config.c
+++ b/test/core/util/test_config.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,11 +33,13 @@
 
 #include "test/core/util/test_config.h"
 
-#include <grpc/support/port_platform.h>
 #include <grpc/support/log.h>
-#include "src/core/support/string.h"
-#include <stdlib.h>
+#include <grpc/support/port_platform.h>
 #include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "src/core/lib/support/string.h"
 
 double g_fixture_slowdown_factor = 1.0;
 
@@ -52,14 +54,127 @@
 #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;
+#include <windows.h>
+
+#include <tchar.h>
+
+// disable warning 4091 - dbghelp.h is broken for msvc2015
+#pragma warning(disable : 4091)
+#define DBGHELP_TRANSLATE_TCHAR
+#include <dbghelp.h>
+
+#ifdef _MSC_VER
+#pragma comment(lib, "dbghelp.lib")
+#endif
+
+static void print_current_stack() {
+  typedef USHORT(WINAPI * CaptureStackBackTraceType)(
+      __in ULONG, __in ULONG, __out PVOID *, __out_opt PULONG);
+  CaptureStackBackTraceType func = (CaptureStackBackTraceType)(GetProcAddress(
+      LoadLibrary(_T("kernel32.dll")), "RtlCaptureStackBackTrace"));
+
+  if (func == NULL) return;  // WOE 29.SEP.2010
+
+// Quote from Microsoft Documentation:
+// ## Windows Server 2003 and Windows XP:
+// ## The sum of the FramesToSkip and FramesToCapture parameters must be less
+// than 63.
+#define MAX_CALLERS 62
+
+  void *callers_stack[MAX_CALLERS];
+  unsigned short frames;
+  SYMBOL_INFOW *symbol;
+  HANDLE process;
+  process = GetCurrentProcess();
+  SymInitialize(process, NULL, TRUE);
+  frames = (func)(0, MAX_CALLERS, callers_stack, NULL);
+  symbol =
+      (SYMBOL_INFOW *)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(wchar_t), 1);
+  symbol->MaxNameLen = 255;
+  symbol->SizeOfStruct = sizeof(SYMBOL_INFOW);
+
+  const unsigned short MAX_CALLERS_SHOWN = 32;
+  frames = frames < MAX_CALLERS_SHOWN ? frames : MAX_CALLERS_SHOWN;
+  for (unsigned int i = 0; i < frames; i++) {
+    SymFromAddrW(process, (DWORD64)(callers_stack[i]), 0, symbol);
+    fwprintf(stderr, L"*** %d: %016I64X %ls - %016I64X\n", i,
+             (DWORD64)callers_stack[i], symbol->Name, (DWORD64)symbol->Address);
+    fflush(stderr);
+  }
+
+  free(symbol);
+}
+
+static void print_stack_from_context(CONTEXT c) {
+  STACKFRAME s;  // in/out stackframe
+  memset(&s, 0, sizeof(s));
+  DWORD imageType;
+#ifdef _M_IX86
+  // normally, call ImageNtHeader() and use machine info from PE header
+  imageType = IMAGE_FILE_MACHINE_I386;
+  s.AddrPC.Offset = c.Eip;
+  s.AddrPC.Mode = AddrModeFlat;
+  s.AddrFrame.Offset = c.Ebp;
+  s.AddrFrame.Mode = AddrModeFlat;
+  s.AddrStack.Offset = c.Esp;
+  s.AddrStack.Mode = AddrModeFlat;
+#elif _M_X64
+  imageType = IMAGE_FILE_MACHINE_AMD64;
+  s.AddrPC.Offset = c.Rip;
+  s.AddrPC.Mode = AddrModeFlat;
+  s.AddrFrame.Offset = c.Rsp;
+  s.AddrFrame.Mode = AddrModeFlat;
+  s.AddrStack.Offset = c.Rsp;
+  s.AddrStack.Mode = AddrModeFlat;
+#elif _M_IA64
+  imageType = IMAGE_FILE_MACHINE_IA64;
+  s.AddrPC.Offset = c.StIIP;
+  s.AddrPC.Mode = AddrModeFlat;
+  s.AddrFrame.Offset = c.IntSp;
+  s.AddrFrame.Mode = AddrModeFlat;
+  s.AddrBStore.Offset = c.RsBSP;
+  s.AddrBStore.Mode = AddrModeFlat;
+  s.AddrStack.Offset = c.IntSp;
+  s.AddrStack.Mode = AddrModeFlat;
+#else
+#error "Platform not supported!"
+#endif
+
+  HANDLE process = GetCurrentProcess();
+  HANDLE thread = GetCurrentThread();
+
+  SYMBOL_INFOW *symbol =
+      (SYMBOL_INFOW *)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(wchar_t), 1);
+  symbol->MaxNameLen = 255;
+  symbol->SizeOfStruct = sizeof(SYMBOL_INFOW);
+
+  while (StackWalk(imageType, process, thread, &s, &c, 0,
+                   SymFunctionTableAccess, SymGetModuleBase, 0)) {
+    BOOL has_symbol =
+        SymFromAddrW(process, (DWORD64)(s.AddrPC.Offset), 0, symbol);
+    fwprintf(
+        stderr, L"*** %016I64X %ls - %016I64X\n", (DWORD64)(s.AddrPC.Offset),
+        has_symbol ? symbol->Name : L"<<no symbol>>", (DWORD64)symbol->Address);
+    fflush(stderr);
+  }
+
+  free(symbol);
+}
+
+static LONG crash_handler(struct _EXCEPTION_POINTERS *ex_info) {
+  fprintf(stderr, "Exception handler called, dumping information\n");
+  bool try_to_print_stack = true;
+  PEXCEPTION_RECORD exrec = ex_info->ExceptionRecord;
+  while (exrec) {
+    DWORD code = exrec->ExceptionCode;
+    DWORD flgs = exrec->ExceptionFlags;
+    PVOID addr = exrec->ExceptionAddress;
+    if (code == EXCEPTION_STACK_OVERFLOW) try_to_print_stack = false;
+    fprintf(stderr, "code: %x - flags: %d - address: %p\n", code, flgs, addr);
+    exrec = exrec->ExceptionRecord;
+  }
+  if (try_to_print_stack) {
+    print_stack_from_context(*ex_info->ContextRecord);
   }
   if (IsDebuggerPresent()) {
     __debugbreak();
@@ -69,8 +184,9 @@
   return EXCEPTION_EXECUTE_HANDLER;
 }
 
-void abort_handler(int sig) {
-  gpr_log(GPR_DEBUG, "Abort handler called.");
+static void abort_handler(int sig) {
+  fprintf(stderr, "Abort handler called.\n");
+  print_current_stack(NULL);
   if (IsDebuggerPresent()) {
     __debugbreak();
   } else {
@@ -79,17 +195,20 @@
 }
 
 static void install_crash_handler() {
+  if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) {
+    fprintf(stderr, "SymInitialize failed: %d\n", GetLastError());
+  }
   SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)crash_handler);
   _set_abort_behavior(0, _WRITE_ABORT_MSG);
   _set_abort_behavior(0, _CALL_REPORTFAULT);
   signal(SIGABRT, abort_handler);
 }
 #elif GPR_POSIX_CRASH_HANDLER
+#include <errno.h>
 #include <execinfo.h>
+#include <grpc/support/useful.h>
 #include <stdio.h>
 #include <string.h>
-#include <grpc/support/useful.h>
-#include <errno.h>
 
 static char g_alt_stack[MINSIGSTKSZ];
 
diff --git a/test/core/util/test_tcp_server.c b/test/core/util/test_tcp_server.c
index ab37944..7703ec0 100644
--- a/test/core/util/test_tcp_server.c
+++ b/test/core/util/test_tcp_server.c
@@ -40,9 +40,9 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 #include <string.h>
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/iomgr/sockaddr.h"
-#include "src/core/iomgr/tcp_server.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/tcp_server.h"
 #include "test/core/util/port.h"
 
 static void on_server_destroyed(grpc_exec_ctx *exec_ctx, void *data,
diff --git a/test/core/util/test_tcp_server.h b/test/core/util/test_tcp_server.h
index 15fcb4f..7d1025f 100644
--- a/test/core/util/test_tcp_server.h
+++ b/test/core/util/test_tcp_server.h
@@ -35,7 +35,7 @@
 #define GRPC_TEST_CORE_UTIL_TEST_TCP_SERVER_H
 
 #include <grpc/support/sync.h>
-#include "src/core/iomgr/tcp_server.h"
+#include "src/core/lib/iomgr/tcp_server.h"
 
 typedef struct test_tcp_server {
   grpc_tcp_server *tcp_server;
diff --git a/test/cpp/codegen/codegen_test.cc b/test/cpp/codegen/codegen_test.cc
new file mode 100644
index 0000000..735755a
--- /dev/null
+++ b/test/cpp/codegen/codegen_test.cc
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <gtest/gtest.h>
+
+namespace grpc {
+namespace {
+
+class CodegenTest : public ::testing::Test {};
+
+TEST_F(CodegenTest, Build) {}
+
+}  // namespace
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/common/auth_property_iterator_test.cc b/test/cpp/common/auth_property_iterator_test.cc
index a629ff5..4b5cf02 100644
--- a/test/cpp/common/auth_property_iterator_test.cc
+++ b/test/cpp/common/auth_property_iterator_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,14 +31,14 @@
  *
  */
 
-#include <grpc/grpc_security.h>
 #include <grpc++/security/auth_context.h>
+#include <grpc/grpc_security.h>
 #include <gtest/gtest.h>
 #include "src/cpp/common/secure_auth_context.h"
 #include "test/cpp/util/string_ref_helper.h"
 
 extern "C" {
-#include "src/core/security/security_context.h"
+#include "src/core/lib/security/security_context.h"
 }
 
 using ::grpc::testing::ToString;
diff --git a/test/cpp/common/secure_auth_context_test.cc b/test/cpp/common/secure_auth_context_test.cc
index 11de646..c421910 100644
--- a/test/cpp/common/secure_auth_context_test.cc
+++ b/test/cpp/common/secure_auth_context_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,14 +31,14 @@
  *
  */
 
-#include <grpc/grpc_security.h>
-#include <grpc++/security/auth_context.h>
-#include <gtest/gtest.h>
 #include "src/cpp/common/secure_auth_context.h"
+#include <grpc++/security/auth_context.h>
+#include <grpc/grpc_security.h>
+#include <gtest/gtest.h>
 #include "test/cpp/util/string_ref_helper.h"
 
 extern "C" {
-#include "src/core/security/security_context.h"
+#include "src/core/lib/security/security_context.h"
 }
 
 using grpc::testing::ToString;
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index 9ca3bf9..d8aa4c0 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -53,7 +53,7 @@
 #include "test/cpp/util/string_ref_helper.h"
 
 #ifdef GPR_POSIX_SOCKET
-#include "src/core/iomgr/pollset_posix.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
 #endif
 
 using grpc::testing::EchoRequest;
@@ -68,6 +68,7 @@
 namespace {
 
 void* tag(int i) { return (void*)(intptr_t)i; }
+int detag(void* p) { return static_cast<int>(reinterpret_cast<intptr_t>(p)); }
 
 #ifdef GPR_POSIX_SOCKET
 static int maybe_assert_non_blocking_poll(struct pollfd* pfds, nfds_t nfds,
@@ -106,37 +107,50 @@
 class Verifier {
  public:
   explicit Verifier(bool spin) : spin_(spin) {}
+  // Expect sets the expected ok value for a specific tag
   Verifier& Expect(int i, bool expect_ok) {
     expectations_[tag(i)] = expect_ok;
     return *this;
   }
 
+  // Next waits for 1 async tag to complete, checks its
+  // expectations, and returns the tag
+  int Next(CompletionQueue* cq, bool ignore_ok) {
+    bool ok;
+    void* got_tag;
+    if (spin_) {
+      for (;;) {
+        auto r = cq->AsyncNext(&got_tag, &ok, gpr_time_0(GPR_CLOCK_REALTIME));
+        if (r == CompletionQueue::TIMEOUT) continue;
+        if (r == CompletionQueue::GOT_EVENT) break;
+        gpr_log(GPR_ERROR, "unexpected result from AsyncNext");
+        abort();
+      }
+    } else {
+      EXPECT_TRUE(cq->Next(&got_tag, &ok));
+    }
+    auto it = expectations_.find(got_tag);
+    EXPECT_TRUE(it != expectations_.end());
+    if (!ignore_ok) {
+      EXPECT_EQ(it->second, ok);
+    }
+    expectations_.erase(it);
+    return detag(got_tag);
+  }
+
+  // Verify keeps calling Next until all currently set
+  // expected tags are complete
   void Verify(CompletionQueue* cq) { Verify(cq, false); }
 
+  // This version of Verify allows optionally ignoring the
+  // outcome of the expectation
   void Verify(CompletionQueue* cq, bool ignore_ok) {
     GPR_ASSERT(!expectations_.empty());
     while (!expectations_.empty()) {
-      bool ok;
-      void* got_tag;
-      if (spin_) {
-        for (;;) {
-          auto r = cq->AsyncNext(&got_tag, &ok, gpr_time_0(GPR_CLOCK_REALTIME));
-          if (r == CompletionQueue::TIMEOUT) continue;
-          if (r == CompletionQueue::GOT_EVENT) break;
-          gpr_log(GPR_ERROR, "unexpected result from AsyncNext");
-          abort();
-        }
-      } else {
-        EXPECT_TRUE(cq->Next(&got_tag, &ok));
-      }
-      auto it = expectations_.find(got_tag);
-      EXPECT_TRUE(it != expectations_.end());
-      if (!ignore_ok) {
-        EXPECT_EQ(it->second, ok);
-      }
-      expectations_.erase(it);
+      Next(cq, ignore_ok);
     }
   }
+  // This version of Verify stops after a certain deadline
   void Verify(CompletionQueue* cq,
               std::chrono::system_clock::time_point deadline) {
     if (expectations_.empty()) {
@@ -793,7 +807,8 @@
 }
 
 // This class is for testing scenarios where RPCs are cancelled on the server
-// by calling ServerContext::TryCancel()
+// by calling ServerContext::TryCancel(). Server uses AsyncNotifyWhenDone
+// API to check for cancellation
 class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
  protected:
   typedef enum {
@@ -803,13 +818,6 @@
     CANCEL_AFTER_PROCESSING
   } ServerTryCancelRequestPhase;
 
-  void ServerTryCancel(ServerContext* context) {
-    EXPECT_FALSE(context->IsCancelled());
-    context->TryCancel();
-    gpr_log(GPR_INFO, "Server called TryCancel()");
-    EXPECT_TRUE(context->IsCancelled());
-  }
-
   // Helper for testing client-streaming RPCs which are cancelled on the server.
   // Depending on the value of server_try_cancel parameter, this will test one
   // of the following three scenarios:
@@ -843,6 +851,7 @@
 
     // On the server, request to be notified of 'RequestStream' calls
     // and receive the 'RequestStream' call just made by the client
+    srv_ctx.AsyncNotifyWhenDone(tag(11));
     service_.RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
                                   tag(2));
     Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
@@ -858,9 +867,12 @@
 
     bool expected_server_cq_result = true;
     bool ignore_cq_result = false;
+    bool want_done_tag = false;
 
     if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
-      ServerTryCancel(&srv_ctx);
+      srv_ctx.TryCancel();
+      Verifier(GetParam()).Expect(11, true).Verify(cq_.get());
+      EXPECT_TRUE(srv_ctx.IsCancelled());
 
       // Since cancellation is done before server reads any results, we know
       // for sure that all cq results will return false from this point forward
@@ -868,22 +880,39 @@
     }
 
     std::thread* server_try_cancel_thd = NULL;
+
+    auto verif = Verifier(GetParam());
+
     if (server_try_cancel == CANCEL_DURING_PROCESSING) {
-      server_try_cancel_thd = new std::thread(
-          &AsyncEnd2endServerTryCancelTest::ServerTryCancel, this, &srv_ctx);
+      server_try_cancel_thd =
+          new std::thread(&ServerContext::TryCancel, &srv_ctx);
       // Server will cancel the RPC in a parallel thread while reading the
       // requests from the client. Since the cancellation can happen at anytime,
       // some of the cq results (i.e those until cancellation) might be true but
       // its non deterministic. So better to ignore the cq results
       ignore_cq_result = true;
+      // Expect that we might possibly see the done tag that
+      // indicates cancellation completion in this case
+      want_done_tag = true;
+      verif.Expect(11, true);
     }
 
     // Server reads 3 messages (tags 6, 7 and 8)
+    // But if want_done_tag is true, we might also see tag 11
     for (int tag_idx = 6; tag_idx <= 8; tag_idx++) {
       srv_stream.Read(&recv_request, tag(tag_idx));
-      Verifier(GetParam())
-          .Expect(tag_idx, expected_server_cq_result)
-          .Verify(cq_.get(), ignore_cq_result);
+      // Note that we'll add something to the verifier and verify that
+      // something was seen, but it might be tag 11 and not what we
+      // just added
+      int got_tag = verif.Expect(tag_idx, expected_server_cq_result)
+                        .Next(cq_.get(), ignore_cq_result);
+      GPR_ASSERT((got_tag == tag_idx) || (got_tag == 11 && want_done_tag));
+      if (got_tag == 11) {
+        EXPECT_TRUE(srv_ctx.IsCancelled());
+        want_done_tag = false;
+        // Now get the other entry that we were waiting on
+        EXPECT_EQ(verif.Next(cq_.get(), ignore_cq_result), tag_idx);
+      }
     }
 
     if (server_try_cancel_thd != NULL) {
@@ -892,7 +921,15 @@
     }
 
     if (server_try_cancel == CANCEL_AFTER_PROCESSING) {
-      ServerTryCancel(&srv_ctx);
+      srv_ctx.TryCancel();
+      want_done_tag = true;
+      verif.Expect(11, true);
+    }
+
+    if (want_done_tag) {
+      verif.Verify(cq_.get());
+      EXPECT_TRUE(srv_ctx.IsCancelled());
+      want_done_tag = false;
     }
 
     // The RPC has been cancelled at this point for sure (i.e irrespective of
@@ -945,6 +982,7 @@
     Verifier(GetParam()).Expect(1, true).Verify(cq_.get());
     // On the server, request to be notified of 'ResponseStream' calls and
     // receive the call just made by the client
+    srv_ctx.AsyncNotifyWhenDone(tag(11));
     service_.RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
                                    cq_.get(), cq_.get(), tag(2));
     Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
@@ -952,9 +990,12 @@
 
     bool expected_cq_result = true;
     bool ignore_cq_result = false;
+    bool want_done_tag = false;
 
     if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
-      ServerTryCancel(&srv_ctx);
+      srv_ctx.TryCancel();
+      Verifier(GetParam()).Expect(11, true).Verify(cq_.get());
+      EXPECT_TRUE(srv_ctx.IsCancelled());
 
       // We know for sure that all cq results will be false from this point
       // since the server cancelled the RPC
@@ -962,24 +1003,41 @@
     }
 
     std::thread* server_try_cancel_thd = NULL;
+
+    auto verif = Verifier(GetParam());
+
     if (server_try_cancel == CANCEL_DURING_PROCESSING) {
-      server_try_cancel_thd = new std::thread(
-          &AsyncEnd2endServerTryCancelTest::ServerTryCancel, this, &srv_ctx);
+      server_try_cancel_thd =
+          new std::thread(&ServerContext::TryCancel, &srv_ctx);
 
       // Server will cancel the RPC in a parallel thread while writing responses
       // to the client. Since the cancellation can happen at anytime, some of
       // the cq results (i.e those until cancellation) might be true but it is
       // non deterministic. So better to ignore the cq results
       ignore_cq_result = true;
+      // Expect that we might possibly see the done tag that
+      // indicates cancellation completion in this case
+      want_done_tag = true;
+      verif.Expect(11, true);
     }
 
     // Server sends three messages (tags 3, 4 and 5)
+    // But if want_done tag is true, we might also see tag 11
     for (int tag_idx = 3; tag_idx <= 5; tag_idx++) {
       send_response.set_message("Pong " + std::to_string(tag_idx));
       srv_stream.Write(send_response, tag(tag_idx));
-      Verifier(GetParam())
-          .Expect(tag_idx, expected_cq_result)
-          .Verify(cq_.get(), ignore_cq_result);
+      // Note that we'll add something to the verifier and verify that
+      // something was seen, but it might be tag 11 and not what we
+      // just added
+      int got_tag = verif.Expect(tag_idx, expected_cq_result)
+                        .Next(cq_.get(), ignore_cq_result);
+      GPR_ASSERT((got_tag == tag_idx) || (got_tag == 11 && want_done_tag));
+      if (got_tag == 11) {
+        EXPECT_TRUE(srv_ctx.IsCancelled());
+        want_done_tag = false;
+        // Now get the other entry that we were waiting on
+        EXPECT_EQ(verif.Next(cq_.get(), ignore_cq_result), tag_idx);
+      }
     }
 
     if (server_try_cancel_thd != NULL) {
@@ -988,13 +1046,21 @@
     }
 
     if (server_try_cancel == CANCEL_AFTER_PROCESSING) {
-      ServerTryCancel(&srv_ctx);
+      srv_ctx.TryCancel();
+      want_done_tag = true;
+      verif.Expect(11, true);
 
       // Client reads may fail bacause it is notified that the stream is
       // cancelled.
       ignore_cq_result = true;
     }
 
+    if (want_done_tag) {
+      verif.Verify(cq_.get());
+      EXPECT_TRUE(srv_ctx.IsCancelled());
+      want_done_tag = false;
+    }
+
     // Client attemts to read the three messages from the server
     for (int tag_idx = 6; tag_idx <= 8; tag_idx++) {
       cli_stream->Read(&recv_response, tag(tag_idx));
@@ -1052,6 +1118,7 @@
 
     // On the server, request to be notified of the 'BidiStream' call and
     // receive the call just made by the client
+    srv_ctx.AsyncNotifyWhenDone(tag(11));
     service_.RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
                                tag(2));
     Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
@@ -1063,9 +1130,12 @@
 
     bool expected_cq_result = true;
     bool ignore_cq_result = false;
+    bool want_done_tag = false;
 
     if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
-      ServerTryCancel(&srv_ctx);
+      srv_ctx.TryCancel();
+      Verifier(GetParam()).Expect(11, true).Verify(cq_.get());
+      EXPECT_TRUE(srv_ctx.IsCancelled());
 
       // We know for sure that all cq results will be false from this point
       // since the server cancelled the RPC
@@ -1073,42 +1143,84 @@
     }
 
     std::thread* server_try_cancel_thd = NULL;
+
+    auto verif = Verifier(GetParam());
+
     if (server_try_cancel == CANCEL_DURING_PROCESSING) {
-      server_try_cancel_thd = new std::thread(
-          &AsyncEnd2endServerTryCancelTest::ServerTryCancel, this, &srv_ctx);
+      server_try_cancel_thd =
+          new std::thread(&ServerContext::TryCancel, &srv_ctx);
 
       // Since server is going to cancel the RPC in a parallel thread, some of
       // the cq results (i.e those until the cancellation) might be true. Since
       // that number is non-deterministic, it is better to ignore the cq results
       ignore_cq_result = true;
+      // Expect that we might possibly see the done tag that
+      // indicates cancellation completion in this case
+      want_done_tag = true;
+      verif.Expect(11, true);
     }
 
+    int got_tag;
     srv_stream.Read(&recv_request, tag(4));
-    Verifier(GetParam())
-        .Expect(4, expected_cq_result)
-        .Verify(cq_.get(), ignore_cq_result);
+    verif.Expect(4, expected_cq_result);
+    got_tag = verif.Next(cq_.get(), ignore_cq_result);
+    GPR_ASSERT((got_tag == 4) || (got_tag == 11 && want_done_tag));
+    if (got_tag == 11) {
+      EXPECT_TRUE(srv_ctx.IsCancelled());
+      want_done_tag = false;
+      // Now get the other entry that we were waiting on
+      EXPECT_EQ(verif.Next(cq_.get(), ignore_cq_result), 4);
+    }
 
     send_response.set_message("Pong");
     srv_stream.Write(send_response, tag(5));
-    Verifier(GetParam())
-        .Expect(5, expected_cq_result)
-        .Verify(cq_.get(), ignore_cq_result);
+    verif.Expect(5, expected_cq_result);
+    got_tag = verif.Next(cq_.get(), ignore_cq_result);
+    GPR_ASSERT((got_tag == 5) || (got_tag == 11 && want_done_tag));
+    if (got_tag == 11) {
+      EXPECT_TRUE(srv_ctx.IsCancelled());
+      want_done_tag = false;
+      // Now get the other entry that we were waiting on
+      EXPECT_EQ(verif.Next(cq_.get(), ignore_cq_result), 5);
+    }
 
     cli_stream->Read(&recv_response, tag(6));
-    Verifier(GetParam())
-        .Expect(6, expected_cq_result)
-        .Verify(cq_.get(), ignore_cq_result);
+    verif.Expect(6, expected_cq_result);
+    got_tag = verif.Next(cq_.get(), ignore_cq_result);
+    GPR_ASSERT((got_tag == 6) || (got_tag == 11 && want_done_tag));
+    if (got_tag == 11) {
+      EXPECT_TRUE(srv_ctx.IsCancelled());
+      want_done_tag = false;
+      // Now get the other entry that we were waiting on
+      EXPECT_EQ(verif.Next(cq_.get(), ignore_cq_result), 6);
+    }
 
     // This is expected to succeed in all cases
     cli_stream->WritesDone(tag(7));
-    Verifier(GetParam()).Expect(7, true).Verify(cq_.get());
+    verif.Expect(7, true);
+    got_tag = verif.Next(cq_.get(), ignore_cq_result);
+    GPR_ASSERT((got_tag == 7) || (got_tag == 11 && want_done_tag));
+    if (got_tag == 11) {
+      EXPECT_TRUE(srv_ctx.IsCancelled());
+      want_done_tag = false;
+      // Now get the other entry that we were waiting on
+      EXPECT_EQ(verif.Next(cq_.get(), ignore_cq_result), 7);
+    }
 
     // This is expected to fail in all cases i.e for all values of
     // server_try_cancel. This is because at this point, either there are no
     // more msgs from the client (because client called WritesDone) or the RPC
     // is cancelled on the server
     srv_stream.Read(&recv_request, tag(8));
-    Verifier(GetParam()).Expect(8, false).Verify(cq_.get());
+    verif.Expect(8, false);
+    got_tag = verif.Next(cq_.get(), ignore_cq_result);
+    GPR_ASSERT((got_tag == 8) || (got_tag == 11 && want_done_tag));
+    if (got_tag == 11) {
+      EXPECT_TRUE(srv_ctx.IsCancelled());
+      want_done_tag = false;
+      // Now get the other entry that we were waiting on
+      EXPECT_EQ(verif.Next(cq_.get(), ignore_cq_result), 8);
+    }
 
     if (server_try_cancel_thd != NULL) {
       server_try_cancel_thd->join();
@@ -1116,7 +1228,15 @@
     }
 
     if (server_try_cancel == CANCEL_AFTER_PROCESSING) {
-      ServerTryCancel(&srv_ctx);
+      srv_ctx.TryCancel();
+      want_done_tag = true;
+      verif.Expect(11, true);
+    }
+
+    if (want_done_tag) {
+      verif.Verify(cq_.get());
+      EXPECT_TRUE(srv_ctx.IsCancelled());
+      want_done_tag = false;
     }
 
     // The RPC has been cancelled at this point for sure (i.e irrespective of
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index dc2c4f6..ff388c0 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -48,7 +48,7 @@
 #include <grpc/support/time.h>
 #include <gtest/gtest.h>
 
-#include "src/core/security/credentials.h"
+#include "src/core/lib/security/credentials.h"
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
@@ -59,6 +59,7 @@
 
 using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
+using grpc::testing::kTlsCredentialsType;
 using std::chrono::system_clock;
 
 namespace grpc {
@@ -1194,6 +1195,8 @@
   request.mutable_param()->set_echo_metadata(true);
   request.mutable_param()->set_expected_client_identity(
       TestAuthMetadataProcessor::kGoodGuy);
+  request.mutable_param()->set_expected_transport_security_type(
+      GetParam().credentials_type);
 
   Status s = stub_->Echo(&context, request, &response);
   EXPECT_EQ(request.message(), response.message());
@@ -1301,6 +1304,8 @@
   request.mutable_param()->set_echo_metadata(true);
   request.mutable_param()->set_expected_client_identity(
       TestAuthMetadataProcessor::kGoodGuy);
+  request.mutable_param()->set_expected_transport_security_type(
+      GetParam().credentials_type);
 
   Status s = stub_->Echo(&context, request, &response);
   EXPECT_EQ(request.message(), response.message());
@@ -1349,25 +1354,30 @@
   EchoRequest request;
   EchoResponse response;
   request.set_message("Hello");
-  request.mutable_param()->set_check_auth_context(true);
-
+  request.mutable_param()->set_check_auth_context(GetParam().credentials_type ==
+                                                  kTlsCredentialsType);
+  request.mutable_param()->set_expected_transport_security_type(
+      GetParam().credentials_type);
   ClientContext context;
   Status s = stub_->Echo(&context, request, &response);
   EXPECT_EQ(response.message(), request.message());
   EXPECT_TRUE(s.ok());
 
   std::shared_ptr<const AuthContext> auth_ctx = context.auth_context();
-  std::vector<grpc::string_ref> ssl =
+  std::vector<grpc::string_ref> tst =
       auth_ctx->FindPropertyValues("transport_security_type");
-  EXPECT_EQ(1u, ssl.size());
-  EXPECT_EQ("ssl", ToString(ssl[0]));
-  EXPECT_EQ("x509_subject_alternative_name",
-            auth_ctx->GetPeerIdentityPropertyName());
-  EXPECT_EQ(3u, auth_ctx->GetPeerIdentity().size());
-  EXPECT_EQ("*.test.google.fr", ToString(auth_ctx->GetPeerIdentity()[0]));
-  EXPECT_EQ("waterzooi.test.google.be",
-            ToString(auth_ctx->GetPeerIdentity()[1]));
-  EXPECT_EQ("*.test.youtube.com", ToString(auth_ctx->GetPeerIdentity()[2]));
+  EXPECT_EQ(1u, tst.size());
+  EXPECT_EQ(GetParam().credentials_type, ToString(tst[0]));
+  if (GetParam().credentials_type == kTlsCredentialsType) {
+    EXPECT_EQ("x509_subject_alternative_name",
+              auth_ctx->GetPeerIdentityPropertyName());
+    EXPECT_EQ(4u, auth_ctx->GetPeerIdentity().size());
+    EXPECT_EQ("*.test.google.fr", ToString(auth_ctx->GetPeerIdentity()[0]));
+    EXPECT_EQ("waterzooi.test.google.be",
+              ToString(auth_ctx->GetPeerIdentity()[1]));
+    EXPECT_EQ("*.test.youtube.com", ToString(auth_ctx->GetPeerIdentity()[2]));
+    EXPECT_EQ("192.168.1.3", ToString(auth_ctx->GetPeerIdentity()[3]));
+  }
 }
 
 std::vector<TestScenario> CreateTestScenarios(bool use_proxy,
diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc
index 4e6d50e..8dad1c2 100644
--- a/test/cpp/end2end/generic_end2end_test.cc
+++ b/test/cpp/end2end/generic_end2end_test.cc
@@ -135,6 +135,8 @@
       std::unique_ptr<ByteBuffer> send_buffer =
           SerializeToByteBuffer(&send_request);
       call->Write(*send_buffer, tag(2));
+      // Send ByteBuffer can be destroyed after calling Write.
+      send_buffer.reset();
       client_ok(2);
       call->WritesDone(tag(3));
       client_ok(3);
@@ -154,6 +156,7 @@
       send_response.set_message(recv_request.message());
       send_buffer = SerializeToByteBuffer(&send_response);
       stream.Write(*send_buffer, tag(6));
+      send_buffer.reset();
       server_ok(6);
 
       stream.Finish(Status::OK, tag(7));
@@ -223,6 +226,7 @@
   std::unique_ptr<ByteBuffer> send_buffer =
       SerializeToByteBuffer(&send_request);
   cli_stream->Write(*send_buffer, tag(3));
+  send_buffer.reset();
   client_ok(3);
 
   ByteBuffer recv_buffer;
@@ -234,6 +238,7 @@
   send_response.set_message(recv_request.message());
   send_buffer = SerializeToByteBuffer(&send_response);
   srv_stream.Write(*send_buffer, tag(5));
+  send_buffer.reset();
   server_ok(5);
 
   cli_stream->Read(&recv_buffer, tag(6));
diff --git a/test/cpp/end2end/hybrid_end2end_test.cc b/test/cpp/end2end/hybrid_end2end_test.cc
index c72e206..02043a8 100644
--- a/test/cpp/end2end/hybrid_end2end_test.cc
+++ b/test/cpp/end2end/hybrid_end2end_test.cc
@@ -356,7 +356,8 @@
 
 TEST_F(HybridEnd2endTest, AsyncEchoRequestStream) {
   EchoTestService::WithAsyncMethod_RequestStream<
-      EchoTestService::WithAsyncMethod_Echo<TestServiceImpl> > service;
+      EchoTestService::WithAsyncMethod_Echo<TestServiceImpl> >
+      service;
   SetUpServer(&service, nullptr, nullptr);
   ResetStub();
   std::thread echo_handler_thread(
@@ -436,7 +437,8 @@
 
 TEST_F(HybridEnd2endTest, GenericEchoAsyncRequestStream) {
   EchoTestService::WithAsyncMethod_RequestStream<
-      EchoTestService::WithGenericMethod_Echo<TestServiceImpl> > service;
+      EchoTestService::WithGenericMethod_Echo<TestServiceImpl> >
+      service;
   AsyncGenericService generic_service;
   SetUpServer(&service, nullptr, &generic_service);
   ResetStub();
@@ -453,7 +455,8 @@
 // Add a second service with one sync method.
 TEST_F(HybridEnd2endTest, GenericEchoAsyncRequestStream_SyncDupService) {
   EchoTestService::WithAsyncMethod_RequestStream<
-      EchoTestService::WithGenericMethod_Echo<TestServiceImpl> > service;
+      EchoTestService::WithGenericMethod_Echo<TestServiceImpl> >
+      service;
   AsyncGenericService generic_service;
   TestServiceImplDupPkg dup_service;
   SetUpServer(&service, &dup_service, &generic_service);
@@ -472,7 +475,8 @@
 // Add a second service with one async method.
 TEST_F(HybridEnd2endTest, GenericEchoAsyncRequestStream_AsyncDupService) {
   EchoTestService::WithAsyncMethod_RequestStream<
-      EchoTestService::WithGenericMethod_Echo<TestServiceImpl> > service;
+      EchoTestService::WithGenericMethod_Echo<TestServiceImpl> >
+      service;
   AsyncGenericService generic_service;
   duplicate::EchoTestService::AsyncService dup_service;
   SetUpServer(&service, &dup_service, &generic_service);
diff --git a/test/cpp/end2end/shutdown_test.cc b/test/cpp/end2end/shutdown_test.cc
index dbbda3a..62bb6b1 100644
--- a/test/cpp/end2end/shutdown_test.cc
+++ b/test/cpp/end2end/shutdown_test.cc
@@ -43,7 +43,7 @@
 #include <grpc/support/sync.h>
 #include <gtest/gtest.h>
 
-#include "src/core/support/env.h"
+#include "src/core/lib/support/env.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
diff --git a/test/cpp/end2end/test_service_impl.cc b/test/cpp/end2end/test_service_impl.cc
index 7c3e514..2f5dd6d 100644
--- a/test/cpp/end2end/test_service_impl.cc
+++ b/test/cpp/end2end/test_service_impl.cc
@@ -62,14 +62,16 @@
   }
 }
 
-void CheckServerAuthContext(const ServerContext* context,
-                            const grpc::string& expected_client_identity) {
+void CheckServerAuthContext(
+    const ServerContext* context,
+    const grpc::string& expected_transport_security_type,
+    const grpc::string& expected_client_identity) {
   std::shared_ptr<const AuthContext> auth_ctx = context->auth_context();
-  std::vector<grpc::string_ref> ssl =
+  std::vector<grpc::string_ref> tst =
       auth_ctx->FindPropertyValues("transport_security_type");
-  EXPECT_EQ(1u, ssl.size());
-  EXPECT_EQ("ssl", ToString(ssl[0]));
-  if (expected_client_identity.length() == 0) {
+  EXPECT_EQ(1u, tst.size());
+  EXPECT_EQ(expected_transport_security_type, ToString(tst[0]));
+  if (expected_client_identity.empty()) {
     EXPECT_TRUE(auth_ctx->GetPeerIdentityPropertyName().empty());
     EXPECT_TRUE(auth_ctx->GetPeerIdentity().empty());
     EXPECT_FALSE(auth_ctx->IsPeerAuthenticated());
@@ -127,10 +129,9 @@
   if (request->has_param() && request->param().echo_metadata()) {
     const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata =
         context->client_metadata();
-    for (
-        std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator iter =
-            client_metadata.begin();
-        iter != client_metadata.end(); ++iter) {
+    for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
+             iter = client_metadata.begin();
+         iter != client_metadata.end(); ++iter) {
       context->AddTrailingMetadata(ToString(iter->first),
                                    ToString(iter->second));
     }
@@ -139,6 +140,7 @@
       (request->param().expected_client_identity().length() > 0 ||
        request->param().check_auth_context())) {
     CheckServerAuthContext(context,
+                           request->param().expected_transport_security_type(),
                            request->param().expected_client_identity());
   }
   if (request->has_param() && request->param().response_message_length() > 0) {
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index e246c0b..3f75a0c 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -45,7 +45,7 @@
 #include <grpc/support/time.h>
 #include <gtest/gtest.h>
 
-#include "src/core/surface/api_trace.h"
+#include "src/core/lib/surface/api_trace.h"
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
@@ -58,6 +58,7 @@
 const int kNumThreads = 100;  // Number of threads
 const int kNumAsyncSendThreads = 2;
 const int kNumAsyncReceiveThreads = 50;
+const int kNumAsyncServerThreads = 50;
 const int kNumRpcs = 1000;  // Number of RPCs per thread
 
 namespace grpc {
@@ -174,23 +175,12 @@
   }
 };
 
+template <class Service>
 class CommonStressTest {
  public:
   CommonStressTest() : kMaxMessageSize_(8192) {}
-  void SetUp() {
-    int port = grpc_pick_unused_port_or_die();
-    server_address_ << "localhost:" << port;
-    // Setup server
-    ServerBuilder builder;
-    builder.AddListeningPort(server_address_.str(),
-                             InsecureServerCredentials());
-    builder.RegisterService(&service_);
-    builder.SetMaxMessageSize(
-        kMaxMessageSize_);  // For testing max message size.
-    builder.RegisterService(&dup_pkg_service_);
-    server_ = builder.BuildAndStart();
-  }
-  void TearDown() { server_->Shutdown(); }
+  virtual void SetUp() = 0;
+  virtual void TearDown() = 0;
   void ResetStub() {
     std::shared_ptr<Channel> channel =
         CreateChannel(server_address_.str(), InsecureChannelCredentials());
@@ -198,15 +188,137 @@
   }
   grpc::testing::EchoTestService::Stub* GetStub() { return stub_.get(); }
 
+ protected:
+  void SetUpStart(ServerBuilder* builder, Service* service) {
+    int port = grpc_pick_unused_port_or_die();
+    server_address_ << "localhost:" << port;
+    // Setup server
+    builder->AddListeningPort(server_address_.str(),
+                              InsecureServerCredentials());
+    builder->RegisterService(service);
+    builder->SetMaxMessageSize(
+        kMaxMessageSize_);  // For testing max message size.
+    builder->RegisterService(&dup_pkg_service_);
+  }
+  void SetUpEnd(ServerBuilder* builder) { server_ = builder->BuildAndStart(); }
+  void TearDownStart() { server_->Shutdown(); }
+  void TearDownEnd() {}
+
  private:
   std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
   std::unique_ptr<Server> server_;
   std::ostringstream server_address_;
   const int kMaxMessageSize_;
-  TestServiceImpl service_;
   TestServiceImplDupPkg dup_pkg_service_;
 };
 
+class CommonStressTestSyncServer : public CommonStressTest<TestServiceImpl> {
+ public:
+  void SetUp() GRPC_OVERRIDE {
+    ServerBuilder builder;
+    SetUpStart(&builder, &service_);
+    SetUpEnd(&builder);
+  }
+  void TearDown() GRPC_OVERRIDE {
+    TearDownStart();
+    TearDownEnd();
+  }
+
+ private:
+  TestServiceImpl service_;
+};
+
+class CommonStressTestAsyncServer
+    : public CommonStressTest<::grpc::testing::EchoTestService::AsyncService> {
+ public:
+  void SetUp() GRPC_OVERRIDE {
+    shutting_down_ = false;
+    ServerBuilder builder;
+    SetUpStart(&builder, &service_);
+    cq_ = builder.AddCompletionQueue();
+    SetUpEnd(&builder);
+    contexts_ = new Context[kNumAsyncServerThreads * 100];
+    for (int i = 0; i < kNumAsyncServerThreads * 100; i++) {
+      RefreshContext(i);
+    }
+    for (int i = 0; i < kNumAsyncServerThreads; i++) {
+      server_threads_.push_back(
+          new std::thread(&CommonStressTestAsyncServer::ProcessRpcs, this));
+    }
+  }
+  void TearDown() GRPC_OVERRIDE {
+    {
+      unique_lock<mutex> l(mu_);
+      TearDownStart();
+      shutting_down_ = true;
+      cq_->Shutdown();
+    }
+
+    for (int i = 0; i < kNumAsyncServerThreads; i++) {
+      server_threads_[i]->join();
+      delete server_threads_[i];
+    }
+
+    void* ignored_tag;
+    bool ignored_ok;
+    while (cq_->Next(&ignored_tag, &ignored_ok))
+      ;
+    TearDownEnd();
+    delete[] contexts_;
+  }
+
+ private:
+  void ProcessRpcs() {
+    void* tag;
+    bool ok;
+    while (cq_->Next(&tag, &ok)) {
+      if (ok) {
+        int i = static_cast<int>(reinterpret_cast<intptr_t>(tag));
+        switch (contexts_[i].state) {
+          case Context::READY: {
+            contexts_[i].state = Context::DONE;
+            EchoResponse send_response;
+            send_response.set_message(contexts_[i].recv_request.message());
+            contexts_[i].response_writer->Finish(send_response, Status::OK,
+                                                 tag);
+            break;
+          }
+          case Context::DONE:
+            RefreshContext(i);
+            break;
+        }
+      }
+    }
+  }
+  void RefreshContext(int i) {
+    unique_lock<mutex> l(mu_);
+    if (!shutting_down_) {
+      contexts_[i].state = Context::READY;
+      contexts_[i].srv_ctx.reset(new ServerContext);
+      contexts_[i].response_writer.reset(
+          new grpc::ServerAsyncResponseWriter<EchoResponse>(
+              contexts_[i].srv_ctx.get()));
+      service_.RequestEcho(contexts_[i].srv_ctx.get(),
+                           &contexts_[i].recv_request,
+                           contexts_[i].response_writer.get(), cq_.get(),
+                           cq_.get(), (void*)(intptr_t)i);
+    }
+  }
+  struct Context {
+    std::unique_ptr<ServerContext> srv_ctx;
+    std::unique_ptr<grpc::ServerAsyncResponseWriter<EchoResponse>>
+        response_writer;
+    EchoRequest recv_request;
+    enum { READY, DONE } state;
+  } * contexts_;
+  ::grpc::testing::EchoTestService::AsyncService service_;
+  std::unique_ptr<ServerCompletionQueue> cq_;
+  bool shutting_down_;
+  mutex mu_;
+  std::vector<std::thread*> server_threads_;
+};
+
+template <class Common>
 class End2endTest : public ::testing::Test {
  protected:
   End2endTest() {}
@@ -214,7 +326,7 @@
   void TearDown() GRPC_OVERRIDE { common_.TearDown(); }
   void ResetStub() { common_.ResetStub(); }
 
-  CommonStressTest common_;
+  Common common_;
 };
 
 static void SendRpc(grpc::testing::EchoTestService::Stub* stub, int num_rpcs) {
@@ -230,11 +342,16 @@
   }
 }
 
-TEST_F(End2endTest, ThreadStress) {
-  common_.ResetStub();
+typedef ::testing::Types<CommonStressTestSyncServer,
+                         CommonStressTestAsyncServer>
+    CommonTypes;
+TYPED_TEST_CASE(End2endTest, CommonTypes);
+TYPED_TEST(End2endTest, ThreadStress) {
+  this->common_.ResetStub();
   std::vector<std::thread*> threads;
   for (int i = 0; i < kNumThreads; ++i) {
-    threads.push_back(new std::thread(SendRpc, common_.GetStub(), kNumRpcs));
+    threads.push_back(
+        new std::thread(SendRpc, this->common_.GetStub(), kNumRpcs));
   }
   for (int i = 0; i < kNumThreads; ++i) {
     threads[i]->join();
@@ -242,6 +359,7 @@
   }
 }
 
+template <class Common>
 class AsyncClientEnd2endTest : public ::testing::Test {
  protected:
   AsyncClientEnd2endTest() : rpcs_outstanding_(0) {}
@@ -309,31 +427,33 @@
     }
   }
 
-  CommonStressTest common_;
+  Common common_;
   CompletionQueue cq_;
   mutex mu_;
   condition_variable cv_;
   int rpcs_outstanding_;
 };
 
-TEST_F(AsyncClientEnd2endTest, ThreadStress) {
-  common_.ResetStub();
-  std::vector<std::thread*> send_threads, completion_threads;
+TYPED_TEST_CASE(AsyncClientEnd2endTest, CommonTypes);
+TYPED_TEST(AsyncClientEnd2endTest, ThreadStress) {
+  this->common_.ResetStub();
+  std::vector<std::thread *> send_threads, completion_threads;
   for (int i = 0; i < kNumAsyncReceiveThreads; ++i) {
     completion_threads.push_back(new std::thread(
-        &AsyncClientEnd2endTest_ThreadStress_Test::AsyncCompleteRpc, this));
+        &AsyncClientEnd2endTest_ThreadStress_Test<TypeParam>::AsyncCompleteRpc,
+        this));
   }
   for (int i = 0; i < kNumAsyncSendThreads; ++i) {
-    send_threads.push_back(
-        new std::thread(&AsyncClientEnd2endTest_ThreadStress_Test::AsyncSendRpc,
-                        this, kNumRpcs));
+    send_threads.push_back(new std::thread(
+        &AsyncClientEnd2endTest_ThreadStress_Test<TypeParam>::AsyncSendRpc,
+        this, kNumRpcs));
   }
   for (int i = 0; i < kNumAsyncSendThreads; ++i) {
     send_threads[i]->join();
     delete send_threads[i];
   }
 
-  Wait();
+  this->Wait();
   for (int i = 0; i < kNumAsyncReceiveThreads; ++i) {
     completion_threads[i]->join();
     delete completion_threads[i];
diff --git a/test/cpp/end2end/zookeeper_test.cc b/test/cpp/end2end/zookeeper_test.cc
index bbf1b0e..f1b6ac2 100644
--- a/test/cpp/end2end/zookeeper_test.cc
+++ b/test/cpp/end2end/zookeeper_test.cc
@@ -42,7 +42,7 @@
 #include <gtest/gtest.h>
 #include <zookeeper/zookeeper.h>
 
-#include "src/core/support/env.h"
+#include "src/core/lib/support/env.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
diff --git a/test/cpp/grpclb/grpclb_api_test.cc b/test/cpp/grpclb/grpclb_api_test.cc
index bd4885f..bc8219c 100644
--- a/test/cpp/grpclb/grpclb_api_test.cc
+++ b/test/cpp/grpclb/grpclb_api_test.cc
@@ -34,7 +34,7 @@
 #include <gtest/gtest.h>
 #include <string>
 
-#include "src/core/client_config/lb_policies/load_balancer_api.h"
+#include "src/core/lib/client_config/lb_policies/load_balancer_api.h"
 #include "src/proto/grpc/lb/v0/load_balancer.pb.h"  // C++ version
 
 namespace grpc {
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index 788adef..8b237fe 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -35,11 +35,11 @@
 
 #include <unistd.h>
 
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
 #include <gflags/gflags.h>
 #include <grpc++/channel.h>
 #include <grpc++/client_context.h>
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
 
 #include "test/cpp/interop/client_helper.h"
 #include "test/cpp/interop/interop_client.h"
diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc
index 5caf0f2..029b967 100644
--- a/test/cpp/interop/client_helper.cc
+++ b/test/cpp/interop/client_helper.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,13 +39,13 @@
 #include <memory>
 #include <sstream>
 
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
 #include <gflags/gflags.h>
 #include <grpc++/channel.h>
 #include <grpc++/create_channel.h>
 #include <grpc++/security/credentials.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
 
 #include "src/cpp/client/secure_credentials.h"
 #include "test/core/security/oauth2_utils.h"
diff --git a/test/cpp/interop/client_helper.h b/test/cpp/interop/client_helper.h
index 0f77474..0790464 100644
--- a/test/cpp/interop/client_helper.h
+++ b/test/cpp/interop/client_helper.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,7 @@
 
 #include <grpc++/channel.h>
 
-#include "src/core/surface/call_test_only.h"
+#include "src/core/lib/surface/call_test_only.h"
 
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index 46f6fda..2fcd9f3 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -46,10 +46,10 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/transport/byte_stream.h"
+#include "src/core/lib/transport/byte_stream.h"
 #include "src/proto/grpc/testing/empty.grpc.pb.h"
-#include "src/proto/grpc/testing/test.grpc.pb.h"
 #include "src/proto/grpc/testing/messages.grpc.pb.h"
+#include "src/proto/grpc/testing/test.grpc.pb.h"
 #include "test/cpp/interop/client_helper.h"
 
 namespace grpc {
diff --git a/test/cpp/interop/interop_client.h b/test/cpp/interop/interop_client.h
index 3f57f3c..e6706b5 100644
--- a/test/cpp/interop/interop_client.h
+++ b/test/cpp/interop/interop_client.h
@@ -36,8 +36,8 @@
 
 #include <memory>
 
-#include <grpc/grpc.h>
 #include <grpc++/channel.h>
+#include <grpc/grpc.h>
 #include "src/proto/grpc/testing/messages.grpc.pb.h"
 #include "src/proto/grpc/testing/test.grpc.pb.h"
 
diff --git a/test/cpp/interop/interop_test.cc b/test/cpp/interop/interop_test.cc
index faf6698..f1fb3c9 100644
--- a/test/cpp/interop/interop_test.cc
+++ b/test/cpp/interop/interop_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,14 +35,14 @@
 #define _POSIX_SOURCE
 #endif
 
-#include <unistd.h>
 #include <assert.h>
-#include <stdio.h>
-#include <string.h>
 #include <signal.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <unistd.h>
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
@@ -51,8 +51,8 @@
 #include "test/core/util/port.h"
 
 extern "C" {
-#include "src/core/iomgr/socket_utils_posix.h"
-#include "src/core/support/string.h"
+#include "src/core/lib/iomgr/socket_utils_posix.h"
+#include "src/core/lib/support/string.h"
 }
 
 int test_client(const char* root, const char* host, int port) {
diff --git a/test/cpp/interop/reconnect_interop_client.cc b/test/cpp/interop/reconnect_interop_client.cc
index 79a60cc..c668eda 100644
--- a/test/cpp/interop/reconnect_interop_client.cc
+++ b/test/cpp/interop/reconnect_interop_client.cc
@@ -34,16 +34,16 @@
 #include <memory>
 #include <sstream>
 
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
 #include <gflags/gflags.h>
 #include <grpc++/channel.h>
 #include <grpc++/client_context.h>
-#include "test/cpp/util/create_test_channel.h"
-#include "test/cpp/util/test_config.h"
-#include "src/proto/grpc/testing/test.grpc.pb.h"
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
 #include "src/proto/grpc/testing/empty.grpc.pb.h"
 #include "src/proto/grpc/testing/messages.grpc.pb.h"
+#include "src/proto/grpc/testing/test.grpc.pb.h"
+#include "test/cpp/util/create_test_channel.h"
+#include "test/cpp/util/test_config.h"
 
 DEFINE_int32(server_control_port, 0, "Server port for control rpcs.");
 DEFINE_int32(server_retry_port, 0, "Server port for testing reconnection.");
diff --git a/test/cpp/interop/reconnect_interop_server.cc b/test/cpp/interop/reconnect_interop_server.cc
index 3602b8c..1f9147d 100644
--- a/test/cpp/interop/reconnect_interop_server.cc
+++ b/test/cpp/interop/reconnect_interop_server.cc
@@ -31,6 +31,8 @@
  *
  */
 
+// Test description at doc/connection-backoff-interop-test-description.md
+
 #include <signal.h>
 #include <unistd.h>
 
@@ -40,17 +42,17 @@
 #include <sstream>
 
 #include <gflags/gflags.h>
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
 
-#include "test/core/util/reconnect_server.h"
-#include "test/cpp/util/test_config.h"
-#include "src/proto/grpc/testing/test.grpc.pb.h"
 #include "src/proto/grpc/testing/empty.grpc.pb.h"
 #include "src/proto/grpc/testing/messages.grpc.pb.h"
+#include "src/proto/grpc/testing/test.grpc.pb.h"
+#include "test/core/util/reconnect_server.h"
+#include "test/cpp/util/test_config.h"
 
 DEFINE_int32(control_port, 0, "Server port for controlling the server.");
 DEFINE_int32(retry_port, 0,
diff --git a/test/cpp/interop/server_helper.cc b/test/cpp/interop/server_helper.cc
index 9a28409..97c39c4 100644
--- a/test/cpp/interop/server_helper.cc
+++ b/test/cpp/interop/server_helper.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,7 @@
 #include <gflags/gflags.h>
 #include <grpc++/security/server_credentials.h>
 
-#include "src/core/surface/call_test_only.h"
+#include "src/core/lib/surface/call_test_only.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 
 DECLARE_bool(use_tls);
diff --git a/test/cpp/interop/server_helper.h b/test/cpp/interop/server_helper.h
index 57337e5..38c2fba 100644
--- a/test/cpp/interop/server_helper.h
+++ b/test/cpp/interop/server_helper.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,9 +36,9 @@
 
 #include <memory>
 
-#include <grpc/compression.h>
-#include <grpc++/server_context.h>
 #include <grpc++/security/server_credentials.h>
+#include <grpc++/server_context.h>
+#include <grpc/compression.h>
 
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/interop/server_main.cc b/test/cpp/interop/server_main.cc
index 18ac35d..8a71870 100644
--- a/test/cpp/interop/server_main.cc
+++ b/test/cpp/interop/server_main.cc
@@ -40,19 +40,19 @@
 #include <thread>
 
 #include <gflags/gflags.h>
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
+#include <grpc++/security/server_credentials.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
-#include <grpc++/security/server_credentials.h>
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
 
-#include "test/cpp/interop/server_helper.h"
-#include "test/cpp/util/test_config.h"
-#include "src/proto/grpc/testing/test.grpc.pb.h"
 #include "src/proto/grpc/testing/empty.grpc.pb.h"
 #include "src/proto/grpc/testing/messages.grpc.pb.h"
+#include "src/proto/grpc/testing/test.grpc.pb.h"
+#include "test/cpp/interop/server_helper.h"
+#include "test/cpp/util/test_config.h"
 
 DEFINE_bool(use_tls, false, "Whether to use tls.");
 DEFINE_int32(port, 0, "Server port.");
diff --git a/test/cpp/interop/stress_test.cc b/test/cpp/interop/stress_test.cc
index 702354d..162f7b3 100644
--- a/test/cpp/interop/stress_test.cc
+++ b/test/cpp/interop/stress_test.cc
@@ -43,12 +43,12 @@
 #include <grpc++/impl/thd.h>
 #include <grpc/support/time.h>
 
+#include "src/proto/grpc/testing/metrics.grpc.pb.h"
+#include "src/proto/grpc/testing/metrics.pb.h"
 #include "test/cpp/interop/interop_client.h"
 #include "test/cpp/interop/stress_interop_client.h"
 #include "test/cpp/util/metrics_server.h"
 #include "test/cpp/util/test_config.h"
-#include "src/proto/grpc/testing/metrics.grpc.pb.h"
-#include "src/proto/grpc/testing/metrics.pb.h"
 
 extern "C" {
 extern void gpr_default_log(gpr_log_func_args* args);
diff --git a/test/cpp/qps/async_streaming_ping_pong_test.cc b/test/cpp/qps/async_streaming_ping_pong_test.cc
index 9749932..d9fbb39 100644
--- a/test/cpp/qps/async_streaming_ping_pong_test.cc
+++ b/test/cpp/qps/async_streaming_ping_pong_test.cc
@@ -43,7 +43,7 @@
 namespace testing {
 
 static const int WARMUP = 5;
-static const int BENCHMARK = 10;
+static const int BENCHMARK = 5;
 
 static void RunAsyncStreamingPingPong() {
   gpr_log(GPR_INFO, "Running Async Streaming Ping Pong");
diff --git a/test/cpp/qps/async_unary_ping_pong_test.cc b/test/cpp/qps/async_unary_ping_pong_test.cc
index d801bdd..5ab8619 100644
--- a/test/cpp/qps/async_unary_ping_pong_test.cc
+++ b/test/cpp/qps/async_unary_ping_pong_test.cc
@@ -43,7 +43,7 @@
 namespace testing {
 
 static const int WARMUP = 5;
-static const int BENCHMARK = 10;
+static const int BENCHMARK = 5;
 
 static void RunAsyncUnaryPingPong() {
   gpr_log(GPR_INFO, "Running Async Unary Ping Pong");
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index 2dc83f0..92e77ee 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -123,15 +123,13 @@
     if (reset) {
       Histogram* to_merge = new Histogram[threads_.size()];
       for (size_t i = 0; i < threads_.size(); i++) {
-        threads_[i]->BeginSwap(&to_merge[i]);
-      }
-      std::unique_ptr<UsageTimer> timer(new UsageTimer);
-      timer_.swap(timer);
-      for (size_t i = 0; i < threads_.size(); i++) {
-        threads_[i]->EndSwap();
+        threads_[i]->Swap(&to_merge[i]);
         latencies.Merge(to_merge[i]);
       }
       delete[] to_merge;
+
+      std::unique_ptr<UsageTimer> timer(new UsageTimer);
+      timer_.swap(timer);
       timer_result = timer->Mark();
     } else {
       // merge snapshots of each thread histogram
@@ -227,7 +225,6 @@
    public:
     Thread(Client* client, size_t idx)
         : done_(false),
-          new_stats_(nullptr),
           client_(client),
           idx_(idx),
           impl_(&Thread::ThreadFunc, this) {}
@@ -240,16 +237,9 @@
       impl_.join();
     }
 
-    void BeginSwap(Histogram* n) {
+    void Swap(Histogram* n) {
       std::lock_guard<std::mutex> g(mu_);
-      new_stats_ = n;
-    }
-
-    void EndSwap() {
-      std::unique_lock<std::mutex> g(mu_);
-      while (new_stats_ != nullptr) {
-        cv_.wait(g);
-      };
+      n->Swap(&histogram_);
     }
 
     void MergeStatsInto(Histogram* hist) {
@@ -263,10 +253,11 @@
 
     void ThreadFunc() {
       for (;;) {
+        // lock since the thread should only be doing one thing at a time
+        std::lock_guard<std::mutex> g(mu_);
         // run the loop body
         const bool thread_still_ok = client_->ThreadFunc(&histogram_, idx_);
-        // lock, see if we're done
-        std::lock_guard<std::mutex> g(mu_);
+        // see if we're done
         if (!thread_still_ok) {
           gpr_log(GPR_ERROR, "Finishing client thread due to RPC error");
           done_ = true;
@@ -274,19 +265,11 @@
         if (done_) {
           return;
         }
-        // check if we're resetting stats, swap out the histogram if so
-        if (new_stats_) {
-          new_stats_->Swap(&histogram_);
-          new_stats_ = nullptr;
-          cv_.notify_one();
-        }
       }
     }
 
     std::mutex mu_;
-    std::condition_variable cv_;
     bool done_;
-    Histogram* new_stats_;
     Histogram histogram_;
     Client* client_;
     const size_t idx_;
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index 9e9da99..dcdb665 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -141,7 +141,8 @@
   std::function<gpr_timespec()> next_issue_;
   std::function<std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>(
       BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&,
-      CompletionQueue*)> start_req_;
+      CompletionQueue*)>
+      start_req_;
   grpc::Status status_;
   double start_;
   std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>
@@ -359,10 +360,10 @@
   State next_state_;
   std::function<void(grpc::Status, ResponseType*)> callback_;
   std::function<gpr_timespec()> next_issue_;
-  std::function<
-      std::unique_ptr<grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>(
-          BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*,
-          void*)> start_req_;
+  std::function<std::unique_ptr<
+      grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>(
+      BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*, void*)>
+      start_req_;
   grpc::Status status_;
   double start_;
   std::unique_ptr<grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>
@@ -491,7 +492,8 @@
   std::function<gpr_timespec()> next_issue_;
   std::function<std::unique_ptr<grpc::GenericClientAsyncReaderWriter>(
       grpc::GenericStub*, grpc::ClientContext*, const grpc::string&,
-      CompletionQueue*, void*)> start_req_;
+      CompletionQueue*, void*)>
+      start_req_;
   grpc::Status status_;
   double start_;
   std::unique_ptr<grpc::GenericClientAsyncReaderWriter> stream_;
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index 4284e07..a1489d8 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -53,7 +53,7 @@
 #include <grpc/support/time.h>
 #include <gtest/gtest.h>
 
-#include "src/core/profiling/timers.h"
+#include "src/core/lib/profiling/timers.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
 #include "test/cpp/qps/client.h"
 #include "test/cpp/qps/histogram.h"
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index 1c7fdf8..6cca7de 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -43,8 +43,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
+#include <gtest/gtest.h>
 
-#include "src/core/support/env.h"
+#include "src/core/lib/support/env.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
@@ -120,11 +121,9 @@
 namespace runsc {
 
 // ClientContext allocator
-template <class T>
-static ClientContext* AllocContext(list<ClientContext>* contexts, T deadline) {
+static ClientContext* AllocContext(list<ClientContext>* contexts) {
   contexts->emplace_back();
   auto context = &contexts->back();
-  context->set_deadline(deadline);
   return context;
 }
 
@@ -196,9 +195,6 @@
   // Trim to just what we need
   workers.resize(num_clients + num_servers);
 
-  gpr_timespec deadline =
-      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(warmup_seconds + benchmark_seconds + 20);
-
   // Start servers
   using runsc::ServerData;
   // servers is array rather than std::vector to avoid gcc-4.4 issues
@@ -248,7 +244,7 @@
     ServerArgs args;
     *args.mutable_setup() = server_config;
     servers[i].stream =
-        servers[i].stub->RunServer(runsc::AllocContext(&contexts, deadline));
+        servers[i].stub->RunServer(runsc::AllocContext(&contexts));
     GPR_ASSERT(servers[i].stream->Write(args));
     ServerStatus init_status;
     GPR_ASSERT(servers[i].stream->Read(&init_status));
@@ -304,7 +300,7 @@
     ClientArgs args;
     *args.mutable_setup() = per_client_config;
     clients[i].stream =
-        clients[i].stub->RunClient(runsc::AllocContext(&contexts, deadline));
+        clients[i].stub->RunClient(runsc::AllocContext(&contexts));
     GPR_ASSERT(clients[i].stream->Write(args));
     ClientStatus init_status;
     GPR_ASSERT(clients[i].stream->Read(&init_status));
@@ -342,25 +338,17 @@
   // Use gpr_sleep_until rather than this_thread::sleep_until to support
   // compilers that don't work with this_thread
   gpr_sleep_until(gpr_time_add(
-      start, gpr_time_from_seconds(benchmark_seconds, GPR_TIMESPAN)));
+      start,
+      gpr_time_from_seconds(warmup_seconds + benchmark_seconds, GPR_TIMESPAN)));
 
   // Finish a run
   std::unique_ptr<ScenarioResult> result(new ScenarioResult);
   result->client_config = result_client_config;
   result->server_config = result_server_config;
-  gpr_log(GPR_INFO, "Finishing");
-  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
-    GPR_ASSERT(server->stream->Write(server_mark));
-  }
+  gpr_log(GPR_INFO, "Finishing clients");
   for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
     GPR_ASSERT(client->stream->Write(client_mark));
-  }
-  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
-    GPR_ASSERT(server->stream->Read(&server_status));
-    const auto& stats = server_status.stats();
-    result->server_resources.emplace_back(
-        stats.time_elapsed(), stats.time_user(), stats.time_system(),
-        server_status.cores());
+    GPR_ASSERT(client->stream->WritesDone());
   }
   for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
     GPR_ASSERT(client->stream->Read(&client_status));
@@ -368,17 +356,30 @@
     result->latencies.MergeProto(stats.latencies());
     result->client_resources.emplace_back(
         stats.time_elapsed(), stats.time_user(), stats.time_system(), -1);
+    GPR_ASSERT(!client->stream->Read(&client_status));
   }
-
   for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
-    GPR_ASSERT(client->stream->WritesDone());
     GPR_ASSERT(client->stream->Finish().ok());
   }
+  delete[] clients;
+
+  gpr_log(GPR_INFO, "Finishing servers");
   for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
+    GPR_ASSERT(server->stream->Write(server_mark));
     GPR_ASSERT(server->stream->WritesDone());
+  }
+  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
+    GPR_ASSERT(server->stream->Read(&server_status));
+    const auto& stats = server_status.stats();
+    result->server_resources.emplace_back(
+        stats.time_elapsed(), stats.time_user(), stats.time_system(),
+        server_status.cores());
+    GPR_ASSERT(!server->stream->Read(&server_status));
+  }
+  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
     GPR_ASSERT(server->stream->Finish().ok());
   }
-  delete[] clients;
+
   delete[] servers;
   return result;
 }
diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h
index 3af61f7..1e2e280 100644
--- a/test/cpp/qps/driver.h
+++ b/test/cpp/qps/driver.h
@@ -36,8 +36,8 @@
 
 #include <memory>
 
-#include "test/cpp/qps/histogram.h"
 #include "src/proto/grpc/testing/control.grpc.pb.h"
+#include "test/cpp/qps/histogram.h"
 
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/qps/generic_async_streaming_ping_pong_test.cc b/test/cpp/qps/generic_async_streaming_ping_pong_test.cc
index d9166ae..fc06cdd 100644
--- a/test/cpp/qps/generic_async_streaming_ping_pong_test.cc
+++ b/test/cpp/qps/generic_async_streaming_ping_pong_test.cc
@@ -43,7 +43,7 @@
 namespace testing {
 
 static const int WARMUP = 5;
-static const int BENCHMARK = 10;
+static const int BENCHMARK = 5;
 
 static void RunGenericAsyncStreamingPingPong() {
   gpr_log(GPR_INFO, "Running Generic Async Streaming Ping Pong");
@@ -62,6 +62,7 @@
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_GENERIC_SERVER);
   server_config.set_async_server_threads(1);
+  *server_config.mutable_payload_config() = client_config.payload_config();
 
   const auto result =
       RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2);
diff --git a/test/cpp/qps/limit_cores.cc b/test/cpp/qps/limit_cores.cc
index fad9a32..59ed369 100644
--- a/test/cpp/qps/limit_cores.cc
+++ b/test/cpp/qps/limit_cores.cc
@@ -37,14 +37,15 @@
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
 
-namespace grpc {
-namespace testing {
-
 #ifdef GPR_CPU_LINUX
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
 #include <sched.h>
+
+namespace grpc {
+namespace testing {
+
 int LimitCores(const int* cores, int cores_size) {
   const int num_cores = gpr_cpu_num_cores();
   int cores_set = 0;
@@ -71,9 +72,16 @@
   CPU_FREE(cpup);
   return cores_set;
 }
-#else
-// LimitCores is not currently supported for non-Linux platforms
-int LimitCores(const int*, int) { return gpr_cpu_num_cores(); }
-#endif
+
 }  // namespace testing
 }  // namespace grpc
+#else
+namespace grpc {
+namespace testing {
+
+// LimitCores is not currently supported for non-Linux platforms
+int LimitCores(const int*, int) { return gpr_cpu_num_cores(); }
+
+}  // namespace testing
+}  // namespace grpc
+#endif
diff --git a/test/cpp/qps/perf_db_client.h b/test/cpp/qps/perf_db_client.h
index ece020a..668083b 100644
--- a/test/cpp/qps/perf_db_client.h
+++ b/test/cpp/qps/perf_db_client.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,17 +31,17 @@
  *
  */
 
+#include <cfloat>
 #include <iostream>
 #include <memory>
 #include <string>
-#include <cfloat>
 
-#include <grpc/grpc.h>
-#include <grpc++/support/channel_arguments.h>
 #include <grpc++/channel.h>
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
 #include <grpc++/security/credentials.h>
+#include <grpc++/support/channel_arguments.h>
+#include <grpc/grpc.h>
 #include "src/proto/grpc/testing/perf_db.grpc.pb.h"
 
 namespace grpc {
diff --git a/test/cpp/qps/qps_driver.cc b/test/cpp/qps/qps_driver.cc
index 69fb4d7..f9bd01b 100644
--- a/test/cpp/qps/qps_driver.cc
+++ b/test/cpp/qps/qps_driver.cc
@@ -171,6 +171,10 @@
     server_config.set_core_limit(FLAGS_server_core_limit);
   }
 
+  if (FLAGS_bbuf_resp_size >= 0) {
+    *server_config.mutable_payload_config() = client_config.payload_config();
+  }
+
   if (FLAGS_secure_test) {
     // Set up security params
     SecurityParams security;
diff --git a/test/cpp/qps/qps_openloop_test.cc b/test/cpp/qps/qps_openloop_test.cc
index 27f266b..2ae0afb 100644
--- a/test/cpp/qps/qps_openloop_test.cc
+++ b/test/cpp/qps/qps_openloop_test.cc
@@ -44,7 +44,7 @@
 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");
diff --git a/test/cpp/qps/qps_test.cc b/test/cpp/qps/qps_test.cc
index 27aaf13..b6a2e1e 100644
--- a/test/cpp/qps/qps_test.cc
+++ b/test/cpp/qps/qps_test.cc
@@ -43,7 +43,7 @@
 namespace testing {
 
 static const int WARMUP = 20;
-static const int BENCHMARK = 40;
+static const int BENCHMARK = 20;
 
 static void RunQPS() {
   gpr_log(GPR_INFO, "Running QPS test");
diff --git a/test/cpp/qps/qps_test_with_poll.cc b/test/cpp/qps/qps_test_with_poll.cc
index 8340a63..647aaac 100644
--- a/test/cpp/qps/qps_test_with_poll.cc
+++ b/test/cpp/qps/qps_test_with_poll.cc
@@ -40,7 +40,7 @@
 #include "test/cpp/util/benchmark_config.h"
 
 extern "C" {
-#include "src/core/iomgr/pollset_posix.h"
+#include "src/core/lib/iomgr/pollset_posix.h"
 }
 
 namespace grpc {
diff --git a/test/cpp/qps/secure_sync_unary_ping_pong_test.cc b/test/cpp/qps/secure_sync_unary_ping_pong_test.cc
index 359310b..946c76f 100644
--- a/test/cpp/qps/secure_sync_unary_ping_pong_test.cc
+++ b/test/cpp/qps/secure_sync_unary_ping_pong_test.cc
@@ -43,7 +43,7 @@
 namespace testing {
 
 static const int WARMUP = 5;
-static const int BENCHMARK = 10;
+static const int BENCHMARK = 5;
 
 static void RunSynchronousUnaryPingPong() {
   gpr_log(GPR_INFO, "Running Synchronous Unary Ping Pong");
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index 2024e0b..1bfb070 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -130,8 +130,7 @@
     }
   }
   ~AsyncQpsServerTest() {
-    auto deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
-    server_->Shutdown(deadline);
+    server_->Shutdown();
     for (auto ss = shutdown_state_.begin(); ss != shutdown_state_.end(); ++ss) {
       (*ss)->set_shutdown();
     }
@@ -388,12 +387,14 @@
 }
 
 std::unique_ptr<Server> CreateAsyncServer(const ServerConfig &config) {
-  return std::unique_ptr<Server>(new AsyncQpsServerTest<
-      SimpleRequest, SimpleResponse, BenchmarkService::AsyncService,
-      grpc::ServerContext>(
-      config, RegisterBenchmarkService,
-      &BenchmarkService::AsyncService::RequestUnaryCall,
-      &BenchmarkService::AsyncService::RequestStreamingCall, ProcessSimpleRPC));
+  return std::unique_ptr<Server>(
+      new AsyncQpsServerTest<SimpleRequest, SimpleResponse,
+                             BenchmarkService::AsyncService,
+                             grpc::ServerContext>(
+          config, RegisterBenchmarkService,
+          &BenchmarkService::AsyncService::RequestUnaryCall,
+          &BenchmarkService::AsyncService::RequestStreamingCall,
+          ProcessSimpleRPC));
 }
 std::unique_ptr<Server> CreateAsyncGenericServer(const ServerConfig &config) {
   return std::unique_ptr<Server>(
diff --git a/test/cpp/qps/sync_streaming_ping_pong_test.cc b/test/cpp/qps/sync_streaming_ping_pong_test.cc
index e02c14c..ee1bbc7 100644
--- a/test/cpp/qps/sync_streaming_ping_pong_test.cc
+++ b/test/cpp/qps/sync_streaming_ping_pong_test.cc
@@ -43,7 +43,7 @@
 namespace testing {
 
 static const int WARMUP = 5;
-static const int BENCHMARK = 10;
+static const int BENCHMARK = 5;
 
 static void RunSynchronousStreamingPingPong() {
   gpr_log(GPR_INFO, "Running Synchronous Streaming Ping Pong");
diff --git a/test/cpp/qps/sync_unary_ping_pong_test.cc b/test/cpp/qps/sync_unary_ping_pong_test.cc
index 9d363c0..4dccfee 100644
--- a/test/cpp/qps/sync_unary_ping_pong_test.cc
+++ b/test/cpp/qps/sync_unary_ping_pong_test.cc
@@ -43,7 +43,7 @@
 namespace testing {
 
 static const int WARMUP = 5;
-static const int BENCHMARK = 10;
+static const int BENCHMARK = 5;
 
 static void RunSynchronousUnaryPingPong() {
   gpr_log(GPR_INFO, "Running Synchronous Unary Ping Pong");
diff --git a/test/cpp/util/benchmark_config.cc b/test/cpp/util/benchmark_config.cc
index 3c38221..5c3a4cf 100644
--- a/test/cpp/util/benchmark_config.cc
+++ b/test/cpp/util/benchmark_config.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,8 @@
  *
  */
 
-#include <gflags/gflags.h>
 #include "test/cpp/util/benchmark_config.h"
+#include <gflags/gflags.h>
 
 DEFINE_bool(enable_log_reporter, true,
             "Enable reporting of benchmark results through GprLog");
diff --git a/test/cpp/util/byte_buffer_test.cc b/test/cpp/util/byte_buffer_test.cc
index f36c32c..bc172e9 100644
--- a/test/cpp/util/byte_buffer_test.cc
+++ b/test/cpp/util/byte_buffer_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,8 +36,8 @@
 #include <cstring>
 #include <vector>
 
-#include <grpc/support/slice.h>
 #include <grpc++/support/slice.h>
+#include <grpc/support/slice.h>
 #include <gtest/gtest.h>
 
 namespace grpc {
@@ -105,6 +105,24 @@
   EXPECT_TRUE(SliceEqual(slices[1], world));
 }
 
+TEST_F(ByteBufferTest, SerializationMakesCopy) {
+  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));
+  grpc_byte_buffer* send_buffer = nullptr;
+  bool owned = false;
+  ByteBuffer buffer(&slices[0], 2);
+  slices.clear();
+  auto status = SerializationTraits<ByteBuffer, void>::Serialize(
+      buffer, &send_buffer, &owned);
+  EXPECT_TRUE(status.ok());
+  EXPECT_TRUE(owned);
+  EXPECT_TRUE(send_buffer != nullptr);
+  grpc_byte_buffer_destroy(send_buffer);
+}
+
 }  // namespace
 }  // namespace grpc
 
diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc
index 5fdf519..474ac28 100644
--- a/test/cpp/util/cli_call_test.cc
+++ b/test/cpp/util/cli_call_test.cc
@@ -33,18 +33,18 @@
 
 #include "test/cpp/util/cli_call.h"
 
-#include <grpc/grpc.h>
 #include <grpc++/channel.h>
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
+#include <grpc/grpc.h>
 #include <gtest/gtest.h>
 
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
-#include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/cpp/util/string_ref_helper.h"
 
 using grpc::testing::EchoRequest;
diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc
index f9b9f0c..0b0bc20 100644
--- a/test/cpp/util/grpc_cli.cc
+++ b/test/cpp/util/grpc_cli.cc
@@ -1,6 +1,6 @@
 /*
 
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -65,11 +65,11 @@
 #include <sstream>
 
 #include <gflags/gflags.h>
-#include <grpc/grpc.h>
 #include <grpc++/channel.h>
 #include <grpc++/create_channel.h>
 #include <grpc++/security/credentials.h>
 #include <grpc++/support/string_ref.h>
+#include <grpc/grpc.h>
 
 #include "test/cpp/util/cli_call.h"
 #include "test/cpp/util/string_ref_helper.h"
diff --git a/test/cpp/util/test_config.cc b/test/cpp/util/test_config.cc
index e74f8fb..c446ae5 100644
--- a/test/cpp/util/test_config.cc
+++ b/test/cpp/util/test_config.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,8 @@
  *
  */
 
-#include <gflags/gflags.h>
 #include "test/cpp/util/test_config.h"
+#include <gflags/gflags.h>
 
 // In some distros, gflags is in the namespace google, and in some others,
 // in gflags. This hack is enabling us to find both.
diff --git a/test/cpp/util/test_credentials_provider.cc b/test/cpp/util/test_credentials_provider.cc
index e314fd6..9c09a73 100644
--- a/test/cpp/util/test_credentials_provider.cc
+++ b/test/cpp/util/test_credentials_provider.cc
@@ -36,8 +36,8 @@
 
 #include <unordered_map>
 
-#include <grpc/support/sync.h>
 #include <grpc++/impl/sync.h>
+#include <grpc/support/sync.h>
 
 #include "test/core/end2end/data/ssl_test_data.h"
 
diff --git a/test/cpp/util/test_credentials_provider.h b/test/cpp/util/test_credentials_provider.h
index 50fadb5..1fb311e 100644
--- a/test/cpp/util/test_credentials_provider.h
+++ b/test/cpp/util/test_credentials_provider.h
@@ -44,7 +44,10 @@
 namespace testing {
 
 const char kInsecureCredentialsType[] = "INSECURE_CREDENTIALS";
-const char kTlsCredentialsType[] = "TLS_CREDENTIALS";
+
+// For real credentials, like tls/ssl, this name should match the AuthContext
+// property "transport_security_type".
+const char kTlsCredentialsType[] = "ssl";
 
 // Provide test credentials of a particular type.
 class CredentialTypeProvider {
diff --git a/test/cpp/util/time_test.cc b/test/cpp/util/time_test.cc
index 48c6ce7..e78c85b 100644
--- a/test/cpp/util/time_test.cc
+++ b/test/cpp/util/time_test.cc
@@ -31,8 +31,8 @@
  *
  */
 
-#include <grpc/support/time.h>
 #include <grpc++/support/time.h>
+#include <grpc/support/time.h>
 #include <gtest/gtest.h>
 
 using std::chrono::duration_cast;
diff --git a/third_party/boringssl b/third_party/boringssl
index 9f897b2..907ae62 160000
--- a/third_party/boringssl
+++ b/third_party/boringssl
@@ -1 +1 @@
-Subproject commit 9f897b25800d2f54f5c442ef01a60721aeca6d87
+Subproject commit 907ae62b9d81121cb86b604f83e6b811a43f7a87
diff --git a/tools/README.md b/tools/README.md
index df4c6ef..cb6c22d 100644
--- a/tools/README.md
+++ b/tools/README.md
@@ -1,13 +1,16 @@
-buildgen: template renderer for our build system.
+buildgen: Template renderer for our build system.
 
-distrib: scripts to distribute language-specific packages.
+distrib: Scripts to distribute language-specific packages.
 
 dockerfile: Docker files to test gRPC.
 
 doxygen: gRPC C/C++ documentation generation via Doxygen.
 
-gce: scripts to help setup testing infrastructure on GCE.
+gce: Scripts to help setup testing infrastructure on GCE.
 
-jenkins: support for running tests on Jenkins.
+gcp: Helper scripts for interacting with various services on GCP (like Google
+container engine, BigQuery etc)
 
-run_tests: scripts to run gRPC tests in parallel.
+jenkins: Support for running tests on Jenkins.
+
+run_tests: Scripts to run gRPC tests in parallel.
diff --git a/tools/buildgen/plugins/expand_filegroups.py b/tools/buildgen/plugins/expand_filegroups.py
index 156bdc4..c40143e 100755
--- a/tools/buildgen/plugins/expand_filegroups.py
+++ b/tools/buildgen/plugins/expand_filegroups.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,9 @@
   return False
 
 
+FILEGROUP_LISTS = ['src', 'headers', 'public_headers']
+
+
 def mako_plugin(dictionary):
   """The exported plugin code for expand_filegroups.
 
@@ -54,21 +57,44 @@
   filegroups_list = dictionary.get('filegroups')
   filegroups = {}
 
-  for fg in filegroups_list:
-    filegroups[fg['name']] = fg
+  todo = filegroups_list[:]
+  skips = 0
+
+  while todo:
+    assert skips != len(todo), "infinite loop in filegroup uses clauses"
+    # take the first element of the todo list
+    cur = todo[0]
+    todo = todo[1:]
+    # check all uses filegroups are present (if no, skip and come back later)
+    skip = False
+    for uses in cur.get('uses', []):
+      if uses not in filegroups:
+        skip = True
+    if skip:
+      skips += 1
+      todo.append(cur)
+    else:
+      skips = 0
+      for uses in cur.get('uses', []):
+        for lst in FILEGROUP_LISTS:
+          vals = cur.get(lst, [])
+          vals.extend(filegroups[uses].get(lst, []))
+          cur[lst] = vals
+      filegroups[cur['name']] = cur
+
+  # the above expansion can introduce duplicate filenames: contract them here
+  for fg in filegroups.itervalues():
+    for lst in FILEGROUP_LISTS:
+      fg[lst] = sorted(list(set(fg.get(lst, []))))
 
   for lib in libs:
     for fg_name in lib.get('filegroups', []):
       fg = filegroups[fg_name]
 
-      src = lib.get('src', [])
-      src.extend(fg.get('src', []))
-      lib['src'] = src
+      for lst in FILEGROUP_LISTS:
+        vals = lib.get(lst, [])
+        vals.extend(fg.get(lst, []))
+        lib[lst] = vals
 
-      headers = lib.get('headers', [])
-      headers.extend(fg.get('headers', []))
-      lib['headers'] = headers
-
-      public_headers = lib.get('public_headers', [])
-      public_headers.extend(fg.get('public_headers', []))
-      lib['public_headers'] = public_headers
+    for lst in FILEGROUP_LISTS:
+      lib[lst] = sorted(list(set(lib.get(lst, []))))
diff --git a/tools/buildgen/plugins/expand_version.py b/tools/buildgen/plugins/expand_version.py
index b55e1b1..dd77f7a 100755
--- a/tools/buildgen/plugins/expand_version.py
+++ b/tools/buildgen/plugins/expand_version.py
@@ -84,6 +84,11 @@
     else:
       return '%d.%d.%d' % (self.major, self.minor, self.patch)
 
+  def php(self):
+    """Version string in PHP style"""
+    """PECL does not allow tag in version string"""
+    return '%d.%d.%d' % (self.major, self.minor, self.patch)
+
 def mako_plugin(dictionary):
   """Expand version numbers:
      - for each language, ensure there's a language_version tag in
diff --git a/tools/codegen/core/gen_hpack_tables.c b/tools/codegen/core/gen_hpack_tables.c
index bae4e4c..cb2b89a 100644
--- a/tools/codegen/core/gen_hpack_tables.c
+++ b/tools/codegen/core/gen_hpack_tables.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,13 +33,13 @@
 
 /* generates constant tables for hpack.c */
 
+#include <assert.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <string.h>
-#include <assert.h>
 
 #include <grpc/support/log.h>
-#include "src/core/transport/chttp2/huffsyms.h"
+#include "src/core/ext/transport/chttp2/transport/huffsyms.h"
 
 /*
  * first byte LUT generation
diff --git a/tools/codegen/core/gen_load_balancing_proto.sh b/tools/codegen/core/gen_load_balancing_proto.sh
index fb6a468..6a5363e 100755
--- a/tools/codegen/core/gen_load_balancing_proto.sh
+++ b/tools/codegen/core/gen_load_balancing_proto.sh
@@ -82,7 +82,7 @@
 
 readonly GRPC_ROOT=$PWD
 
-OUTPUT_DIR="$GRPC_ROOT/src/core/proto/grpc/lb/v0"
+OUTPUT_DIR="$GRPC_ROOT/src/core/lib/proto/grpc/lb/v0"
 if [ $# -eq 2 ]; then
   mkdir -p "$2"
   if [ $? != 0 ]; then
@@ -122,7 +122,7 @@
 "$(basename $1)"
 
 readonly PROTO_BASENAME=$(basename $1 .proto)
-sed -i "s:$PROTO_BASENAME.pb.h:src/core/proto/grpc/lb/v0/$PROTO_BASENAME.pb.h:g" \
+sed -i "s:$PROTO_BASENAME.pb.h:src/core/lib/proto/grpc/lb/v0/$PROTO_BASENAME.pb.h:g" \
     "$OUTPUT_DIR/$PROTO_BASENAME.pb.c"
 
 # prepend copyright
diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py
index e6ae00e..70d4141 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -196,7 +196,7 @@
   all_strs.add(val)
   all_elems.add(elem)
   compression_elems.append(elem)
-  static_userdata[elem] = 1 + mask
+  static_userdata[elem] = 1 + (mask | 1)
 all_strs = sorted(list(all_strs), key=mangle)
 all_elems = sorted(list(all_elems), key=mangle)
 
@@ -215,9 +215,9 @@
     C = open('/dev/null', 'w')
 else:
   H = open(os.path.join(
-      os.path.dirname(sys.argv[0]), '../../../src/core/transport/static_metadata.h'), 'w')
+      os.path.dirname(sys.argv[0]), '../../../src/core/lib/transport/static_metadata.h'), 'w')
   C = open(os.path.join(
-      os.path.dirname(sys.argv[0]), '../../../src/core/transport/static_metadata.c'), 'w')
+      os.path.dirname(sys.argv[0]), '../../../src/core/lib/transport/static_metadata.c'), 'w')
 
 # copy-paste copyright notice from this file
 with open(sys.argv[0]) as my_source:
@@ -247,10 +247,10 @@
 print >>H, '#ifndef GRPC_INTERNAL_CORE_TRANSPORT_STATIC_METADATA_H'
 print >>H, '#define GRPC_INTERNAL_CORE_TRANSPORT_STATIC_METADATA_H'
 print >>H
-print >>H, '#include "src/core/transport/metadata.h"'
+print >>H, '#include "src/core/lib/transport/metadata.h"'
 print >>H
 
-print >>C, '#include "src/core/transport/static_metadata.h"'
+print >>C, '#include "src/core/lib/transport/static_metadata.h"'
 print >>C
 
 print >>H, '#define GRPC_STATIC_MDSTR_COUNT %d' % len(all_strs)
@@ -309,4 +309,3 @@
 
 H.close()
 C.close()
-
diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py
index 99771f9..5badbf4 100755
--- a/tools/distrib/check_copyright.py
+++ b/tools/distrib/check_copyright.py
@@ -105,7 +105,7 @@
      for k, v in LICENSE_PREFIX.iteritems())
 
 if args.precommit:
-  FILE_LIST_COMMAND = 'git diff --name-only HEAD | grep -v ^third_party/'
+  FILE_LIST_COMMAND = 'git status -z | grep -Poz \'(?<=^[MARC][MARCD ] )[^\s]+\''
 else:
   FILE_LIST_COMMAND = 'git ls-tree -r --name-only -r HEAD | grep -v ^third_party/'
 
diff --git a/tools/distrib/check_include_guards.py b/tools/distrib/check_include_guards.py
new file mode 100755
index 0000000..463e316
--- /dev/null
+++ b/tools/distrib/check_include_guards.py
@@ -0,0 +1,197 @@
+#!/usr/bin/env python2.7
+
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import argparse
+import os
+import re
+import sys
+import subprocess
+
+
+def build_valid_guard(fpath):
+  prefix = 'GRPC_' if not fpath.startswith('include/') else ''
+  return prefix + '_'.join(fpath.replace('++', 'XX').replace('.', '_').upper().split('/')[1:])
+
+
+def load(fpath):
+  with open(fpath, 'r') as f:
+    return f.read()
+
+
+def save(fpath, contents):
+  with open(fpath, 'w') as f:
+    f.write(contents)
+
+
+class GuardValidator(object):
+  def __init__(self):
+    self.ifndef_re = re.compile(r'#ifndef ([A-Z][A-Z_1-9]*)')
+    self.define_re = re.compile(r'#define ([A-Z][A-Z_1-9]*)')
+    self.endif_c_re = re.compile(r'#endif /\* ([A-Z][A-Z_1-9]*) \*/')
+    self.endif_cpp_re = re.compile(r'#endif  // ([A-Z][A-Z_1-9]*)')
+    self.failed = False
+
+  def fail(self, fpath, regexp, fcontents, match_txt, correct, fix):
+    cpp_header = 'grpc++' in fpath
+    self.failed = True
+    invalid_guards_msg_template = (
+        '{0}: Missing preprocessor guards (RE {1}). '
+        'Please wrap your code around the following guards:\n'
+        '#ifndef {2}\n'
+        '#define {2}\n'
+        '...\n'
+        '... epic code ...\n'
+        '...\n') + ('#endif  // {2}' if cpp_header else '#endif /* {2} */')
+    if not match_txt:
+      print invalid_guards_msg_template.format(fpath, regexp.pattern,
+                                               build_valid_guard(fpath))
+      return fcontents
+
+    print ('{}: Wrong preprocessor guards (RE {}):'
+           '\n\tFound {}, expected {}').format(
+        fpath, regexp.pattern, match_txt, correct)
+    if fix:
+      print 'Fixing {}...\n'.format(fpath)
+      fixed_fcontents = re.sub(match_txt, correct, fcontents)
+      if fixed_fcontents:
+        self.failed = False
+      return fixed_fcontents
+    else:
+      print
+    return fcontents
+
+  def check(self, fpath, fix):
+    cpp_header = 'grpc++' in fpath
+    valid_guard = build_valid_guard(fpath)
+
+    fcontents = load(fpath)
+
+    match = self.ifndef_re.search(fcontents)
+    if match.lastindex is None:
+      # No ifndef. Request manual addition with hints
+      self.fail(fpath, match.re, match.string, '', '', False)
+      return False  # failed
+
+    # Does the guard end with a '_H'?
+    running_guard = match.group(1)
+    if not running_guard.endswith('_H'):
+      fcontents = self.fail(fpath, match.re, match.string, match.group(1),
+                            valid_guard, fix)
+      if fix: save(fpath, fcontents)
+
+    # Is it the expected one based on the file path?
+    if running_guard != valid_guard:
+      fcontents = self.fail(fpath, match.re, match.string, match.group(1),
+                            valid_guard, fix)
+      if fix: save(fpath, fcontents)
+
+    # Is there a #define? Is it the same as the #ifndef one?
+    match = self.define_re.search(fcontents)
+    if match.lastindex is None:
+      # No define. Request manual addition with hints
+      self.fail(fpath, match.re, match.string, '', '', False)
+      return False  # failed
+
+    # Is the #define guard the same as the #ifndef guard?
+    if match.group(1) != running_guard:
+      fcontents = self.fail(fpath, match.re, match.string, match.group(1),
+                            valid_guard, fix)
+      if fix: save(fpath, fcontents)
+
+    # Is there a properly commented #endif?
+    endif_re = self.endif_cpp_re if cpp_header else self.endif_c_re
+    flines = fcontents.rstrip().splitlines()
+    match = endif_re.search(flines[-1])
+    if not match:
+      # No endif. Check if we have the last line as just '#endif' and if so
+      # replace it with a properly commented one.
+      if flines[-1] == '#endif':
+        flines[-1] = ('#endif' +
+                      ('  // {}\n'.format(valid_guard) if cpp_header
+                       else ' /* {} */\n'.format(valid_guard)))
+        if fix:
+            fcontents = '\n'.join(flines)
+            save(fpath, fcontents)
+      else:
+        # something else is wrong, bail out
+        self.fail(fpath, endif_re, flines[-1], '', '', False)
+    elif match.group(1) != running_guard:
+      # Is the #endif guard the same as the #ifndef and #define guards?
+      fcontents = self.fail(fpath, endif_re, fcontents, match.group(1),
+                            valid_guard, fix)
+      if fix: save(fpath, fcontents)
+
+    return not self.failed  # Did the check succeed? (ie, not failed)
+
+# find our home
+ROOT = os.path.abspath(
+    os.path.join(os.path.dirname(sys.argv[0]), '../..'))
+os.chdir(ROOT)
+
+# parse command line
+argp = argparse.ArgumentParser(description='include guard checker')
+argp.add_argument('-f', '--fix',
+                  default=False,
+                  action='store_true');
+argp.add_argument('--precommit',
+                  default=False,
+                  action='store_true')
+args = argp.parse_args()
+
+KNOWN_BAD = set([
+    'src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h',
+])
+
+
+grep_filter = r"grep -E '^(include|src/core)/.*\.h$'"
+if args.precommit:
+  git_command = 'git diff --name-only HEAD'
+else:
+  git_command = 'git ls-tree -r --name-only -r HEAD'
+
+FILE_LIST_COMMAND = ' | '.join((git_command, grep_filter))
+
+# scan files
+ok = True
+filename_list = []
+try:
+  filename_list = subprocess.check_output(FILE_LIST_COMMAND,
+                                          shell=True).splitlines()
+except subprocess.CalledProcessError:
+  sys.exit(0)
+
+validator = GuardValidator()
+
+for filename in filename_list:
+  if filename in KNOWN_BAD: continue
+  ok = validator.check(filename, args.fix)
+
+sys.exit(0 if ok else 1)
diff --git a/tools/distrib/check_nanopb_output.sh b/tools/distrib/check_nanopb_output.sh
index 5f49ebb..e0a6094 100755
--- a/tools/distrib/check_nanopb_output.sh
+++ b/tools/distrib/check_nanopb_output.sh
@@ -30,8 +30,6 @@
 
 set -ex
 
-apt-get install -y autoconf automake libtool curl python-virtualenv
-
 readonly NANOPB_TMP_OUTPUT="$(mktemp -d)"
 
 # install protoc version 3
@@ -62,7 +60,7 @@
   $NANOPB_TMP_OUTPUT
 
 # compare outputs to checked compiled code
-if ! diff -r $NANOPB_TMP_OUTPUT src/core/proto/grpc/lb/v0; then
-  echo "Outputs differ: $NANOPB_TMP_OUTPUT vs src/core/proto/grpc/lb/v0"
+if ! diff -r $NANOPB_TMP_OUTPUT src/core/lib/proto/grpc/lb/v0; then
+  echo "Outputs differ: $NANOPB_TMP_OUTPUT vs src/core/lib/proto/grpc/lb/v0"
   exit 2
 fi
diff --git a/tools/distrib/python_wrapper.sh b/tools/distrib/python_wrapper.sh
new file mode 100755
index 0000000..347a715
--- /dev/null
+++ b/tools/distrib/python_wrapper.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+for p in python2.7 python2.6 python2 python not_found ; do 
+
+  python=`which $p || echo not_found`
+
+  if [ -x "$python" ] ; then
+    break
+  fi
+
+done
+
+if [ -x "$python" ] ; then
+  exec $python $@
+else
+  echo "No acceptable version of python found on the system"
+  exit 1
+fi
diff --git a/tools/dockerfile/grpc_clang_format/Dockerfile b/tools/dockerfile/grpc_clang_format/Dockerfile
index 4b101f6..be2ffc5 100644
--- a/tools/dockerfile/grpc_clang_format/Dockerfile
+++ b/tools/dockerfile/grpc_clang_format/Dockerfile
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -27,9 +27,13 @@
 # (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 ubuntu:vivid
+FROM ubuntu:wily
 RUN apt-get update
-RUN apt-get -y install clang-format-3.6
+RUN apt-get -y install wget
+RUN echo deb http://llvm.org/apt/wily/ llvm-toolchain-wily main >> /etc/apt/sources.list
+RUN echo deb-src http://llvm.org/apt/wily/ llvm-toolchain-wily main >> /etc/apt/sources.list
+RUN wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key| apt-key add -
+RUN apt-get update
+RUN apt-get -y install clang-format-3.8
 ADD clang_format_all_the_things.sh /
 CMD ["echo 'Run with tools/distrib/clang_format_code.sh'"]
-
diff --git a/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh b/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
index d56bc01..a50ca17 100755
--- a/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
+++ b/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
@@ -37,7 +37,7 @@
 GLOB="*.h *.c *.cc"
 
 # clang format command
-CLANG_FORMAT=clang-format-3.6
+CLANG_FORMAT=clang-format-3.8
 
 files=
 for dir in $DIRS
diff --git a/tools/dockerfile/grpc_interop_stress_cxx/Dockerfile b/tools/dockerfile/grpc_interop_stress_cxx/Dockerfile
index 4123cc1..556a26e 100644
--- a/tools/dockerfile/grpc_interop_stress_cxx/Dockerfile
+++ b/tools/dockerfile/grpc_interop_stress_cxx/Dockerfile
@@ -27,12 +27,9 @@
 # (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 test suites
-# inside a docker container.
-
 FROM debian:jessie
 
-# Install Git.
+# Install Git and basic packages.
 RUN apt-get update && apt-get install -y \
   autoconf \
   autotools-dev \
@@ -43,13 +40,16 @@
   gcc \
   gcc-multilib \
   git \
+  golang \
   gyp \
+  lcov \
   libc6 \
   libc6-dbg \
   libc6-dev \
   libgtest-dev \
   libtool \
   make \
+  perl \
   strace \
   python-dev \
   python-setuptools \
@@ -59,7 +59,9 @@
   wget \
   zip && apt-get clean
 
-RUN easy_install -U pip
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
 
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
@@ -69,12 +71,47 @@
 RUN ln -s /usr/bin/ccache /usr/local/bin/clang
 RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
 
-##################
+#=================
 # C++ dependencies
-RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
 
-# Google Cloud platform API libraries (for BigQuery)
+# Google Cloud platform API libraries
+RUN apt-get update && apt-get install -y python-pip && apt-get clean
 RUN pip install --upgrade google-api-python-client
 
+
+#=================
+# Update clang to a version with improved tsan and fuzzing capabilities
+
+RUN apt-get update && apt-get -y install python cmake && apt-get clean
+
+RUN git clone -n -b release_38 http://llvm.org/git/llvm.git && \
+  cd llvm && git checkout ad57503 && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/clang.git && \
+  cd clang && git checkout ad2c56e && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/compiler-rt.git && \
+  cd compiler-rt && git checkout 3176922 && cd ..
+RUN git clone -n -b release_38 \
+  http://llvm.org/git/clang-tools-extra.git && cd clang-tools-extra && \
+  git checkout c288525 && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/libcxx.git && \
+  cd libcxx && git checkout fda3549  && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/libcxxabi.git && \
+  cd libcxxabi && git checkout 8d4e51d && cd ..
+
+RUN mv clang llvm/tools
+RUN mv compiler-rt llvm/projects
+RUN mv clang-tools-extra llvm/tools/clang/tools
+RUN mv libcxx llvm/projects
+RUN mv libcxxabi llvm/projects
+
+RUN mkdir llvm-build
+RUN cd llvm-build && cmake \
+  -DCMAKE_BUILD_TYPE:STRING=Release \
+  -DCMAKE_INSTALL_PREFIX:STRING=/usr \
+  -DLLVM_TARGETS_TO_BUILD:STRING=X86 \
+  ../llvm
+RUN make -C llvm-build -j 12 && make -C llvm-build install && rm -rf llvm-build
+
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_stress_cxx/build_interop_stress.sh b/tools/dockerfile/grpc_interop_stress_cxx/build_interop_stress.sh
index 392bdfc..470db4c 100755
--- a/tools/dockerfile/grpc_interop_stress_cxx/build_interop_stress.sh
+++ b/tools/dockerfile/grpc_interop_stress_cxx/build_interop_stress.sh
@@ -41,5 +41,7 @@
 
 make install-certs
 
+BUILD_TYPE=${BUILD_TYPE:=opt}
+
 # build C++ interop stress client, interop client and server
-make stress_test metrics_client interop_client interop_server
+make CONFIG=$BUILD_TYPE stress_test metrics_client interop_client interop_server
diff --git a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
index e3ed39d..6c7aece 100644
--- a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
@@ -67,6 +67,39 @@
 # C++ dependencies
 RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
 
+#=================
+# Update clang to a version with improved tsan and fuzzing capabilities
+
+RUN apt-get update && apt-get -y install python cmake && apt-get clean
+
+RUN git clone -n -b release_38 http://llvm.org/git/llvm.git && \
+  cd llvm && git checkout ad57503 && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/clang.git && \
+  cd clang && git checkout ad2c56e && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/compiler-rt.git && \
+  cd compiler-rt && git checkout 3176922 && cd ..
+RUN git clone -n -b release_38 \
+  http://llvm.org/git/clang-tools-extra.git && cd clang-tools-extra && \
+  git checkout c288525 && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/libcxx.git && \
+  cd libcxx && git checkout fda3549  && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/libcxxabi.git && \
+  cd libcxxabi && git checkout 8d4e51d && cd ..
+
+RUN mv clang llvm/tools
+RUN mv compiler-rt llvm/projects
+RUN mv clang-tools-extra llvm/tools/clang/tools
+RUN mv libcxx llvm/projects
+RUN mv libcxxabi llvm/projects
+
+RUN mkdir llvm-build
+RUN cd llvm-build && cmake \
+  -DCMAKE_BUILD_TYPE:STRING=Release \
+  -DCMAKE_INSTALL_PREFIX:STRING=/usr \
+  -DLLVM_TARGETS_TO_BUILD:STRING=X86 \
+  ../llvm
+RUN make -C llvm-build -j 12 && make -C llvm-build install && rm -rf llvm-build
+
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
diff --git a/tools/dockerfile/test/cxx_squeeze_x64/Dockerfile b/tools/dockerfile/test/cxx_squeeze_x64/Dockerfile
deleted file mode 100644
index b7f95aa..0000000
--- a/tools/dockerfile/test/cxx_squeeze_x64/Dockerfile
+++ /dev/null
@@ -1,88 +0,0 @@
-# Copyright 2016, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-FROM debian:squeeze
-
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  ccache \
-  curl \
-  gcc \
-  gcc-multilib \
-  git \
-  gyp \
-  lcov \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  perl \
-  strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
-
-#================
-# Build profiling
-RUN apt-get update && apt-get install -y time && apt-get clean
-
-
-# libgflags-dev is not available on squeezy
-RUN apt-get update && apt-get -y install libgtest-dev libc++-dev clang && apt-get clean
-
-RUN apt-get update && apt-get -y install python-pip && apt-get clean
-RUN pip install argparse
-
-RUN wget http://openssl.org/source/openssl-1.0.2f.tar.gz
-
-ENV POST_GIT_STEP tools/dockerfile/test/cxx_squeeze_x64/post-git-setup.sh
-
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
-
-
-RUN mkdir /var/local/jenkins
-
-# Define the default command.
-CMD ["bash"]
diff --git a/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile b/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
new file mode 100644
index 0000000..e8dab1b
--- /dev/null
+++ b/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
@@ -0,0 +1,86 @@
+# Copyright 2015-2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+FROM ubuntu:14.04
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile b/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile
new file mode 100644
index 0000000..6f330f9
--- /dev/null
+++ b/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile
@@ -0,0 +1,95 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+FROM debian:wheezy
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
+
+RUN apt-get update && apt-get install -y \
+  gcc-4.4 \
+  gcc-4.4-multilib
+
+RUN wget https://openssl.org/source/old/1.0.2/openssl-1.0.2f.tar.gz
+
+ENV POST_GIT_STEP tools/dockerfile/test/cxx_wheezy_x64/post-git-setup.sh
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/cxx_squeeze_x64/post-git-setup.sh b/tools/dockerfile/test/cxx_wheezy_x64/post-git-setup.sh
similarity index 100%
rename from tools/dockerfile/test/cxx_squeeze_x64/post-git-setup.sh
rename to tools/dockerfile/test/cxx_wheezy_x64/post-git-setup.sh
diff --git a/tools/dockerfile/test/fuzzer/Dockerfile b/tools/dockerfile/test/fuzzer/Dockerfile
new file mode 100644
index 0000000..7b35c00
--- /dev/null
+++ b/tools/dockerfile/test/fuzzer/Dockerfile
@@ -0,0 +1,123 @@
+# Copyright 2015-2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+FROM debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
+#=================
+# Update clang to a version with improved tsan and fuzzing capabilities
+
+RUN apt-get update && apt-get -y install python cmake && apt-get clean
+
+RUN git clone -n -b release_38 http://llvm.org/git/llvm.git && \
+  cd llvm && git checkout ad57503 && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/clang.git && \
+  cd clang && git checkout ad2c56e && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/compiler-rt.git && \
+  cd compiler-rt && git checkout 3176922 && cd ..
+RUN git clone -n -b release_38 \
+  http://llvm.org/git/clang-tools-extra.git && cd clang-tools-extra && \
+  git checkout c288525 && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/libcxx.git && \
+  cd libcxx && git checkout fda3549  && cd ..
+RUN git clone -n -b release_38 http://llvm.org/git/libcxxabi.git && \
+  cd libcxxabi && git checkout 8d4e51d && cd ..
+
+RUN mv clang llvm/tools
+RUN mv compiler-rt llvm/projects
+RUN mv clang-tools-extra llvm/tools/clang/tools
+RUN mv libcxx llvm/projects
+RUN mv libcxxabi llvm/projects
+
+RUN mkdir llvm-build
+RUN cd llvm-build && cmake \
+  -DCMAKE_BUILD_TYPE:STRING=Release \
+  -DCMAKE_INSTALL_PREFIX:STRING=/usr \
+  -DLLVM_TARGETS_TO_BUILD:STRING=X86 \
+  ../llvm
+RUN make -C llvm-build -j 12 && make -C llvm-build install && rm -rf llvm-build
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+RUN clang++ -c -g -O2 -std=c++11 llvm/lib/Fuzzer/*.cpp -IFuzzer
+RUN ar ruv libFuzzer.a Fuzzer*.o
+RUN mv libFuzzer.a /usr/lib
+RUN rm -f Fuzzer*.o
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
new file mode 100644
index 0000000..71ebf2b
--- /dev/null
+++ b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
@@ -0,0 +1,155 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+FROM debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#================
+# C# dependencies
+
+# Update to a newer version of mono
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
+
+# Install dependencies
+RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
+    mono-devel \
+    ca-certificates-mono \
+    nuget \
+    && apt-get clean
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
+#==================
+# Node dependencies
+
+# Install nvm
+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 && npm config set cache /tmp/npm-cache"
+
+#=================
+# PHP dependencies
+
+# Install dependencies
+
+RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
+    >> /etc/apt/sources.list.d/dotdeb.list"
+RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
+    >> /etc/apt/sources.list.d/dotdeb.list"
+RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
+
+RUN apt-get update && apt-get install -y \
+    git php5 php5-dev phpunit unzip
+
+#==================
+# Ruby dependencies
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.1
+RUN /bin/bash -l -c "rvm install ruby-2.1"
+RUN /bin/bash -l -c "rvm use --default ruby-2.1"
+RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
+RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
+
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 tox
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/sanity/Dockerfile b/tools/dockerfile/test/sanity/Dockerfile
index 1935f67..4a69cd8 100644
--- a/tools/dockerfile/test/sanity/Dockerfile
+++ b/tools/dockerfile/test/sanity/Dockerfile
@@ -65,7 +65,13 @@
 
 #========================
 # Sanity test dependencies
-RUN apt-get update && apt-get install -y python-pip
+RUN apt-get update && apt-get install -y \
+      python-pip \
+      autoconf \
+      automake \
+      libtool \
+      curl \
+      python-virtualenv
 RUN pip install simplejson mako
 
 #===================
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 8256faf..fe7962b 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.13.1-pre1
+PROJECT_NUMBER         = 0.14.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -770,6 +770,37 @@
 include/grpc++/grpc++.h \
 include/grpc++/impl/call.h \
 include/grpc++/impl/client_unary_call.h \
+include/grpc++/impl/codegen/async_stream.h \
+include/grpc++/impl/codegen/async_unary_call.h \
+include/grpc++/impl/codegen/call.h \
+include/grpc++/impl/codegen/call_hook.h \
+include/grpc++/impl/codegen/channel_interface.h \
+include/grpc++/impl/codegen/client_context.h \
+include/grpc++/impl/codegen/client_unary_call.h \
+include/grpc++/impl/codegen/completion_queue.h \
+include/grpc++/impl/codegen/completion_queue_tag.h \
+include/grpc++/impl/codegen/config.h \
+include/grpc++/impl/codegen/config_protobuf.h \
+include/grpc++/impl/codegen/core_codegen_interface.h \
+include/grpc++/impl/codegen/grpc_library.h \
+include/grpc++/impl/codegen/method_handler_impl.h \
+include/grpc++/impl/codegen/proto_utils.h \
+include/grpc++/impl/codegen/rpc_method.h \
+include/grpc++/impl/codegen/rpc_service_method.h \
+include/grpc++/impl/codegen/security/auth_context.h \
+include/grpc++/impl/codegen/serialization_traits.h \
+include/grpc++/impl/codegen/server_context.h \
+include/grpc++/impl/codegen/server_interface.h \
+include/grpc++/impl/codegen/service_type.h \
+include/grpc++/impl/codegen/status.h \
+include/grpc++/impl/codegen/status_code_enum.h \
+include/grpc++/impl/codegen/string_ref.h \
+include/grpc++/impl/codegen/stub_options.h \
+include/grpc++/impl/codegen/sync.h \
+include/grpc++/impl/codegen/sync_cxx11.h \
+include/grpc++/impl/codegen/sync_no_cxx11.h \
+include/grpc++/impl/codegen/sync_stream.h \
+include/grpc++/impl/codegen/time.h \
 include/grpc++/impl/grpc_library.h \
 include/grpc++/impl/method_handler_impl.h \
 include/grpc++/impl/proto_utils.h \
@@ -803,37 +834,7 @@
 include/grpc++/support/string_ref.h \
 include/grpc++/support/stub_options.h \
 include/grpc++/support/sync_stream.h \
-include/grpc++/support/time.h \
-include/grpc++/impl/codegen/async_stream.h \
-include/grpc++/impl/codegen/async_unary_call.h \
-include/grpc++/impl/codegen/call.h \
-include/grpc++/impl/codegen/call_hook.h \
-include/grpc++/impl/codegen/channel_interface.h \
-include/grpc++/impl/codegen/client_context.h \
-include/grpc++/impl/codegen/client_unary_call.h \
-include/grpc++/impl/codegen/completion_queue.h \
-include/grpc++/impl/codegen/completion_queue_tag.h \
-include/grpc++/impl/codegen/config.h \
-include/grpc++/impl/codegen/config_protobuf.h \
-include/grpc++/impl/codegen/grpc_library.h \
-include/grpc++/impl/codegen/method_handler_impl.h \
-include/grpc++/impl/codegen/proto_utils.h \
-include/grpc++/impl/codegen/rpc_method.h \
-include/grpc++/impl/codegen/rpc_service_method.h \
-include/grpc++/impl/codegen/security/auth_context.h \
-include/grpc++/impl/codegen/serialization_traits.h \
-include/grpc++/impl/codegen/server_context.h \
-include/grpc++/impl/codegen/server_interface.h \
-include/grpc++/impl/codegen/service_type.h \
-include/grpc++/impl/codegen/status.h \
-include/grpc++/impl/codegen/status_code_enum.h \
-include/grpc++/impl/codegen/string_ref.h \
-include/grpc++/impl/codegen/stub_options.h \
-include/grpc++/impl/codegen/sync.h \
-include/grpc++/impl/codegen/sync_cxx11.h \
-include/grpc++/impl/codegen/sync_no_cxx11.h \
-include/grpc++/impl/codegen/sync_stream.h \
-include/grpc++/impl/codegen/time.h
+include/grpc++/support/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 9533fbc..30bf7bf 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.13.1-pre1
+PROJECT_NUMBER         = 0.14.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -770,6 +770,37 @@
 include/grpc++/grpc++.h \
 include/grpc++/impl/call.h \
 include/grpc++/impl/client_unary_call.h \
+include/grpc++/impl/codegen/async_stream.h \
+include/grpc++/impl/codegen/async_unary_call.h \
+include/grpc++/impl/codegen/call.h \
+include/grpc++/impl/codegen/call_hook.h \
+include/grpc++/impl/codegen/channel_interface.h \
+include/grpc++/impl/codegen/client_context.h \
+include/grpc++/impl/codegen/client_unary_call.h \
+include/grpc++/impl/codegen/completion_queue.h \
+include/grpc++/impl/codegen/completion_queue_tag.h \
+include/grpc++/impl/codegen/config.h \
+include/grpc++/impl/codegen/config_protobuf.h \
+include/grpc++/impl/codegen/core_codegen_interface.h \
+include/grpc++/impl/codegen/grpc_library.h \
+include/grpc++/impl/codegen/method_handler_impl.h \
+include/grpc++/impl/codegen/proto_utils.h \
+include/grpc++/impl/codegen/rpc_method.h \
+include/grpc++/impl/codegen/rpc_service_method.h \
+include/grpc++/impl/codegen/security/auth_context.h \
+include/grpc++/impl/codegen/serialization_traits.h \
+include/grpc++/impl/codegen/server_context.h \
+include/grpc++/impl/codegen/server_interface.h \
+include/grpc++/impl/codegen/service_type.h \
+include/grpc++/impl/codegen/status.h \
+include/grpc++/impl/codegen/status_code_enum.h \
+include/grpc++/impl/codegen/string_ref.h \
+include/grpc++/impl/codegen/stub_options.h \
+include/grpc++/impl/codegen/sync.h \
+include/grpc++/impl/codegen/sync_cxx11.h \
+include/grpc++/impl/codegen/sync_no_cxx11.h \
+include/grpc++/impl/codegen/sync_stream.h \
+include/grpc++/impl/codegen/time.h \
 include/grpc++/impl/grpc_library.h \
 include/grpc++/impl/method_handler_impl.h \
 include/grpc++/impl/proto_utils.h \
@@ -804,49 +835,14 @@
 include/grpc++/support/stub_options.h \
 include/grpc++/support/sync_stream.h \
 include/grpc++/support/time.h \
-include/grpc++/impl/codegen/async_stream.h \
-include/grpc++/impl/codegen/async_unary_call.h \
-include/grpc++/impl/codegen/call.h \
-include/grpc++/impl/codegen/call_hook.h \
-include/grpc++/impl/codegen/channel_interface.h \
-include/grpc++/impl/codegen/client_context.h \
-include/grpc++/impl/codegen/client_unary_call.h \
-include/grpc++/impl/codegen/completion_queue.h \
-include/grpc++/impl/codegen/completion_queue_tag.h \
-include/grpc++/impl/codegen/config.h \
-include/grpc++/impl/codegen/config_protobuf.h \
-include/grpc++/impl/codegen/grpc_library.h \
-include/grpc++/impl/codegen/method_handler_impl.h \
-include/grpc++/impl/codegen/proto_utils.h \
-include/grpc++/impl/codegen/rpc_method.h \
-include/grpc++/impl/codegen/rpc_service_method.h \
-include/grpc++/impl/codegen/security/auth_context.h \
-include/grpc++/impl/codegen/serialization_traits.h \
-include/grpc++/impl/codegen/server_context.h \
-include/grpc++/impl/codegen/server_interface.h \
-include/grpc++/impl/codegen/service_type.h \
-include/grpc++/impl/codegen/status.h \
-include/grpc++/impl/codegen/status_code_enum.h \
-include/grpc++/impl/codegen/string_ref.h \
-include/grpc++/impl/codegen/stub_options.h \
-include/grpc++/impl/codegen/sync.h \
-include/grpc++/impl/codegen/sync_cxx11.h \
-include/grpc++/impl/codegen/sync_no_cxx11.h \
-include/grpc++/impl/codegen/sync_stream.h \
-include/grpc++/impl/codegen/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/create_channel_internal.h \
+src/cpp/client/secure_credentials.h \
+src/cpp/common/core_codegen.h \
 src/cpp/common/create_auth_context.h \
+src/cpp/common/secure_auth_context.h \
 src/cpp/server/dynamic_thread_pool.h \
+src/cpp/server/secure_server_credentials.h \
 src/cpp/server/thread_pool_interface.h \
-src/cpp/client/secure_credentials.cc \
-src/cpp/common/auth_property_iterator.cc \
-src/cpp/common/secure_auth_context.cc \
-src/cpp/common/secure_channel_arguments.cc \
-src/cpp/common/secure_create_auth_context.cc \
-src/cpp/server/secure_server_credentials.cc \
 src/cpp/client/channel.cc \
 src/cpp/client/client_context.cc \
 src/cpp/client/create_channel.cc \
@@ -854,15 +850,21 @@
 src/cpp/client/credentials.cc \
 src/cpp/client/generic_stub.cc \
 src/cpp/client/insecure_credentials.cc \
-src/cpp/common/call.cc \
+src/cpp/client/secure_credentials.cc \
+src/cpp/codegen/codegen_init.cc \
+src/cpp/common/auth_property_iterator.cc \
 src/cpp/common/channel_arguments.cc \
 src/cpp/common/completion_queue.cc \
+src/cpp/common/core_codegen.cc \
 src/cpp/common/rpc_method.cc \
-src/cpp/proto/proto_utils.cc \
+src/cpp/common/secure_auth_context.cc \
+src/cpp/common/secure_channel_arguments.cc \
+src/cpp/common/secure_create_auth_context.cc \
 src/cpp/server/async_generic_service.cc \
 src/cpp/server/create_default_thread_pool.cc \
 src/cpp/server/dynamic_thread_pool.cc \
 src/cpp/server/insecure_server_credentials.cc \
+src/cpp/server/secure_server_credentials.cc \
 src/cpp/server/server.cc \
 src/cpp/server/server_builder.cc \
 src/cpp/server/server_context.cc \
@@ -871,8 +873,7 @@
 src/cpp/util/slice.cc \
 src/cpp/util/status.cc \
 src/cpp/util/string_ref.cc \
-src/cpp/util/time.cc \
-src/cpp/codegen/grpc_library.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 89f93b9..55f4ffe 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.13.1-pre1
+PROJECT_NUMBER         = 0.14.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -760,19 +760,33 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc/grpc_security.h \
+INPUT                  = 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/impl/codegen/byte_buffer.h \
 include/grpc/impl/codegen/compression_types.h \
 include/grpc/impl/codegen/connectivity_state.h \
 include/grpc/impl/codegen/grpc_types.h \
 include/grpc/impl/codegen/propagation_bits.h \
 include/grpc/impl/codegen/status.h \
-include/grpc/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/impl/codegen/alloc.h \
+include/grpc/impl/codegen/atm.h \
+include/grpc/impl/codegen/atm_gcc_atomic.h \
+include/grpc/impl/codegen/atm_gcc_sync.h \
+include/grpc/impl/codegen/atm_win32.h \
+include/grpc/impl/codegen/log.h \
+include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/slice_buffer.h \
+include/grpc/impl/codegen/sync.h \
+include/grpc/impl/codegen/sync_generic.h \
+include/grpc/impl/codegen/sync_posix.h \
+include/grpc/impl/codegen/sync_win32.h \
+include/grpc/impl/codegen/time.h \
 include/grpc/support/alloc.h \
 include/grpc/support/atm.h \
 include/grpc/support/atm_gcc_atomic.h \
@@ -800,21 +814,7 @@
 include/grpc/support/tls_gcc.h \
 include/grpc/support/tls_msvc.h \
 include/grpc/support/tls_pthread.h \
-include/grpc/support/useful.h \
-include/grpc/impl/codegen/alloc.h \
-include/grpc/impl/codegen/atm.h \
-include/grpc/impl/codegen/atm_gcc_atomic.h \
-include/grpc/impl/codegen/atm_gcc_sync.h \
-include/grpc/impl/codegen/atm_win32.h \
-include/grpc/impl/codegen/log.h \
-include/grpc/impl/codegen/port_platform.h \
-include/grpc/impl/codegen/slice.h \
-include/grpc/impl/codegen/slice_buffer.h \
-include/grpc/impl/codegen/sync.h \
-include/grpc/impl/codegen/sync_generic.h \
-include/grpc/impl/codegen/sync_posix.h \
-include/grpc/impl/codegen/sync_win32.h \
-include/grpc/impl/codegen/time.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 c94ae87..bb7177f 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.13.1-pre1
+PROJECT_NUMBER         = 0.14.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -760,315 +760,338 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc/grpc_security.h \
+INPUT                  = 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/impl/codegen/byte_buffer.h \
 include/grpc/impl/codegen/compression_types.h \
 include/grpc/impl/codegen/connectivity_state.h \
 include/grpc/impl/codegen/grpc_types.h \
 include/grpc/impl/codegen/propagation_bits.h \
 include/grpc/impl/codegen/status.h \
-include/grpc/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/census/grpc_filter.h \
-src/core/channel/channel_args.h \
-src/core/channel/channel_stack.h \
-src/core/channel/client_channel.h \
-src/core/channel/client_uchannel.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/subchannel_call_holder.h \
-src/core/client_config/client_config.h \
-src/core/client_config/connector.h \
-src/core/client_config/initial_connect_string.h \
-src/core/client_config/lb_policies/load_balancer_api.h \
-src/core/client_config/lb_policies/pick_first.h \
-src/core/client_config/lb_policies/round_robin.h \
-src/core/client_config/lb_policy.h \
-src/core/client_config/lb_policy_factory.h \
-src/core/client_config/lb_policy_registry.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/sockaddr_resolver.h \
-src/core/client_config/subchannel.h \
-src/core/client_config/subchannel_factory.h \
-src/core/client_config/subchannel_index.h \
-src/core/client_config/uri_parser.h \
-src/core/compression/algorithm_metadata.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/parser.h \
-src/core/iomgr/closure.h \
-src/core/iomgr/endpoint.h \
-src/core/iomgr/endpoint_pair.h \
-src/core/iomgr/exec_ctx.h \
-src/core/iomgr/executor.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_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/timer.h \
-src/core/iomgr/timer_heap.h \
-src/core/iomgr/udp_server.h \
-src/core/iomgr/wakeup_fd_pipe.h \
-src/core/iomgr/wakeup_fd_posix.h \
-src/core/iomgr/workqueue.h \
-src/core/iomgr/workqueue_posix.h \
-src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.h \
-src/core/statistics/census_interface.h \
-src/core/statistics/census_rpc_stats.h \
-src/core/surface/api_trace.h \
-src/core/surface/call.h \
-src/core/surface/call_test_only.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/byte_stream.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_encoder.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_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/metadata_batch.h \
-src/core/transport/static_metadata.h \
-src/core/transport/transport.h \
-src/core/transport/transport_impl.h \
-src/core/security/auth_filters.h \
-src/core/security/b64.h \
-src/core/security/credentials.h \
-src/core/security/handshake.h \
-src/core/security/json_token.h \
-src/core/security/jwt_verifier.h \
-src/core/security/secure_endpoint.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/ssl_types.h \
-src/core/tsi/transport_security.h \
-src/core/tsi/transport_security_interface.h \
-src/core/census/aggregation.h \
-src/core/census/mlog.h \
-src/core/census/rpc_metric_id.h \
+src/core/ext/transport/chttp2/transport/alpn.h \
+src/core/ext/transport/chttp2/transport/bin_encoder.h \
+src/core/ext/transport/chttp2/transport/chttp2_transport.h \
+src/core/ext/transport/chttp2/transport/frame.h \
+src/core/ext/transport/chttp2/transport/frame_data.h \
+src/core/ext/transport/chttp2/transport/frame_goaway.h \
+src/core/ext/transport/chttp2/transport/frame_ping.h \
+src/core/ext/transport/chttp2/transport/frame_rst_stream.h \
+src/core/ext/transport/chttp2/transport/frame_settings.h \
+src/core/ext/transport/chttp2/transport/frame_window_update.h \
+src/core/ext/transport/chttp2/transport/hpack_encoder.h \
+src/core/ext/transport/chttp2/transport/hpack_parser.h \
+src/core/ext/transport/chttp2/transport/hpack_table.h \
+src/core/ext/transport/chttp2/transport/http2_errors.h \
+src/core/ext/transport/chttp2/transport/huffsyms.h \
+src/core/ext/transport/chttp2/transport/incoming_metadata.h \
+src/core/ext/transport/chttp2/transport/internal.h \
+src/core/ext/transport/chttp2/transport/status_conversion.h \
+src/core/ext/transport/chttp2/transport/stream_map.h \
+src/core/ext/transport/chttp2/transport/timeout_encoding.h \
+src/core/ext/transport/chttp2/transport/varint.h \
+src/core/lib/census/aggregation.h \
+src/core/lib/census/grpc_filter.h \
+src/core/lib/census/grpc_plugin.h \
+src/core/lib/census/mlog.h \
+src/core/lib/census/rpc_metric_id.h \
+src/core/lib/channel/channel_args.h \
+src/core/lib/channel/channel_stack.h \
+src/core/lib/channel/channel_stack_builder.h \
+src/core/lib/channel/client_channel.h \
+src/core/lib/channel/compress_filter.h \
+src/core/lib/channel/connected_channel.h \
+src/core/lib/channel/context.h \
+src/core/lib/channel/http_client_filter.h \
+src/core/lib/channel/http_server_filter.h \
+src/core/lib/channel/subchannel_call_holder.h \
+src/core/lib/client_config/client_config.h \
+src/core/lib/client_config/connector.h \
+src/core/lib/client_config/initial_connect_string.h \
+src/core/lib/client_config/lb_policies/load_balancer_api.h \
+src/core/lib/client_config/lb_policies/pick_first.h \
+src/core/lib/client_config/lb_policies/round_robin.h \
+src/core/lib/client_config/lb_policy.h \
+src/core/lib/client_config/lb_policy_factory.h \
+src/core/lib/client_config/lb_policy_registry.h \
+src/core/lib/client_config/resolver.h \
+src/core/lib/client_config/resolver_factory.h \
+src/core/lib/client_config/resolver_registry.h \
+src/core/lib/client_config/resolvers/dns_resolver.h \
+src/core/lib/client_config/resolvers/sockaddr_resolver.h \
+src/core/lib/client_config/subchannel.h \
+src/core/lib/client_config/subchannel_factory.h \
+src/core/lib/client_config/subchannel_index.h \
+src/core/lib/client_config/uri_parser.h \
+src/core/lib/compression/algorithm_metadata.h \
+src/core/lib/compression/message_compress.h \
+src/core/lib/debug/trace.h \
+src/core/lib/http/format_request.h \
+src/core/lib/http/httpcli.h \
+src/core/lib/http/parser.h \
+src/core/lib/iomgr/closure.h \
+src/core/lib/iomgr/endpoint.h \
+src/core/lib/iomgr/endpoint_pair.h \
+src/core/lib/iomgr/exec_ctx.h \
+src/core/lib/iomgr/executor.h \
+src/core/lib/iomgr/fd_posix.h \
+src/core/lib/iomgr/iocp_windows.h \
+src/core/lib/iomgr/iomgr.h \
+src/core/lib/iomgr/iomgr_internal.h \
+src/core/lib/iomgr/iomgr_posix.h \
+src/core/lib/iomgr/pollset.h \
+src/core/lib/iomgr/pollset_posix.h \
+src/core/lib/iomgr/pollset_set.h \
+src/core/lib/iomgr/pollset_set_posix.h \
+src/core/lib/iomgr/pollset_set_windows.h \
+src/core/lib/iomgr/pollset_windows.h \
+src/core/lib/iomgr/resolve_address.h \
+src/core/lib/iomgr/sockaddr.h \
+src/core/lib/iomgr/sockaddr_posix.h \
+src/core/lib/iomgr/sockaddr_utils.h \
+src/core/lib/iomgr/sockaddr_win32.h \
+src/core/lib/iomgr/socket_utils_posix.h \
+src/core/lib/iomgr/socket_windows.h \
+src/core/lib/iomgr/tcp_client.h \
+src/core/lib/iomgr/tcp_posix.h \
+src/core/lib/iomgr/tcp_server.h \
+src/core/lib/iomgr/tcp_windows.h \
+src/core/lib/iomgr/time_averaged_stats.h \
+src/core/lib/iomgr/timer.h \
+src/core/lib/iomgr/timer_heap.h \
+src/core/lib/iomgr/udp_server.h \
+src/core/lib/iomgr/unix_sockets_posix.h \
+src/core/lib/iomgr/wakeup_fd_pipe.h \
+src/core/lib/iomgr/wakeup_fd_posix.h \
+src/core/lib/iomgr/workqueue.h \
+src/core/lib/iomgr/workqueue_posix.h \
+src/core/lib/iomgr/workqueue_windows.h \
+src/core/lib/json/json.h \
+src/core/lib/json/json_common.h \
+src/core/lib/json/json_reader.h \
+src/core/lib/json/json_writer.h \
+src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h \
+src/core/lib/security/auth_filters.h \
+src/core/lib/security/b64.h \
+src/core/lib/security/credentials.h \
+src/core/lib/security/handshake.h \
+src/core/lib/security/json_token.h \
+src/core/lib/security/jwt_verifier.h \
+src/core/lib/security/secure_endpoint.h \
+src/core/lib/security/security_connector.h \
+src/core/lib/security/security_context.h \
+src/core/lib/statistics/census_interface.h \
+src/core/lib/statistics/census_rpc_stats.h \
+src/core/lib/surface/api_trace.h \
+src/core/lib/surface/call.h \
+src/core/lib/surface/call_test_only.h \
+src/core/lib/surface/channel.h \
+src/core/lib/surface/channel_init.h \
+src/core/lib/surface/channel_stack_type.h \
+src/core/lib/surface/completion_queue.h \
+src/core/lib/surface/event_string.h \
+src/core/lib/surface/init.h \
+src/core/lib/surface/lame_client.h \
+src/core/lib/surface/server.h \
+src/core/lib/surface/surface_trace.h \
+src/core/lib/transport/byte_stream.h \
+src/core/lib/transport/connectivity_state.h \
+src/core/lib/transport/metadata.h \
+src/core/lib/transport/metadata_batch.h \
+src/core/lib/transport/static_metadata.h \
+src/core/lib/transport/transport.h \
+src/core/lib/transport/transport_impl.h \
+src/core/lib/tsi/fake_transport_security.h \
+src/core/lib/tsi/ssl_transport_security.h \
+src/core/lib/tsi/ssl_types.h \
+src/core/lib/tsi/transport_security.h \
+src/core/lib/tsi/transport_security_interface.h \
 third_party/nanopb/pb.h \
 third_party/nanopb/pb_common.h \
 third_party/nanopb/pb_decode.h \
 third_party/nanopb/pb_encode.h \
-src/core/census/grpc_context.c \
-src/core/census/grpc_filter.c \
-src/core/channel/channel_args.c \
-src/core/channel/channel_stack.c \
-src/core/channel/client_channel.c \
-src/core/channel/client_uchannel.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/subchannel_call_holder.c \
-src/core/client_config/client_config.c \
-src/core/client_config/connector.c \
-src/core/client_config/default_initial_connect_string.c \
-src/core/client_config/initial_connect_string.c \
-src/core/client_config/lb_policies/load_balancer_api.c \
-src/core/client_config/lb_policies/pick_first.c \
-src/core/client_config/lb_policies/round_robin.c \
-src/core/client_config/lb_policy.c \
-src/core/client_config/lb_policy_factory.c \
-src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c \
-src/core/client_config/subchannel.c \
-src/core/client_config/subchannel_factory.c \
-src/core/client_config/subchannel_index.c \
-src/core/client_config/uri_parser.c \
-src/core/compression/compression_algorithm.c \
-src/core/compression/message_compress.c \
-src/core/debug/trace.c \
-src/core/httpcli/format_request.c \
-src/core/httpcli/httpcli.c \
-src/core/httpcli/parser.c \
-src/core/iomgr/closure.c \
-src/core/iomgr/endpoint.c \
-src/core/iomgr/endpoint_pair_posix.c \
-src/core/iomgr/endpoint_pair_windows.c \
-src/core/iomgr/exec_ctx.c \
-src/core/iomgr/executor.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_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/timer.c \
-src/core/iomgr/timer_heap.c \
-src/core/iomgr/udp_server.c \
-src/core/iomgr/wakeup_fd_eventfd.c \
-src/core/iomgr/wakeup_fd_nospecial.c \
-src/core/iomgr/wakeup_fd_pipe.c \
-src/core/iomgr/wakeup_fd_posix.c \
-src/core/iomgr/workqueue_posix.c \
-src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c \
-src/core/surface/alarm.c \
-src/core/surface/api_trace.c \
-src/core/surface/byte_buffer.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_connectivity.c \
-src/core/surface/channel_create.c \
-src/core/surface/channel_ping.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/validate_metadata.c \
-src/core/surface/version.c \
-src/core/transport/byte_stream.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_encoder.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_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/metadata_batch.c \
-src/core/transport/static_metadata.c \
-src/core/transport/transport.c \
-src/core/transport/transport_op_string.c \
-src/core/httpcli/httpcli_security_connector.c \
-src/core/security/b64.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/handshake.c \
-src/core/security/json_token.c \
-src/core/security/jwt_verifier.c \
-src/core/security/secure_endpoint.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/context.c \
-src/core/census/initialize.c \
-src/core/census/mlog.c \
-src/core/census/operation.c \
-src/core/census/placeholders.c \
-src/core/census/tracing.c \
+src/core/ext/transport/chttp2/client/insecure/channel_create.c \
+src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
+src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
+src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c \
+src/core/ext/transport/chttp2/transport/alpn.c \
+src/core/ext/transport/chttp2/transport/bin_encoder.c \
+src/core/ext/transport/chttp2/transport/chttp2_transport.c \
+src/core/ext/transport/chttp2/transport/frame_data.c \
+src/core/ext/transport/chttp2/transport/frame_goaway.c \
+src/core/ext/transport/chttp2/transport/frame_ping.c \
+src/core/ext/transport/chttp2/transport/frame_rst_stream.c \
+src/core/ext/transport/chttp2/transport/frame_settings.c \
+src/core/ext/transport/chttp2/transport/frame_window_update.c \
+src/core/ext/transport/chttp2/transport/hpack_encoder.c \
+src/core/ext/transport/chttp2/transport/hpack_parser.c \
+src/core/ext/transport/chttp2/transport/hpack_table.c \
+src/core/ext/transport/chttp2/transport/huffsyms.c \
+src/core/ext/transport/chttp2/transport/incoming_metadata.c \
+src/core/ext/transport/chttp2/transport/parsing.c \
+src/core/ext/transport/chttp2/transport/status_conversion.c \
+src/core/ext/transport/chttp2/transport/stream_lists.c \
+src/core/ext/transport/chttp2/transport/stream_map.c \
+src/core/ext/transport/chttp2/transport/timeout_encoding.c \
+src/core/ext/transport/chttp2/transport/varint.c \
+src/core/ext/transport/chttp2/transport/writing.c \
+src/core/lib/census/context.c \
+src/core/lib/census/grpc_context.c \
+src/core/lib/census/grpc_filter.c \
+src/core/lib/census/grpc_plugin.c \
+src/core/lib/census/initialize.c \
+src/core/lib/census/mlog.c \
+src/core/lib/census/operation.c \
+src/core/lib/census/placeholders.c \
+src/core/lib/census/tracing.c \
+src/core/lib/channel/channel_args.c \
+src/core/lib/channel/channel_stack.c \
+src/core/lib/channel/channel_stack_builder.c \
+src/core/lib/channel/client_channel.c \
+src/core/lib/channel/compress_filter.c \
+src/core/lib/channel/connected_channel.c \
+src/core/lib/channel/http_client_filter.c \
+src/core/lib/channel/http_server_filter.c \
+src/core/lib/channel/subchannel_call_holder.c \
+src/core/lib/client_config/client_config.c \
+src/core/lib/client_config/connector.c \
+src/core/lib/client_config/default_initial_connect_string.c \
+src/core/lib/client_config/initial_connect_string.c \
+src/core/lib/client_config/lb_policies/load_balancer_api.c \
+src/core/lib/client_config/lb_policies/pick_first.c \
+src/core/lib/client_config/lb_policies/round_robin.c \
+src/core/lib/client_config/lb_policy.c \
+src/core/lib/client_config/lb_policy_factory.c \
+src/core/lib/client_config/lb_policy_registry.c \
+src/core/lib/client_config/resolver.c \
+src/core/lib/client_config/resolver_factory.c \
+src/core/lib/client_config/resolver_registry.c \
+src/core/lib/client_config/resolvers/dns_resolver.c \
+src/core/lib/client_config/resolvers/sockaddr_resolver.c \
+src/core/lib/client_config/subchannel.c \
+src/core/lib/client_config/subchannel_factory.c \
+src/core/lib/client_config/subchannel_index.c \
+src/core/lib/client_config/uri_parser.c \
+src/core/lib/compression/compression_algorithm.c \
+src/core/lib/compression/message_compress.c \
+src/core/lib/debug/trace.c \
+src/core/lib/http/format_request.c \
+src/core/lib/http/httpcli.c \
+src/core/lib/http/httpcli_security_connector.c \
+src/core/lib/http/parser.c \
+src/core/lib/iomgr/closure.c \
+src/core/lib/iomgr/endpoint.c \
+src/core/lib/iomgr/endpoint_pair_posix.c \
+src/core/lib/iomgr/endpoint_pair_windows.c \
+src/core/lib/iomgr/exec_ctx.c \
+src/core/lib/iomgr/executor.c \
+src/core/lib/iomgr/fd_posix.c \
+src/core/lib/iomgr/iocp_windows.c \
+src/core/lib/iomgr/iomgr.c \
+src/core/lib/iomgr/iomgr_posix.c \
+src/core/lib/iomgr/iomgr_windows.c \
+src/core/lib/iomgr/pollset_multipoller_with_epoll.c \
+src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c \
+src/core/lib/iomgr/pollset_posix.c \
+src/core/lib/iomgr/pollset_set_posix.c \
+src/core/lib/iomgr/pollset_set_windows.c \
+src/core/lib/iomgr/pollset_windows.c \
+src/core/lib/iomgr/resolve_address_posix.c \
+src/core/lib/iomgr/resolve_address_windows.c \
+src/core/lib/iomgr/sockaddr_utils.c \
+src/core/lib/iomgr/socket_utils_common_posix.c \
+src/core/lib/iomgr/socket_utils_linux.c \
+src/core/lib/iomgr/socket_utils_posix.c \
+src/core/lib/iomgr/socket_windows.c \
+src/core/lib/iomgr/tcp_client_posix.c \
+src/core/lib/iomgr/tcp_client_windows.c \
+src/core/lib/iomgr/tcp_posix.c \
+src/core/lib/iomgr/tcp_server_posix.c \
+src/core/lib/iomgr/tcp_server_windows.c \
+src/core/lib/iomgr/tcp_windows.c \
+src/core/lib/iomgr/time_averaged_stats.c \
+src/core/lib/iomgr/timer.c \
+src/core/lib/iomgr/timer_heap.c \
+src/core/lib/iomgr/udp_server.c \
+src/core/lib/iomgr/unix_sockets_posix.c \
+src/core/lib/iomgr/unix_sockets_posix_noop.c \
+src/core/lib/iomgr/wakeup_fd_eventfd.c \
+src/core/lib/iomgr/wakeup_fd_nospecial.c \
+src/core/lib/iomgr/wakeup_fd_pipe.c \
+src/core/lib/iomgr/wakeup_fd_posix.c \
+src/core/lib/iomgr/workqueue_posix.c \
+src/core/lib/iomgr/workqueue_windows.c \
+src/core/lib/json/json.c \
+src/core/lib/json/json_reader.c \
+src/core/lib/json/json_string.c \
+src/core/lib/json/json_writer.c \
+src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c \
+src/core/lib/security/b64.c \
+src/core/lib/security/client_auth_filter.c \
+src/core/lib/security/credentials.c \
+src/core/lib/security/credentials_metadata.c \
+src/core/lib/security/credentials_posix.c \
+src/core/lib/security/credentials_win32.c \
+src/core/lib/security/google_default_credentials.c \
+src/core/lib/security/handshake.c \
+src/core/lib/security/json_token.c \
+src/core/lib/security/jwt_verifier.c \
+src/core/lib/security/secure_endpoint.c \
+src/core/lib/security/security_connector.c \
+src/core/lib/security/security_context.c \
+src/core/lib/security/server_auth_filter.c \
+src/core/lib/surface/alarm.c \
+src/core/lib/surface/api_trace.c \
+src/core/lib/surface/byte_buffer.c \
+src/core/lib/surface/byte_buffer_reader.c \
+src/core/lib/surface/call.c \
+src/core/lib/surface/call_details.c \
+src/core/lib/surface/call_log_batch.c \
+src/core/lib/surface/channel.c \
+src/core/lib/surface/channel_connectivity.c \
+src/core/lib/surface/channel_init.c \
+src/core/lib/surface/channel_ping.c \
+src/core/lib/surface/channel_stack_type.c \
+src/core/lib/surface/completion_queue.c \
+src/core/lib/surface/event_string.c \
+src/core/lib/surface/init.c \
+src/core/lib/surface/init_secure.c \
+src/core/lib/surface/lame_client.c \
+src/core/lib/surface/metadata_array.c \
+src/core/lib/surface/server.c \
+src/core/lib/surface/validate_metadata.c \
+src/core/lib/surface/version.c \
+src/core/lib/transport/byte_stream.c \
+src/core/lib/transport/connectivity_state.c \
+src/core/lib/transport/metadata.c \
+src/core/lib/transport/metadata_batch.c \
+src/core/lib/transport/static_metadata.c \
+src/core/lib/transport/transport.c \
+src/core/lib/transport/transport_op_string.c \
+src/core/lib/tsi/fake_transport_security.c \
+src/core/lib/tsi/ssl_transport_security.c \
+src/core/lib/tsi/transport_security.c \
 third_party/nanopb/pb_common.c \
 third_party/nanopb/pb_decode.c \
 third_party/nanopb/pb_encode.c \
+include/grpc/impl/codegen/alloc.h \
+include/grpc/impl/codegen/atm.h \
+include/grpc/impl/codegen/atm_gcc_atomic.h \
+include/grpc/impl/codegen/atm_gcc_sync.h \
+include/grpc/impl/codegen/atm_win32.h \
+include/grpc/impl/codegen/log.h \
+include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/slice_buffer.h \
+include/grpc/impl/codegen/sync.h \
+include/grpc/impl/codegen/sync_generic.h \
+include/grpc/impl/codegen/sync_posix.h \
+include/grpc/impl/codegen/sync_win32.h \
+include/grpc/impl/codegen/time.h \
 include/grpc/support/alloc.h \
 include/grpc/support/atm.h \
 include/grpc/support/atm_gcc_atomic.h \
@@ -1097,74 +1120,62 @@
 include/grpc/support/tls_msvc.h \
 include/grpc/support/tls_pthread.h \
 include/grpc/support/useful.h \
-include/grpc/impl/codegen/alloc.h \
-include/grpc/impl/codegen/atm.h \
-include/grpc/impl/codegen/atm_gcc_atomic.h \
-include/grpc/impl/codegen/atm_gcc_sync.h \
-include/grpc/impl/codegen/atm_win32.h \
-include/grpc/impl/codegen/log.h \
-include/grpc/impl/codegen/port_platform.h \
-include/grpc/impl/codegen/slice.h \
-include/grpc/impl/codegen/slice_buffer.h \
-include/grpc/impl/codegen/sync.h \
-include/grpc/impl/codegen/sync_generic.h \
-include/grpc/impl/codegen/sync_posix.h \
-include/grpc/impl/codegen/sync_win32.h \
-include/grpc/impl/codegen/time.h \
-src/core/profiling/timers.h \
-src/core/support/block_annotate.h \
-src/core/support/env.h \
-src/core/support/load_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/time_precise.h \
-src/core/support/tmpfile.h \
-src/core/profiling/basic_timers.c \
-src/core/profiling/stap_timers.c \
-src/core/support/alloc.c \
-src/core/support/avl.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/histogram.c \
-src/core/support/host_port.c \
-src/core/support/load_file.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/subprocess_windows.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_precise.c \
-src/core/support/time_win32.c \
-src/core/support/tls_pthread.c \
-src/core/support/tmpfile_posix.c \
-src/core/support/tmpfile_win32.c \
-src/core/support/wrap_memcpy.c
+src/core/lib/profiling/timers.h \
+src/core/lib/support/backoff.h \
+src/core/lib/support/block_annotate.h \
+src/core/lib/support/env.h \
+src/core/lib/support/load_file.h \
+src/core/lib/support/murmur_hash.h \
+src/core/lib/support/stack_lockfree.h \
+src/core/lib/support/string.h \
+src/core/lib/support/string_win32.h \
+src/core/lib/support/thd_internal.h \
+src/core/lib/support/time_precise.h \
+src/core/lib/support/tmpfile.h \
+src/core/lib/profiling/basic_timers.c \
+src/core/lib/profiling/stap_timers.c \
+src/core/lib/support/alloc.c \
+src/core/lib/support/avl.c \
+src/core/lib/support/backoff.c \
+src/core/lib/support/cmdline.c \
+src/core/lib/support/cpu_iphone.c \
+src/core/lib/support/cpu_linux.c \
+src/core/lib/support/cpu_posix.c \
+src/core/lib/support/cpu_windows.c \
+src/core/lib/support/env_linux.c \
+src/core/lib/support/env_posix.c \
+src/core/lib/support/env_win32.c \
+src/core/lib/support/histogram.c \
+src/core/lib/support/host_port.c \
+src/core/lib/support/load_file.c \
+src/core/lib/support/log.c \
+src/core/lib/support/log_android.c \
+src/core/lib/support/log_linux.c \
+src/core/lib/support/log_posix.c \
+src/core/lib/support/log_win32.c \
+src/core/lib/support/murmur_hash.c \
+src/core/lib/support/slice.c \
+src/core/lib/support/slice_buffer.c \
+src/core/lib/support/stack_lockfree.c \
+src/core/lib/support/string.c \
+src/core/lib/support/string_posix.c \
+src/core/lib/support/string_win32.c \
+src/core/lib/support/subprocess_posix.c \
+src/core/lib/support/subprocess_windows.c \
+src/core/lib/support/sync.c \
+src/core/lib/support/sync_posix.c \
+src/core/lib/support/sync_win32.c \
+src/core/lib/support/thd.c \
+src/core/lib/support/thd_posix.c \
+src/core/lib/support/thd_win32.c \
+src/core/lib/support/time.c \
+src/core/lib/support/time_posix.c \
+src/core/lib/support/time_precise.c \
+src/core/lib/support/time_win32.c \
+src/core/lib/support/tls_pthread.c \
+src/core/lib/support/tmpfile_posix.c \
+src/core/lib/support/tmpfile_win32.c \
+src/core/lib/support/wrap_memcpy.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/fuzzer/build_and_run_fuzzer.sh b/tools/fuzzer/build_and_run_fuzzer.sh
new file mode 100755
index 0000000..bbe6888
--- /dev/null
+++ b/tools/fuzzer/build_and_run_fuzzer.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+set -ex
+
+cd $(dirname $0)/../..
+make CONFIG=$config $1 -j3
+mkdir -p fuzzer_output
+. tools/fuzzer/runners/$1.sh
diff --git a/tools/fuzzer/runners/hpack_parser_fuzzer_test.sh b/tools/fuzzer/runners/hpack_parser_fuzzer_test.sh
new file mode 100644
index 0000000..a91cf6d
--- /dev/null
+++ b/tools/fuzzer/runners/hpack_parser_fuzzer_test.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+flags="-max_total_time=3600 -jobs=3 -workers=3"
+if [ "$config" == "asan-trace-cmp" ]
+then
+  flags="-use_traces=1 $flags"
+fi
+
+bins/$config/hpack_parser_fuzzer_test $flags fuzzer_output test/core/transport/chttp2/hpack_parser_corpus
diff --git a/tools/fuzzer/runners/http_fuzzer_test.sh b/tools/fuzzer/runners/http_fuzzer_test.sh
new file mode 100644
index 0000000..47adad0
--- /dev/null
+++ b/tools/fuzzer/runners/http_fuzzer_test.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+flags="-max_total_time=3600 -jobs=3 -workers=3"
+if [ "$config" == "asan-trace-cmp" ]
+then
+  flags="-use_traces=1 $flags"
+fi
+
+bins/$config/http_fuzzer_test $flags fuzzer_output test/core/http/corpus
diff --git a/tools/fuzzer/runners/json_fuzzer_test.sh b/tools/fuzzer/runners/json_fuzzer_test.sh
new file mode 100644
index 0000000..9c5cba3
--- /dev/null
+++ b/tools/fuzzer/runners/json_fuzzer_test.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+flags="-max_total_time=3600 -jobs=3 -workers=3"
+if [ "$config" == "asan-trace-cmp" ]
+then
+  flags="-use_traces=1 $flags"
+fi
+
+bins/$config/json_fuzzer_test $flags fuzzer_output test/core/json/corpus
diff --git a/tools/fuzzer/runners/uri_fuzzer_test.sh b/tools/fuzzer/runners/uri_fuzzer_test.sh
new file mode 100644
index 0000000..58f20d0
--- /dev/null
+++ b/tools/fuzzer/runners/uri_fuzzer_test.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+flags="-max_total_time=3600 -jobs=3 -workers=3"
+if [ "$config" == "asan-trace-cmp" ]
+then
+  flags="-use_traces=1 $flags"
+fi
+
+bins/$config/uri_fuzzer_test $flags fuzzer_output test/core/client_config/uri_corpus
diff --git a/tools/gce/create_interop_worker.sh b/tools/gce/create_interop_worker.sh
new file mode 100755
index 0000000..3c49c61
--- /dev/null
+++ b/tools/gce/create_interop_worker.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+# Copyright 2015-2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Creates an interop worker on GCE.
+# IMPORTANT: After this script finishes, there are still some manual
+# steps needed there are hard to automatize.
+# See go/grpc-jenkins-setup for followup instructions.
+
+set -ex
+
+cd $(dirname $0)
+
+CLOUD_PROJECT=grpc-testing
+ZONE=us-east1-a  # canary gateway is reachable from this zone
+
+INSTANCE_NAME="${1:-grpc-canary-interop2}"
+
+gcloud compute instances create $INSTANCE_NAME \
+    --project="$CLOUD_PROJECT" \
+    --zone "$ZONE" \
+    --machine-type n1-standard-16 \
+    --image ubuntu-15-10 \
+    --boot-disk-size 1000 \
+    --scopes https://www.googleapis.com/auth/xapi.zoo
+
+echo 'Created GCE instance, waiting 60 seconds for it to come online.'
+sleep 60
+
+gcloud compute copy-files \
+    --project="$CLOUD_PROJECT" \
+    --zone "$ZONE" \
+    jenkins_master.pub linux_worker_init.sh ${INSTANCE_NAME}:~
+
+gcloud compute ssh \
+    --project="$CLOUD_PROJECT" \
+    --zone "$ZONE" \
+    $INSTANCE_NAME --command "./linux_worker_init.sh"
diff --git a/tools/gce/create_linux_performance_worker.sh b/tools/gce/create_linux_performance_worker.sh
new file mode 100755
index 0000000..720fc80
--- /dev/null
+++ b/tools/gce/create_linux_performance_worker.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+# Copyright 2015-2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Creates a performance worker on GCE.
+
+set -ex
+
+cd $(dirname $0)
+
+CLOUD_PROJECT=grpc-testing
+ZONE=us-central1-b  # this zone allows 32core machines
+
+INSTANCE_NAME="${1:-grpc-performance-driver}"
+MACHINE_TYPE=n1-standard-32
+
+gcloud compute instances create $INSTANCE_NAME \
+    --project="$CLOUD_PROJECT" \
+    --zone "$ZONE" \
+    --machine-type $MACHINE_TYPE \
+    --image ubuntu-15-10 \
+    --boot-disk-size 300
+
+echo 'Created GCE instance, waiting 60 seconds for it to come online.'
+sleep 60
+
+gcloud compute copy-files \
+    --project="$CLOUD_PROJECT" \
+    --zone "$ZONE" \
+    jenkins_master.pub linux_performance_worker_init.sh ${INSTANCE_NAME}:~
+
+gcloud compute ssh \
+    --project="$CLOUD_PROJECT" \
+    --zone "$ZONE" \
+    $INSTANCE_NAME --command "./linux_performance_worker_init.sh"
diff --git a/tools/gce/create_linux_worker.sh b/tools/gce/create_linux_worker.sh
index 2a9e77a..399e3ec 100755
--- a/tools/gce/create_linux_worker.sh
+++ b/tools/gce/create_linux_worker.sh
@@ -37,7 +37,7 @@
 CLOUD_PROJECT=grpc-testing
 ZONE=us-central1-a
 
-INSTANCE_NAME=grpc-jenkins-worker1
+INSTANCE_NAME="${1:-grpc-jenkins-worker1}"
 
 gcloud compute instances create $INSTANCE_NAME \
     --project="$CLOUD_PROJECT" \
diff --git a/tools/gce/linux_performance_worker_init.sh b/tools/gce/linux_performance_worker_init.sh
new file mode 100755
index 0000000..bae2b51
--- /dev/null
+++ b/tools/gce/linux_performance_worker_init.sh
@@ -0,0 +1,106 @@
+#!/bin/bash
+# Copyright 2015-2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Initializes a fresh GCE VM to become a jenkins linux performance worker.
+# You shouldn't run this script on your own,
+# use create_linux_performance_worker.sh instead.
+
+set -ex
+
+sudo apt-get update
+
+# Install JRE
+sudo apt-get install -y openjdk-7-jre
+sudo apt-get install -y unzip lsof
+
+# Setup jenkins user (or the user will already exist bcuz magic)
+sudo adduser jenkins --disabled-password || true
+
+# Add pubkey of jenkins@grpc-jenkins-master to authorized keys of jenkins@
+# This needs to happen as the last step to prevent Jenkins master from connecting
+# to a machine that hasn't been properly setup yet.
+cat jenkins_master.pub | sudo tee --append ~jenkins/.ssh/authorized_keys
+
+sudo apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  strace \
+  pypy \
+  python-dev \
+  python-pip \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip
+
+# perftools
+sudo apt-get install -y google-perftools libgoogle-perftools-dev
+
+# C++ dependencies
+sudo apt-get install -y libgflags-dev libgtest-dev libc++-dev clang
+
+# Python dependencies
+sudo pip install tabulate
+curl -O https://bootstrap.pypa.io/get-pip.py
+sudo pypy get-pip.py
+sudo pypy -m pip install tabulate
+
+# Node dependences.
+touch .profile
+curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+nvm install 0.12 && npm config set cache /tmp/npm-cache
+
+# C# dependencies (http://www.mono-project.com/docs/getting-started/install/linux/#debian-ubuntu-and-derivatives)
+
+sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
+sudo apt-get update
+sudo apt-get install -y mono-devel nuget
+
+# Ruby dependencies
+gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+curl -sSL https://get.rvm.io | bash -s stable --ruby
diff --git a/tools/gource/gource.sh b/tools/gource/gource.sh
new file mode 100755
index 0000000..167a256
--- /dev/null
+++ b/tools/gource/gource.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+gource -c 4 -s 0.1 --max-file-lag 0.05 --max-files 0 -e 0.01 --hide filenames,dirnames --file-filter 'doc/ref|vsprojects/vcxproj' $*
diff --git a/tools/http2_interop/http2interop_test.go b/tools/http2_interop/http2interop_test.go
index fb314da..305125f 100644
--- a/tools/http2_interop/http2interop_test.go
+++ b/tools/http2_interop/http2interop_test.go
@@ -49,7 +49,7 @@
 
 	if ctx.UseTestCa {
 		// It would be odd if useTestCa was true, but not useTls.  meh
-		certData, err := ioutil.ReadFile("src/core/tsi/test_creds/ca.pem")
+		certData, err := ioutil.ReadFile("src/core/lib/tsi/test_creds/ca.pem")
 		if err != nil {
 			t.Fatal(err)
 		}
diff --git a/tools/jenkins/build_interop_stress_image.sh b/tools/jenkins/build_interop_stress_image.sh
index 501dc5b..b5dbcc5 100755
--- a/tools/jenkins/build_interop_stress_image.sh
+++ b/tools/jenkins/build_interop_stress_image.sh
@@ -34,10 +34,12 @@
 set -x
 
 # Params:
-#  INTEROP_IMAGE - name of tag of the final interop image
+#  INTEROP_IMAGE - Name of tag of the final interop image
 #  INTEROP_IMAGE_TAG - Optional. If set, the created image will be tagged using
 #    the command: 'docker tag $INTEROP_IMAGE $INTEROP_IMAGE_REPOSITORY_TAG'
-#  BASE_NAME - base name used to locate the base Dockerfile and build script
+#  BASE_NAME - Base name used to locate the base Dockerfile and build script
+#  BUILD_TYPE - The 'CONFIG' variable passed to the 'make' command (example:
+#  asan, tsan. Default value: opt).
 #  TTY_FLAG - optional -t flag to make docker allocate tty
 #  BUILD_INTEROP_DOCKER_EXTRA_ARGS - optional args to be passed to the
 #    docker run command
@@ -71,6 +73,7 @@
 (docker run \
   -e CCACHE_DIR=/tmp/ccache \
   -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \
+  -e BUILD_TYPE=${BUILD_TYPE:=opt} \
   -i $TTY_FLAG \
   $MOUNT_ARGS \
   $BUILD_INTEROP_DOCKER_EXTRA_ARGS \
diff --git a/tools/jenkins/docker_run_tests.sh b/tools/jenkins/docker_run_tests.sh
index 8d6c42c..90a2bd8 100755
--- a/tools/jenkins/docker_run_tests.sh
+++ b/tools/jenkins/docker_run_tests.sh
@@ -34,7 +34,7 @@
 set -e
 
 export CONFIG=$config
-export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.5
+export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer
 
 # Ensure that programs depending on current-user-ownership of cache directories
 # are satisfied (it's being mounted from outside the image).
diff --git a/tools/jenkins/run_full_interop.sh b/tools/jenkins/run_full_interop.sh
new file mode 100755
index 0000000..a82da1c
--- /dev/null
+++ b/tools/jenkins/run_full_interop.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# This script is invoked by Jenkins and runs interop test suite.
+set -ex
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../..
+
+tools/run_tests/run_interop_tests.py -l all -s all --cloud_to_prod --cloud_to_prod_auth --prod_servers default cloud_gateway gateway_v2 cloud_gateway_v2 gateway_v4 cloud_gateway_v4 --use_docker --http2_interop -t -j 12 $@ || true
diff --git a/tools/jenkins/run_fuzzer.sh b/tools/jenkins/run_fuzzer.sh
new file mode 100755
index 0000000..3d6da99
--- /dev/null
+++ b/tools/jenkins/run_fuzzer.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Builds and runs a fuzzer (specified by the first command line argument)
+
+set -ex
+
+export RUN_COMMAND="tools/fuzzer/build_and_run_fuzzer.sh $1"
+export DOCKER_RUN_SCRIPT=tools/jenkins/docker_run.sh
+export DOCKERFILE_DIR=tools/dockerfile/test/fuzzer
+export OUTPUT_DIR=fuzzer_output
+
+tools/jenkins/build_and_run_docker.sh \
+  -e RUN_COMMAND="$RUN_COMMAND" \
+  -e OUTPUT_DIR="$OUTPUT_DIR" \
+  -e config="$config"
diff --git a/tools/openssl/use_openssl.sh b/tools/openssl/use_openssl.sh
index 3098217..9318b34 100755
--- a/tools/openssl/use_openssl.sh
+++ b/tools/openssl/use_openssl.sh
@@ -38,8 +38,8 @@
 # allow openssl to be pre-downloaded
 if [ ! -e third_party/openssl-1.0.2f.tar.gz ]
 then
-  echo "Downloading http://openssl.org/source/openssl-1.0.2f.tar.gz to third_party/openssl-1.0.2f.tar.gz"
-  wget http://openssl.org/source/openssl-1.0.2f.tar.gz -O third_party/openssl-1.0.2f.tar.gz
+  echo "Downloading https://openssl.org/source/old/1.0.2/openssl-1.0.2f.tar.gz to third_party/openssl-1.0.2f.tar.gz"
+  wget https://openssl.org/source/old/1.0.2/openssl-1.0.2f.tar.gz -O third_party/openssl-1.0.2f.tar.gz
 fi
 
 # clean openssl directory
diff --git a/tools/run_tests/build_python.sh b/tools/run_tests/build_python.sh
index 79a148f..fe84300 100755
--- a/tools/run_tests/build_python.sh
+++ b/tools/run_tests/build_python.sh
@@ -40,6 +40,7 @@
 export CFLAGS="-I$ROOT/include -std=gnu99"
 export LDFLAGS="-L$ROOT/libs/$CONFIG"
 export GRPC_PYTHON_BUILD_WITH_CYTHON=1
+export GRPC_PYTHON_USE_PRECOMPILED_BINARIES=0
 
 if [ "$CONFIG" = "gcov" ]
 then
diff --git a/tools/run_tests/configs.json b/tools/run_tests/configs.json
index cbb8ec5..325e9aa 100644
--- a/tools/run_tests/configs.json
+++ b/tools/run_tests/configs.json
@@ -3,6 +3,37 @@
     "config": "opt"
   }, 
   {
+    "config": "asan-trace-cmp", 
+    "environ": {
+      "ASAN_OPTIONS": "detect_leaks=1:color=always", 
+      "LSAN_OPTIONS": "suppressions=tools/lsan_suppressions.txt:report_objects=1"
+    }, 
+    "timeout_multiplier": 3
+  }, 
+  {
+    "config": "dbg"
+  }, 
+  {
+    "config": "easan", 
+    "environ": {
+      "ASAN_OPTIONS": "detect_leaks=1:color=always", 
+      "LSAN_OPTIONS": "suppressions=tools/lsan_suppressions.txt:report_objects=1"
+    }, 
+    "timeout_multiplier": 3
+  }, 
+  {
+    "config": "asan", 
+    "environ": {
+      "ASAN_OPTIONS": "detect_leaks=1:color=always", 
+      "LSAN_OPTIONS": "suppressions=tools/lsan_suppressions.txt:report_objects=1"
+    }, 
+    "timeout_multiplier": 3
+  }, 
+  {
+    "config": "msan", 
+    "timeout_multiplier": 4
+  }, 
+  {
     "config": "basicprof"
   }, 
   {
@@ -21,17 +52,24 @@
     "timeout_multiplier": 3
   }, 
   {
+    "config": "edbg"
+  }, 
+  {
     "config": "ubsan", 
     "timeout_multiplier": 1.5
   }, 
   {
-    "config": "dbg"
+    "config": "tsan", 
+    "environ": {
+      "TSAN_OPTIONS": "suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1"
+    }, 
+    "timeout_multiplier": 5
   }, 
   {
     "config": "stapprof"
   }, 
   {
-    "config": "gcov"
+    "config": "mutrace"
   }, 
   {
     "config": "memcheck", 
@@ -43,25 +81,13 @@
     ]
   }, 
   {
-    "config": "asan", 
-    "environ": {
-      "ASAN_OPTIONS": "detect_leaks=1:color=always", 
-      "LSAN_OPTIONS": "suppressions=tools/lsan_suppressions.txt:report_objects=1"
-    }, 
-    "timeout_multiplier": 3
-  }, 
-  {
-    "config": "tsan", 
+    "config": "etsan", 
     "environ": {
       "TSAN_OPTIONS": "suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1"
     }, 
     "timeout_multiplier": 5
   }, 
   {
-    "config": "msan", 
-    "timeout_multiplier": 4
-  }, 
-  {
-    "config": "mutrace"
+    "config": "gcov"
   }
 ]
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 1dc772a..86eb52b 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -589,7 +589,11 @@
     'cloud_gateway': ('216.239.32.255', 'grpc-test.sandbox.googleapis.com',
                       False),
     'cloud_gateway_v2': ('216.239.32.255', 'grpc-test2.sandbox.googleapis.com',
-                         True)
+                         True),
+    'gateway_v4': ('grpc-test4.sandbox.googleapis.com', 
+                   'grpc-test4.sandbox.googleapis.com', True), 
+    'cloud_gateway_v4': ('216.239.32.255', 'grpc-test4.sandbox.googleapis.com',
+                         True),
 }
 
 argp = argparse.ArgumentParser(description='Run interop tests.')
diff --git a/tools/run_tests/run_python.sh b/tools/run_tests/run_python.sh
index d4b7250..e3be14e 100755
--- a/tools/run_tests/run_python.sh
+++ b/tools/run_tests/run_python.sh
@@ -40,6 +40,7 @@
 export CFLAGS="-I$ROOT/include -std=c89"
 export LDFLAGS="-L$ROOT/libs/$CONFIG"
 export GRPC_PYTHON_BUILD_WITH_CYTHON=1
+export GRPC_PYTHON_USE_PRECOMPILED_BINARIES=0
 
 if [ "$CONFIG" = "gcov" ]
 then
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 2df82ad..71bb7b1 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -80,7 +80,7 @@
     self.timeout_multiplier = timeout_multiplier
 
   def job_spec(self, cmdline, hash_targets, timeout_seconds=5*60,
-               shortname=None, environ={}, cpu_cost=1.0):
+               shortname=None, environ={}, cpu_cost=1.0, flaky=False):
     """Construct a jobset.JobSpec for a test under this config
 
        Args:
@@ -102,7 +102,7 @@
                           timeout_seconds=(self.timeout_multiplier * timeout_seconds if timeout_seconds else None),
                           hash_targets=hash_targets
                               if self.allow_hashing else None,
-                          flake_retries=5 if args.allow_flakes else 0,
+                          flake_retries=5 if flaky or args.allow_flakes else 0,
                           timeout_retries=3 if args.allow_flakes else 0)
 
 
@@ -120,7 +120,12 @@
 
 def _check_compiler(compiler, supported_compilers):
   if compiler not in supported_compilers:
-    raise Exception('Compiler %s not supported.' % compiler)
+    raise Exception('Compiler %s not supported (on this platform).' % compiler)
+
+
+def _check_arch(arch, supported_archs):
+  if arch not in supported_archs:
+    raise Exception('Architecture %s not supported.' % arch)
 
 
 def _is_use_docker_child():
@@ -142,9 +147,8 @@
       self._make_options = [_windows_toolset_option(self.args.compiler),
                             _windows_arch_option(self.args.arch)]
     else:
-      self._make_options = []
-      self._docker_distro = self._get_docker_distro(self.args.use_docker,
-                                                    self.args.compiler)
+      self._docker_distro, self._make_options = self._compiler_options(self.args.use_docker,
+                                                                       self.args.compiler)
 
   def test_specs(self):
     out = []
@@ -184,14 +188,15 @@
                                               shortname='%s:%s' % (binary, test),
                                               cpu_cost=target['cpu_cost'],
                                               environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
-                                                       _ROOT + '/src/core/tsi/test_creds/ca.pem'}))
+                                                       _ROOT + '/src/core/lib/tsi/test_creds/ca.pem'}))
         else:
           cmdline = [binary] + target['args']
           out.append(self.config.job_spec(cmdline, [binary],
                                           shortname=' '.join(cmdline),
                                           cpu_cost=target['cpu_cost'],
+                                          flaky=target.get('flaky', False),
                                           environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
-                                                   _ROOT + '/src/core/tsi/test_creds/ca.pem'}))
+                                                   _ROOT + '/src/core/lib/tsi/test_creds/ca.pem'}))
       elif self.args.regex == '.*' or self.platform == 'windows':
         print '\nWARNING: binary not found, skipping', binary
     return sorted(out)
@@ -229,18 +234,29 @@
   def makefile_name(self):
     return 'Makefile'
 
-  def _get_docker_distro(self, use_docker, compiler):
+  def _clang_make_options(self):
+    return ['CC=clang', 'CXX=clang++', 'LD=clang', 'LDXX=clang++']
+
+  def _gcc44_make_options(self):
+    return ['CC=gcc-4.4', 'CXX=g++-4.4', 'LD=gcc-4.4', 'LDXX=g++-4.4']
+
+  def _compiler_options(self, use_docker, compiler):
+    """Returns docker distro and make options to use for given compiler."""
     if _is_use_docker_child():
-      return "already_under_docker"
+      return ("already_under_docker", [])
     if not use_docker:
       _check_compiler(compiler, ['default'])
 
     if compiler == 'gcc4.9' or compiler == 'default':
-      return 'jessie'
+      return ('jessie', [])
     elif compiler == 'gcc4.4':
-      return 'squeeze'
+      return ('wheezy', self._gcc44_make_options())
     elif compiler == 'gcc5.3':
-      return 'ubuntu1604'
+      return ('ubuntu1604', [])
+    elif compiler == 'clang3.4':
+      return ('ubuntu1404', self._clang_make_options())
+    elif compiler == 'clang3.6':
+      return ('ubuntu1604', self._clang_make_options())
     else:
       raise Exception('Compiler %s not supported.' % compiler)
 
@@ -453,7 +469,20 @@
   def configure(self, config, args):
     self.config = config
     self.args = args
-    _check_compiler(self.args.compiler, ['default'])
+    if self.platform == 'windows':
+      # Explicitly choosing between x86 and x64 arch doesn't work yet
+      _check_arch(self.args.arch, ['default'])
+      self._make_options = [_windows_toolset_option(self.args.compiler),
+                            _windows_arch_option(self.args.arch)]
+    else:
+      _check_compiler(self.args.compiler, ['default'])
+      if self.platform == 'mac':
+        # On Mac, official distribution of mono is 32bit.
+        # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
+        self._make_options = ['EMBED_OPENSSL=true',
+                              'CFLAGS=-m32', 'LDFLAGS=-m32']
+      else:
+        self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
 
   def test_specs(self):
     with open('src/csharp/tests.json') as f:
@@ -500,23 +529,16 @@
       return [['tools/run_tests/pre_build_csharp.sh']]
 
   def make_targets(self):
-    # For Windows, this target doesn't really build anything,
-    # everything is build by buildall script later.
-    if self.platform == 'windows':
-      return []
-    else:
-      return ['grpc_csharp_ext']
+    return ['grpc_csharp_ext']
 
   def make_options(self):
-    if self.platform == 'mac':
-      # On Mac, official distribution of mono is 32bit.
-      return ['CFLAGS=-arch i386', 'LDFLAGS=-arch i386']
-    else:
-      return []
+    return self._make_options;
 
   def build_steps(self):
     if self.platform == 'windows':
-      return [['src\\csharp\\buildall.bat']]
+      return [[_windows_build_bat(self.args.compiler),
+               'src/csharp/Grpc.sln',
+               '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
     else:
       return [['tools/run_tests/build_csharp.sh']]
 
@@ -774,6 +796,7 @@
 argp.add_argument('--compiler',
                   choices=['default',
                            'gcc4.4', 'gcc4.9', 'gcc5.3',
+                           'clang3.4', 'clang3.6',
                            'vs2010', 'vs2013', 'vs2015'],
                   default='default',
                   help='Selects compiler to use. Allowed values depend on the platform and language.')
@@ -861,9 +884,16 @@
 
   dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
   if len(dockerfile_dirs) > 1:
-    print 'Languages to be tested require running under different docker images.'
-    sys.exit(1)
-  dockerfile_dir = next(iter(dockerfile_dirs))
+    if 'gcov' in args.config:
+      dockerfile_dir = 'tools/dockerfile/test/multilang_jessie_x64'
+      print ('Using multilang_jessie_x64 docker image for code coverage for '
+             'all languages.')
+    else:
+      print ('Languages to be tested require running under different docker '
+             'images.')
+      sys.exit(1)
+  else:
+    dockerfile_dir = next(iter(dockerfile_dirs))
 
   child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
   run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
diff --git a/tools/run_tests/sanity/check_sources_and_headers.py b/tools/run_tests/sanity/check_sources_and_headers.py
index 44dc49b..b5f7912 100755
--- a/tools/run_tests/sanity/check_sources_and_headers.py
+++ b/tools/run_tests/sanity/check_sources_and_headers.py
@@ -55,7 +55,7 @@
   for dep in target['deps']:
     if target_has_header(get_target(dep), name):
       return True
-  if name == 'src/core/profiling/stap_probes.h':
+  if name == 'src/core/lib/profiling/stap_probes.h':
     return True
   return False
 
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index 3c6dbb9..630e7fb 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -41,7 +41,7 @@
 
 git submodule | awk '{ print $1 }' | sort > $submodules
 cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
+ 907ae62b9d81121cb86b604f83e6b811a43f7a87 third_party/boringssl (version_for_cocoapods_1.0-72-g907ae62)
  05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
  c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
  f8ac463766281625ad710900479130c7fcb4d63b third_party/nanopb (nanopb-0.3.4-29-gf8ac463)
diff --git a/tools/run_tests/sanity/sanity_tests.yaml b/tools/run_tests/sanity/sanity_tests.yaml
index 3840f4d..f155c8d 100644
--- a/tools/run_tests/sanity/sanity_tests.yaml
+++ b/tools/run_tests/sanity/sanity_tests.yaml
@@ -8,3 +8,4 @@
 - script: tools/distrib/clang_format_code.sh
 - script: tools/distrib/check_trailing_newlines.sh
 - script: tools/distrib/check_nanopb_output.sh
+- script: tools/distrib/check_include_guards.py
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index 0c7a6c7..d7c9839 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -198,6 +198,38 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "concurrent_connectivity_test", 
+    "src": [
+      "test/core/surface/concurrent_connectivity_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "dns_resolver_connectivity_test", 
+    "src": [
+      "test/core/client_config/resolvers/dns_resolver_connectivity_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
     "name": "dns_resolver_test", 
     "src": [
       "test/core/client_config/resolvers/dns_resolver_test.c"
@@ -379,6 +411,20 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "gpr_backoff_test", 
+    "src": [
+      "test/core/support/backoff_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
     "name": "gpr_cmdline_test", 
     "src": [
       "test/core/support/cmdline_test.c"
@@ -845,6 +891,22 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "hpack_parser_fuzzer_test", 
+    "src": [
+      "test/core/transport/chttp2/hpack_parser_fuzzer_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "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"
@@ -877,9 +939,9 @@
     ], 
     "headers": [], 
     "language": "c", 
-    "name": "httpcli_format_request_test", 
+    "name": "http_fuzzer_test", 
     "src": [
-      "test/core/httpcli/format_request_test.c"
+      "test/core/http/fuzzer.c"
     ], 
     "third_party": false, 
     "type": "target"
@@ -893,9 +955,25 @@
     ], 
     "headers": [], 
     "language": "c", 
-    "name": "httpcli_parser_test", 
+    "name": "http_parser_test", 
     "src": [
-      "test/core/httpcli/parser_test.c"
+      "test/core/http/parser_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "httpcli_format_request_test", 
+    "src": [
+      "test/core/http/format_request_test.c"
     ], 
     "third_party": false, 
     "type": "target"
@@ -911,7 +989,7 @@
     "language": "c", 
     "name": "httpcli_test", 
     "src": [
-      "test/core/httpcli/httpcli_test.c"
+      "test/core/http/httpcli_test.c"
     ], 
     "third_party": false, 
     "type": "target"
@@ -927,7 +1005,7 @@
     "language": "c", 
     "name": "httpscli_test", 
     "src": [
-      "test/core/httpcli/httpscli_test.c"
+      "test/core/http/httpscli_test.c"
     ], 
     "third_party": false, 
     "type": "target"
@@ -967,6 +1045,22 @@
   {
     "deps": [
       "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "json_fuzzer_test", 
+    "src": [
+      "test/core/json/fuzzer.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
       "grpc"
     ], 
     "headers": [], 
@@ -1498,6 +1592,22 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "uri_fuzzer_test", 
+    "src": [
+      "test/core/client_config/uri_fuzzer_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "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"
@@ -1684,6 +1794,32 @@
   }, 
   {
     "deps": [
+      "grpc++_codegen_lib"
+    ], 
+    "headers": [
+      "src/proto/grpc/testing/control.grpc.pb.h", 
+      "src/proto/grpc/testing/control.pb.h", 
+      "src/proto/grpc/testing/messages.grpc.pb.h", 
+      "src/proto/grpc/testing/messages.pb.h", 
+      "src/proto/grpc/testing/payloads.grpc.pb.h", 
+      "src/proto/grpc/testing/payloads.pb.h", 
+      "src/proto/grpc/testing/perf_db.grpc.pb.h", 
+      "src/proto/grpc/testing/perf_db.pb.h", 
+      "src/proto/grpc/testing/services.grpc.pb.h", 
+      "src/proto/grpc/testing/services.pb.h", 
+      "src/proto/grpc/testing/stats.grpc.pb.h", 
+      "src/proto/grpc/testing/stats.pb.h"
+    ], 
+    "language": "c++", 
+    "name": "codegen_test", 
+    "src": [
+      "test/cpp/codegen/codegen_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
       "gpr", 
       "grpc", 
       "grpc++"
@@ -2461,6 +2597,19 @@
   {
     "deps": [
       "boringssl", 
+      "boringssl_asn1_test_lib", 
+      "boringssl_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "boringssl_asn1_test", 
+    "src": [], 
+    "third_party": true, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "boringssl", 
       "boringssl_base64_test_lib", 
       "boringssl_test_util"
     ], 
@@ -3117,7 +3266,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3135,7 +3283,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3153,7 +3300,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3171,7 +3317,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3189,7 +3334,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3207,7 +3351,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3225,7 +3368,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3243,7 +3385,23 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
+      "end2end_tests", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "src": [
+      "test/core/end2end/fixtures/h2_full+trace.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3261,7 +3419,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3279,7 +3436,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3297,7 +3453,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3315,7 +3470,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3333,7 +3487,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3351,7 +3504,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3369,7 +3521,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3387,25 +3538,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
-      "end2end_tests", 
-      "gpr", 
-      "gpr_test_util", 
-      "grpc", 
-      "grpc_test_util"
-    ], 
-    "headers": [], 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "src": [
-      "test/core/end2end/fixtures/h2_uchannel.c"
-    ], 
-    "third_party": false, 
-    "type": "target"
-  }, 
-  {
-    "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3423,7 +3555,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "end2end_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -3551,6 +3682,23 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "src": [
+      "test/core/end2end/fixtures/h2_full+trace.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "end2end_nosec_tests", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "language": "c", 
     "name": "h2_proxy_nosec_test", 
     "src": [
       "test/core/end2end/fixtures/h2_proxy.c"
@@ -3619,23 +3767,6 @@
     ], 
     "headers": [], 
     "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "src": [
-      "test/core/end2end/fixtures/h2_uchannel.c"
-    ], 
-    "third_party": false, 
-    "type": "target"
-  }, 
-  {
-    "deps": [
-      "end2end_nosec_tests", 
-      "gpr", 
-      "gpr_test_util", 
-      "grpc_test_util_unsecure", 
-      "grpc_unsecure"
-    ], 
-    "headers": [], 
-    "language": "c", 
     "name": "h2_uds_nosec_test", 
     "src": [
       "test/core/end2end/fixtures/h2_uds.c"
@@ -3705,17 +3836,18 @@
       "include/grpc/support/tls_msvc.h", 
       "include/grpc/support/tls_pthread.h", 
       "include/grpc/support/useful.h", 
-      "src/core/profiling/timers.h", 
-      "src/core/support/block_annotate.h", 
-      "src/core/support/env.h", 
-      "src/core/support/load_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/time_precise.h", 
-      "src/core/support/tmpfile.h"
+      "src/core/lib/profiling/timers.h", 
+      "src/core/lib/support/backoff.h", 
+      "src/core/lib/support/block_annotate.h", 
+      "src/core/lib/support/env.h", 
+      "src/core/lib/support/load_file.h", 
+      "src/core/lib/support/murmur_hash.h", 
+      "src/core/lib/support/stack_lockfree.h", 
+      "src/core/lib/support/string.h", 
+      "src/core/lib/support/string_win32.h", 
+      "src/core/lib/support/thd_internal.h", 
+      "src/core/lib/support/time_precise.h", 
+      "src/core/lib/support/tmpfile.h"
     ], 
     "language": "c", 
     "name": "gpr", 
@@ -3762,60 +3894,62 @@
       "include/grpc/support/tls_msvc.h", 
       "include/grpc/support/tls_pthread.h", 
       "include/grpc/support/useful.h", 
-      "src/core/profiling/basic_timers.c", 
-      "src/core/profiling/stap_timers.c", 
-      "src/core/profiling/timers.h", 
-      "src/core/support/alloc.c", 
-      "src/core/support/avl.c", 
-      "src/core/support/block_annotate.h", 
-      "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/histogram.c", 
-      "src/core/support/host_port.c", 
-      "src/core/support/load_file.c", 
-      "src/core/support/load_file.h", 
-      "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/subprocess_windows.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_precise.c", 
-      "src/core/support/time_precise.h", 
-      "src/core/support/time_win32.c", 
-      "src/core/support/tls_pthread.c", 
-      "src/core/support/tmpfile.h", 
-      "src/core/support/tmpfile_posix.c", 
-      "src/core/support/tmpfile_win32.c", 
-      "src/core/support/wrap_memcpy.c"
+      "src/core/lib/profiling/basic_timers.c", 
+      "src/core/lib/profiling/stap_timers.c", 
+      "src/core/lib/profiling/timers.h", 
+      "src/core/lib/support/alloc.c", 
+      "src/core/lib/support/avl.c", 
+      "src/core/lib/support/backoff.c", 
+      "src/core/lib/support/backoff.h", 
+      "src/core/lib/support/block_annotate.h", 
+      "src/core/lib/support/cmdline.c", 
+      "src/core/lib/support/cpu_iphone.c", 
+      "src/core/lib/support/cpu_linux.c", 
+      "src/core/lib/support/cpu_posix.c", 
+      "src/core/lib/support/cpu_windows.c", 
+      "src/core/lib/support/env.h", 
+      "src/core/lib/support/env_linux.c", 
+      "src/core/lib/support/env_posix.c", 
+      "src/core/lib/support/env_win32.c", 
+      "src/core/lib/support/histogram.c", 
+      "src/core/lib/support/host_port.c", 
+      "src/core/lib/support/load_file.c", 
+      "src/core/lib/support/load_file.h", 
+      "src/core/lib/support/log.c", 
+      "src/core/lib/support/log_android.c", 
+      "src/core/lib/support/log_linux.c", 
+      "src/core/lib/support/log_posix.c", 
+      "src/core/lib/support/log_win32.c", 
+      "src/core/lib/support/murmur_hash.c", 
+      "src/core/lib/support/murmur_hash.h", 
+      "src/core/lib/support/slice.c", 
+      "src/core/lib/support/slice_buffer.c", 
+      "src/core/lib/support/stack_lockfree.c", 
+      "src/core/lib/support/stack_lockfree.h", 
+      "src/core/lib/support/string.c", 
+      "src/core/lib/support/string.h", 
+      "src/core/lib/support/string_posix.c", 
+      "src/core/lib/support/string_win32.c", 
+      "src/core/lib/support/string_win32.h", 
+      "src/core/lib/support/subprocess_posix.c", 
+      "src/core/lib/support/subprocess_windows.c", 
+      "src/core/lib/support/sync.c", 
+      "src/core/lib/support/sync_posix.c", 
+      "src/core/lib/support/sync_win32.c", 
+      "src/core/lib/support/thd.c", 
+      "src/core/lib/support/thd_internal.h", 
+      "src/core/lib/support/thd_posix.c", 
+      "src/core/lib/support/thd_win32.c", 
+      "src/core/lib/support/time.c", 
+      "src/core/lib/support/time_posix.c", 
+      "src/core/lib/support/time_precise.c", 
+      "src/core/lib/support/time_precise.h", 
+      "src/core/lib/support/time_win32.c", 
+      "src/core/lib/support/tls_pthread.c", 
+      "src/core/lib/support/tmpfile.h", 
+      "src/core/lib/support/tmpfile_posix.c", 
+      "src/core/lib/support/tmpfile_win32.c", 
+      "src/core/lib/support/wrap_memcpy.c"
     ], 
     "third_party": false, 
     "type": "lib"
@@ -3854,138 +3988,143 @@
       "include/grpc/impl/codegen/propagation_bits.h", 
       "include/grpc/impl/codegen/status.h", 
       "include/grpc/status.h", 
-      "src/core/census/aggregation.h", 
-      "src/core/census/grpc_filter.h", 
-      "src/core/census/mlog.h", 
-      "src/core/census/rpc_metric_id.h", 
-      "src/core/channel/channel_args.h", 
-      "src/core/channel/channel_stack.h", 
-      "src/core/channel/client_channel.h", 
-      "src/core/channel/client_uchannel.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/subchannel_call_holder.h", 
-      "src/core/client_config/client_config.h", 
-      "src/core/client_config/connector.h", 
-      "src/core/client_config/initial_connect_string.h", 
-      "src/core/client_config/lb_policies/load_balancer_api.h", 
-      "src/core/client_config/lb_policies/pick_first.h", 
-      "src/core/client_config/lb_policies/round_robin.h", 
-      "src/core/client_config/lb_policy.h", 
-      "src/core/client_config/lb_policy_factory.h", 
-      "src/core/client_config/lb_policy_registry.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/sockaddr_resolver.h", 
-      "src/core/client_config/subchannel.h", 
-      "src/core/client_config/subchannel_factory.h", 
-      "src/core/client_config/subchannel_index.h", 
-      "src/core/client_config/uri_parser.h", 
-      "src/core/compression/algorithm_metadata.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/parser.h", 
-      "src/core/iomgr/closure.h", 
-      "src/core/iomgr/endpoint.h", 
-      "src/core/iomgr/endpoint_pair.h", 
-      "src/core/iomgr/exec_ctx.h", 
-      "src/core/iomgr/executor.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_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/timer.h", 
-      "src/core/iomgr/timer_heap.h", 
-      "src/core/iomgr/udp_server.h", 
-      "src/core/iomgr/wakeup_fd_pipe.h", 
-      "src/core/iomgr/wakeup_fd_posix.h", 
-      "src/core/iomgr/workqueue.h", 
-      "src/core/iomgr/workqueue_posix.h", 
-      "src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.h", 
-      "src/core/security/auth_filters.h", 
-      "src/core/security/b64.h", 
-      "src/core/security/credentials.h", 
-      "src/core/security/handshake.h", 
-      "src/core/security/json_token.h", 
-      "src/core/security/jwt_verifier.h", 
-      "src/core/security/secure_endpoint.h", 
-      "src/core/security/security_connector.h", 
-      "src/core/security/security_context.h", 
-      "src/core/statistics/census_interface.h", 
-      "src/core/statistics/census_rpc_stats.h", 
-      "src/core/surface/api_trace.h", 
-      "src/core/surface/call.h", 
-      "src/core/surface/call_test_only.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/byte_stream.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_encoder.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_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/metadata_batch.h", 
-      "src/core/transport/static_metadata.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/ssl_types.h", 
-      "src/core/tsi/transport_security.h", 
-      "src/core/tsi/transport_security_interface.h", 
+      "src/core/ext/transport/chttp2/transport/alpn.h", 
+      "src/core/ext/transport/chttp2/transport/bin_encoder.h", 
+      "src/core/ext/transport/chttp2/transport/chttp2_transport.h", 
+      "src/core/ext/transport/chttp2/transport/frame.h", 
+      "src/core/ext/transport/chttp2/transport/frame_data.h", 
+      "src/core/ext/transport/chttp2/transport/frame_goaway.h", 
+      "src/core/ext/transport/chttp2/transport/frame_ping.h", 
+      "src/core/ext/transport/chttp2/transport/frame_rst_stream.h", 
+      "src/core/ext/transport/chttp2/transport/frame_settings.h", 
+      "src/core/ext/transport/chttp2/transport/frame_window_update.h", 
+      "src/core/ext/transport/chttp2/transport/hpack_encoder.h", 
+      "src/core/ext/transport/chttp2/transport/hpack_parser.h", 
+      "src/core/ext/transport/chttp2/transport/hpack_table.h", 
+      "src/core/ext/transport/chttp2/transport/http2_errors.h", 
+      "src/core/ext/transport/chttp2/transport/huffsyms.h", 
+      "src/core/ext/transport/chttp2/transport/incoming_metadata.h", 
+      "src/core/ext/transport/chttp2/transport/internal.h", 
+      "src/core/ext/transport/chttp2/transport/status_conversion.h", 
+      "src/core/ext/transport/chttp2/transport/stream_map.h", 
+      "src/core/ext/transport/chttp2/transport/timeout_encoding.h", 
+      "src/core/ext/transport/chttp2/transport/varint.h", 
+      "src/core/lib/census/aggregation.h", 
+      "src/core/lib/census/grpc_filter.h", 
+      "src/core/lib/census/grpc_plugin.h", 
+      "src/core/lib/census/mlog.h", 
+      "src/core/lib/census/rpc_metric_id.h", 
+      "src/core/lib/channel/channel_args.h", 
+      "src/core/lib/channel/channel_stack.h", 
+      "src/core/lib/channel/channel_stack_builder.h", 
+      "src/core/lib/channel/client_channel.h", 
+      "src/core/lib/channel/compress_filter.h", 
+      "src/core/lib/channel/connected_channel.h", 
+      "src/core/lib/channel/context.h", 
+      "src/core/lib/channel/http_client_filter.h", 
+      "src/core/lib/channel/http_server_filter.h", 
+      "src/core/lib/channel/subchannel_call_holder.h", 
+      "src/core/lib/client_config/client_config.h", 
+      "src/core/lib/client_config/connector.h", 
+      "src/core/lib/client_config/initial_connect_string.h", 
+      "src/core/lib/client_config/lb_policies/load_balancer_api.h", 
+      "src/core/lib/client_config/lb_policies/pick_first.h", 
+      "src/core/lib/client_config/lb_policies/round_robin.h", 
+      "src/core/lib/client_config/lb_policy.h", 
+      "src/core/lib/client_config/lb_policy_factory.h", 
+      "src/core/lib/client_config/lb_policy_registry.h", 
+      "src/core/lib/client_config/resolver.h", 
+      "src/core/lib/client_config/resolver_factory.h", 
+      "src/core/lib/client_config/resolver_registry.h", 
+      "src/core/lib/client_config/resolvers/dns_resolver.h", 
+      "src/core/lib/client_config/resolvers/sockaddr_resolver.h", 
+      "src/core/lib/client_config/subchannel.h", 
+      "src/core/lib/client_config/subchannel_factory.h", 
+      "src/core/lib/client_config/subchannel_index.h", 
+      "src/core/lib/client_config/uri_parser.h", 
+      "src/core/lib/compression/algorithm_metadata.h", 
+      "src/core/lib/compression/message_compress.h", 
+      "src/core/lib/debug/trace.h", 
+      "src/core/lib/http/format_request.h", 
+      "src/core/lib/http/httpcli.h", 
+      "src/core/lib/http/parser.h", 
+      "src/core/lib/iomgr/closure.h", 
+      "src/core/lib/iomgr/endpoint.h", 
+      "src/core/lib/iomgr/endpoint_pair.h", 
+      "src/core/lib/iomgr/exec_ctx.h", 
+      "src/core/lib/iomgr/executor.h", 
+      "src/core/lib/iomgr/fd_posix.h", 
+      "src/core/lib/iomgr/iocp_windows.h", 
+      "src/core/lib/iomgr/iomgr.h", 
+      "src/core/lib/iomgr/iomgr_internal.h", 
+      "src/core/lib/iomgr/iomgr_posix.h", 
+      "src/core/lib/iomgr/pollset.h", 
+      "src/core/lib/iomgr/pollset_posix.h", 
+      "src/core/lib/iomgr/pollset_set.h", 
+      "src/core/lib/iomgr/pollset_set_posix.h", 
+      "src/core/lib/iomgr/pollset_set_windows.h", 
+      "src/core/lib/iomgr/pollset_windows.h", 
+      "src/core/lib/iomgr/resolve_address.h", 
+      "src/core/lib/iomgr/sockaddr.h", 
+      "src/core/lib/iomgr/sockaddr_posix.h", 
+      "src/core/lib/iomgr/sockaddr_utils.h", 
+      "src/core/lib/iomgr/sockaddr_win32.h", 
+      "src/core/lib/iomgr/socket_utils_posix.h", 
+      "src/core/lib/iomgr/socket_windows.h", 
+      "src/core/lib/iomgr/tcp_client.h", 
+      "src/core/lib/iomgr/tcp_posix.h", 
+      "src/core/lib/iomgr/tcp_server.h", 
+      "src/core/lib/iomgr/tcp_windows.h", 
+      "src/core/lib/iomgr/time_averaged_stats.h", 
+      "src/core/lib/iomgr/timer.h", 
+      "src/core/lib/iomgr/timer_heap.h", 
+      "src/core/lib/iomgr/udp_server.h", 
+      "src/core/lib/iomgr/unix_sockets_posix.h", 
+      "src/core/lib/iomgr/wakeup_fd_pipe.h", 
+      "src/core/lib/iomgr/wakeup_fd_posix.h", 
+      "src/core/lib/iomgr/workqueue.h", 
+      "src/core/lib/iomgr/workqueue_posix.h", 
+      "src/core/lib/iomgr/workqueue_windows.h", 
+      "src/core/lib/json/json.h", 
+      "src/core/lib/json/json_common.h", 
+      "src/core/lib/json/json_reader.h", 
+      "src/core/lib/json/json_writer.h", 
+      "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h", 
+      "src/core/lib/security/auth_filters.h", 
+      "src/core/lib/security/b64.h", 
+      "src/core/lib/security/credentials.h", 
+      "src/core/lib/security/handshake.h", 
+      "src/core/lib/security/json_token.h", 
+      "src/core/lib/security/jwt_verifier.h", 
+      "src/core/lib/security/secure_endpoint.h", 
+      "src/core/lib/security/security_connector.h", 
+      "src/core/lib/security/security_context.h", 
+      "src/core/lib/statistics/census_interface.h", 
+      "src/core/lib/statistics/census_rpc_stats.h", 
+      "src/core/lib/surface/api_trace.h", 
+      "src/core/lib/surface/call.h", 
+      "src/core/lib/surface/call_test_only.h", 
+      "src/core/lib/surface/channel.h", 
+      "src/core/lib/surface/channel_init.h", 
+      "src/core/lib/surface/channel_stack_type.h", 
+      "src/core/lib/surface/completion_queue.h", 
+      "src/core/lib/surface/event_string.h", 
+      "src/core/lib/surface/init.h", 
+      "src/core/lib/surface/lame_client.h", 
+      "src/core/lib/surface/server.h", 
+      "src/core/lib/surface/surface_trace.h", 
+      "src/core/lib/transport/byte_stream.h", 
+      "src/core/lib/transport/connectivity_state.h", 
+      "src/core/lib/transport/metadata.h", 
+      "src/core/lib/transport/metadata_batch.h", 
+      "src/core/lib/transport/static_metadata.h", 
+      "src/core/lib/transport/transport.h", 
+      "src/core/lib/transport/transport_impl.h", 
+      "src/core/lib/tsi/fake_transport_security.h", 
+      "src/core/lib/tsi/ssl_transport_security.h", 
+      "src/core/lib/tsi/ssl_types.h", 
+      "src/core/lib/tsi/transport_security.h", 
+      "src/core/lib/tsi/transport_security_interface.h", 
       "third_party/nanopb/pb.h", 
       "third_party/nanopb/pb_common.h", 
       "third_party/nanopb/pb_decode.h", 
@@ -4007,295 +4146,355 @@
       "include/grpc/impl/codegen/propagation_bits.h", 
       "include/grpc/impl/codegen/status.h", 
       "include/grpc/status.h", 
-      "src/core/census/aggregation.h", 
-      "src/core/census/context.c", 
-      "src/core/census/grpc_context.c", 
-      "src/core/census/grpc_filter.c", 
-      "src/core/census/grpc_filter.h", 
-      "src/core/census/initialize.c", 
-      "src/core/census/mlog.c", 
-      "src/core/census/mlog.h", 
-      "src/core/census/operation.c", 
-      "src/core/census/placeholders.c", 
-      "src/core/census/rpc_metric_id.h", 
-      "src/core/census/tracing.c", 
-      "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/client_uchannel.c", 
-      "src/core/channel/client_uchannel.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/subchannel_call_holder.c", 
-      "src/core/channel/subchannel_call_holder.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/default_initial_connect_string.c", 
-      "src/core/client_config/initial_connect_string.c", 
-      "src/core/client_config/initial_connect_string.h", 
-      "src/core/client_config/lb_policies/load_balancer_api.c", 
-      "src/core/client_config/lb_policies/load_balancer_api.h", 
-      "src/core/client_config/lb_policies/pick_first.c", 
-      "src/core/client_config/lb_policies/pick_first.h", 
-      "src/core/client_config/lb_policies/round_robin.c", 
-      "src/core/client_config/lb_policies/round_robin.h", 
-      "src/core/client_config/lb_policy.c", 
-      "src/core/client_config/lb_policy.h", 
-      "src/core/client_config/lb_policy_factory.c", 
-      "src/core/client_config/lb_policy_factory.h", 
-      "src/core/client_config/lb_policy_registry.c", 
-      "src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c", 
-      "src/core/client_config/resolvers/sockaddr_resolver.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/subchannel_index.c", 
-      "src/core/client_config/subchannel_index.h", 
-      "src/core/client_config/uri_parser.c", 
-      "src/core/client_config/uri_parser.h", 
-      "src/core/compression/algorithm_metadata.h", 
-      "src/core/compression/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/parser.c", 
-      "src/core/httpcli/parser.h", 
-      "src/core/iomgr/closure.c", 
-      "src/core/iomgr/closure.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/exec_ctx.c", 
-      "src/core/iomgr/exec_ctx.h", 
-      "src/core/iomgr/executor.c", 
-      "src/core/iomgr/executor.h", 
-      "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_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/timer.c", 
-      "src/core/iomgr/timer.h", 
-      "src/core/iomgr/timer_heap.c", 
-      "src/core/iomgr/timer_heap.h", 
-      "src/core/iomgr/udp_server.c", 
-      "src/core/iomgr/udp_server.h", 
-      "src/core/iomgr/wakeup_fd_eventfd.c", 
-      "src/core/iomgr/wakeup_fd_nospecial.c", 
-      "src/core/iomgr/wakeup_fd_pipe.c", 
-      "src/core/iomgr/wakeup_fd_pipe.h", 
-      "src/core/iomgr/wakeup_fd_posix.c", 
-      "src/core/iomgr/wakeup_fd_posix.h", 
-      "src/core/iomgr/workqueue.h", 
-      "src/core/iomgr/workqueue_posix.c", 
-      "src/core/iomgr/workqueue_posix.h", 
-      "src/core/iomgr/workqueue_windows.c", 
-      "src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c", 
-      "src/core/proto/grpc/lb/v0/load_balancer.pb.h", 
-      "src/core/security/auth_filters.h", 
-      "src/core/security/b64.c", 
-      "src/core/security/b64.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/handshake.c", 
-      "src/core/security/handshake.h", 
-      "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/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/statistics/census_interface.h", 
-      "src/core/statistics/census_rpc_stats.h", 
-      "src/core/surface/alarm.c", 
-      "src/core/surface/api_trace.c", 
-      "src/core/surface/api_trace.h", 
-      "src/core/surface/byte_buffer.c", 
-      "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/call_test_only.h", 
-      "src/core/surface/channel.c", 
-      "src/core/surface/channel.h", 
-      "src/core/surface/channel_connectivity.c", 
-      "src/core/surface/channel_create.c", 
-      "src/core/surface/channel_ping.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.h", 
-      "src/core/surface/validate_metadata.c", 
-      "src/core/surface/version.c", 
-      "src/core/transport/byte_stream.c", 
-      "src/core/transport/byte_stream.h", 
-      "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_encoder.c", 
-      "src/core/transport/chttp2/hpack_encoder.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_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/metadata_batch.c", 
-      "src/core/transport/metadata_batch.h", 
-      "src/core/transport/static_metadata.c", 
-      "src/core/transport/static_metadata.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/ssl_types.h", 
-      "src/core/tsi/transport_security.c", 
-      "src/core/tsi/transport_security.h", 
-      "src/core/tsi/transport_security_interface.h"
+      "src/core/ext/transport/chttp2/client/insecure/channel_create.c", 
+      "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c", 
+      "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c", 
+      "src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c", 
+      "src/core/ext/transport/chttp2/transport/alpn.c", 
+      "src/core/ext/transport/chttp2/transport/alpn.h", 
+      "src/core/ext/transport/chttp2/transport/bin_encoder.c", 
+      "src/core/ext/transport/chttp2/transport/bin_encoder.h", 
+      "src/core/ext/transport/chttp2/transport/chttp2_transport.c", 
+      "src/core/ext/transport/chttp2/transport/chttp2_transport.h", 
+      "src/core/ext/transport/chttp2/transport/frame.h", 
+      "src/core/ext/transport/chttp2/transport/frame_data.c", 
+      "src/core/ext/transport/chttp2/transport/frame_data.h", 
+      "src/core/ext/transport/chttp2/transport/frame_goaway.c", 
+      "src/core/ext/transport/chttp2/transport/frame_goaway.h", 
+      "src/core/ext/transport/chttp2/transport/frame_ping.c", 
+      "src/core/ext/transport/chttp2/transport/frame_ping.h", 
+      "src/core/ext/transport/chttp2/transport/frame_rst_stream.c", 
+      "src/core/ext/transport/chttp2/transport/frame_rst_stream.h", 
+      "src/core/ext/transport/chttp2/transport/frame_settings.c", 
+      "src/core/ext/transport/chttp2/transport/frame_settings.h", 
+      "src/core/ext/transport/chttp2/transport/frame_window_update.c", 
+      "src/core/ext/transport/chttp2/transport/frame_window_update.h", 
+      "src/core/ext/transport/chttp2/transport/hpack_encoder.c", 
+      "src/core/ext/transport/chttp2/transport/hpack_encoder.h", 
+      "src/core/ext/transport/chttp2/transport/hpack_parser.c", 
+      "src/core/ext/transport/chttp2/transport/hpack_parser.h", 
+      "src/core/ext/transport/chttp2/transport/hpack_table.c", 
+      "src/core/ext/transport/chttp2/transport/hpack_table.h", 
+      "src/core/ext/transport/chttp2/transport/http2_errors.h", 
+      "src/core/ext/transport/chttp2/transport/huffsyms.c", 
+      "src/core/ext/transport/chttp2/transport/huffsyms.h", 
+      "src/core/ext/transport/chttp2/transport/incoming_metadata.c", 
+      "src/core/ext/transport/chttp2/transport/incoming_metadata.h", 
+      "src/core/ext/transport/chttp2/transport/internal.h", 
+      "src/core/ext/transport/chttp2/transport/parsing.c", 
+      "src/core/ext/transport/chttp2/transport/status_conversion.c", 
+      "src/core/ext/transport/chttp2/transport/status_conversion.h", 
+      "src/core/ext/transport/chttp2/transport/stream_lists.c", 
+      "src/core/ext/transport/chttp2/transport/stream_map.c", 
+      "src/core/ext/transport/chttp2/transport/stream_map.h", 
+      "src/core/ext/transport/chttp2/transport/timeout_encoding.c", 
+      "src/core/ext/transport/chttp2/transport/timeout_encoding.h", 
+      "src/core/ext/transport/chttp2/transport/varint.c", 
+      "src/core/ext/transport/chttp2/transport/varint.h", 
+      "src/core/ext/transport/chttp2/transport/writing.c", 
+      "src/core/lib/census/aggregation.h", 
+      "src/core/lib/census/context.c", 
+      "src/core/lib/census/grpc_context.c", 
+      "src/core/lib/census/grpc_filter.c", 
+      "src/core/lib/census/grpc_filter.h", 
+      "src/core/lib/census/grpc_plugin.c", 
+      "src/core/lib/census/grpc_plugin.h", 
+      "src/core/lib/census/initialize.c", 
+      "src/core/lib/census/mlog.c", 
+      "src/core/lib/census/mlog.h", 
+      "src/core/lib/census/operation.c", 
+      "src/core/lib/census/placeholders.c", 
+      "src/core/lib/census/rpc_metric_id.h", 
+      "src/core/lib/census/tracing.c", 
+      "src/core/lib/channel/channel_args.c", 
+      "src/core/lib/channel/channel_args.h", 
+      "src/core/lib/channel/channel_stack.c", 
+      "src/core/lib/channel/channel_stack.h", 
+      "src/core/lib/channel/channel_stack_builder.c", 
+      "src/core/lib/channel/channel_stack_builder.h", 
+      "src/core/lib/channel/client_channel.c", 
+      "src/core/lib/channel/client_channel.h", 
+      "src/core/lib/channel/compress_filter.c", 
+      "src/core/lib/channel/compress_filter.h", 
+      "src/core/lib/channel/connected_channel.c", 
+      "src/core/lib/channel/connected_channel.h", 
+      "src/core/lib/channel/context.h", 
+      "src/core/lib/channel/http_client_filter.c", 
+      "src/core/lib/channel/http_client_filter.h", 
+      "src/core/lib/channel/http_server_filter.c", 
+      "src/core/lib/channel/http_server_filter.h", 
+      "src/core/lib/channel/subchannel_call_holder.c", 
+      "src/core/lib/channel/subchannel_call_holder.h", 
+      "src/core/lib/client_config/client_config.c", 
+      "src/core/lib/client_config/client_config.h", 
+      "src/core/lib/client_config/connector.c", 
+      "src/core/lib/client_config/connector.h", 
+      "src/core/lib/client_config/default_initial_connect_string.c", 
+      "src/core/lib/client_config/initial_connect_string.c", 
+      "src/core/lib/client_config/initial_connect_string.h", 
+      "src/core/lib/client_config/lb_policies/load_balancer_api.c", 
+      "src/core/lib/client_config/lb_policies/load_balancer_api.h", 
+      "src/core/lib/client_config/lb_policies/pick_first.c", 
+      "src/core/lib/client_config/lb_policies/pick_first.h", 
+      "src/core/lib/client_config/lb_policies/round_robin.c", 
+      "src/core/lib/client_config/lb_policies/round_robin.h", 
+      "src/core/lib/client_config/lb_policy.c", 
+      "src/core/lib/client_config/lb_policy.h", 
+      "src/core/lib/client_config/lb_policy_factory.c", 
+      "src/core/lib/client_config/lb_policy_factory.h", 
+      "src/core/lib/client_config/lb_policy_registry.c", 
+      "src/core/lib/client_config/lb_policy_registry.h", 
+      "src/core/lib/client_config/resolver.c", 
+      "src/core/lib/client_config/resolver.h", 
+      "src/core/lib/client_config/resolver_factory.c", 
+      "src/core/lib/client_config/resolver_factory.h", 
+      "src/core/lib/client_config/resolver_registry.c", 
+      "src/core/lib/client_config/resolver_registry.h", 
+      "src/core/lib/client_config/resolvers/dns_resolver.c", 
+      "src/core/lib/client_config/resolvers/dns_resolver.h", 
+      "src/core/lib/client_config/resolvers/sockaddr_resolver.c", 
+      "src/core/lib/client_config/resolvers/sockaddr_resolver.h", 
+      "src/core/lib/client_config/subchannel.c", 
+      "src/core/lib/client_config/subchannel.h", 
+      "src/core/lib/client_config/subchannel_factory.c", 
+      "src/core/lib/client_config/subchannel_factory.h", 
+      "src/core/lib/client_config/subchannel_index.c", 
+      "src/core/lib/client_config/subchannel_index.h", 
+      "src/core/lib/client_config/uri_parser.c", 
+      "src/core/lib/client_config/uri_parser.h", 
+      "src/core/lib/compression/algorithm_metadata.h", 
+      "src/core/lib/compression/compression_algorithm.c", 
+      "src/core/lib/compression/message_compress.c", 
+      "src/core/lib/compression/message_compress.h", 
+      "src/core/lib/debug/trace.c", 
+      "src/core/lib/debug/trace.h", 
+      "src/core/lib/http/format_request.c", 
+      "src/core/lib/http/format_request.h", 
+      "src/core/lib/http/httpcli.c", 
+      "src/core/lib/http/httpcli.h", 
+      "src/core/lib/http/httpcli_security_connector.c", 
+      "src/core/lib/http/parser.c", 
+      "src/core/lib/http/parser.h", 
+      "src/core/lib/iomgr/closure.c", 
+      "src/core/lib/iomgr/closure.h", 
+      "src/core/lib/iomgr/endpoint.c", 
+      "src/core/lib/iomgr/endpoint.h", 
+      "src/core/lib/iomgr/endpoint_pair.h", 
+      "src/core/lib/iomgr/endpoint_pair_posix.c", 
+      "src/core/lib/iomgr/endpoint_pair_windows.c", 
+      "src/core/lib/iomgr/exec_ctx.c", 
+      "src/core/lib/iomgr/exec_ctx.h", 
+      "src/core/lib/iomgr/executor.c", 
+      "src/core/lib/iomgr/executor.h", 
+      "src/core/lib/iomgr/fd_posix.c", 
+      "src/core/lib/iomgr/fd_posix.h", 
+      "src/core/lib/iomgr/iocp_windows.c", 
+      "src/core/lib/iomgr/iocp_windows.h", 
+      "src/core/lib/iomgr/iomgr.c", 
+      "src/core/lib/iomgr/iomgr.h", 
+      "src/core/lib/iomgr/iomgr_internal.h", 
+      "src/core/lib/iomgr/iomgr_posix.c", 
+      "src/core/lib/iomgr/iomgr_posix.h", 
+      "src/core/lib/iomgr/iomgr_windows.c", 
+      "src/core/lib/iomgr/pollset.h", 
+      "src/core/lib/iomgr/pollset_multipoller_with_epoll.c", 
+      "src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c", 
+      "src/core/lib/iomgr/pollset_posix.c", 
+      "src/core/lib/iomgr/pollset_posix.h", 
+      "src/core/lib/iomgr/pollset_set.h", 
+      "src/core/lib/iomgr/pollset_set_posix.c", 
+      "src/core/lib/iomgr/pollset_set_posix.h", 
+      "src/core/lib/iomgr/pollset_set_windows.c", 
+      "src/core/lib/iomgr/pollset_set_windows.h", 
+      "src/core/lib/iomgr/pollset_windows.c", 
+      "src/core/lib/iomgr/pollset_windows.h", 
+      "src/core/lib/iomgr/resolve_address.h", 
+      "src/core/lib/iomgr/resolve_address_posix.c", 
+      "src/core/lib/iomgr/resolve_address_windows.c", 
+      "src/core/lib/iomgr/sockaddr.h", 
+      "src/core/lib/iomgr/sockaddr_posix.h", 
+      "src/core/lib/iomgr/sockaddr_utils.c", 
+      "src/core/lib/iomgr/sockaddr_utils.h", 
+      "src/core/lib/iomgr/sockaddr_win32.h", 
+      "src/core/lib/iomgr/socket_utils_common_posix.c", 
+      "src/core/lib/iomgr/socket_utils_linux.c", 
+      "src/core/lib/iomgr/socket_utils_posix.c", 
+      "src/core/lib/iomgr/socket_utils_posix.h", 
+      "src/core/lib/iomgr/socket_windows.c", 
+      "src/core/lib/iomgr/socket_windows.h", 
+      "src/core/lib/iomgr/tcp_client.h", 
+      "src/core/lib/iomgr/tcp_client_posix.c", 
+      "src/core/lib/iomgr/tcp_client_windows.c", 
+      "src/core/lib/iomgr/tcp_posix.c", 
+      "src/core/lib/iomgr/tcp_posix.h", 
+      "src/core/lib/iomgr/tcp_server.h", 
+      "src/core/lib/iomgr/tcp_server_posix.c", 
+      "src/core/lib/iomgr/tcp_server_windows.c", 
+      "src/core/lib/iomgr/tcp_windows.c", 
+      "src/core/lib/iomgr/tcp_windows.h", 
+      "src/core/lib/iomgr/time_averaged_stats.c", 
+      "src/core/lib/iomgr/time_averaged_stats.h", 
+      "src/core/lib/iomgr/timer.c", 
+      "src/core/lib/iomgr/timer.h", 
+      "src/core/lib/iomgr/timer_heap.c", 
+      "src/core/lib/iomgr/timer_heap.h", 
+      "src/core/lib/iomgr/udp_server.c", 
+      "src/core/lib/iomgr/udp_server.h", 
+      "src/core/lib/iomgr/unix_sockets_posix.c", 
+      "src/core/lib/iomgr/unix_sockets_posix.h", 
+      "src/core/lib/iomgr/unix_sockets_posix_noop.c", 
+      "src/core/lib/iomgr/wakeup_fd_eventfd.c", 
+      "src/core/lib/iomgr/wakeup_fd_nospecial.c", 
+      "src/core/lib/iomgr/wakeup_fd_pipe.c", 
+      "src/core/lib/iomgr/wakeup_fd_pipe.h", 
+      "src/core/lib/iomgr/wakeup_fd_posix.c", 
+      "src/core/lib/iomgr/wakeup_fd_posix.h", 
+      "src/core/lib/iomgr/workqueue.h", 
+      "src/core/lib/iomgr/workqueue_posix.c", 
+      "src/core/lib/iomgr/workqueue_posix.h", 
+      "src/core/lib/iomgr/workqueue_windows.c", 
+      "src/core/lib/iomgr/workqueue_windows.h", 
+      "src/core/lib/json/json.c", 
+      "src/core/lib/json/json.h", 
+      "src/core/lib/json/json_common.h", 
+      "src/core/lib/json/json_reader.c", 
+      "src/core/lib/json/json_reader.h", 
+      "src/core/lib/json/json_string.c", 
+      "src/core/lib/json/json_writer.c", 
+      "src/core/lib/json/json_writer.h", 
+      "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c", 
+      "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h", 
+      "src/core/lib/security/auth_filters.h", 
+      "src/core/lib/security/b64.c", 
+      "src/core/lib/security/b64.h", 
+      "src/core/lib/security/client_auth_filter.c", 
+      "src/core/lib/security/credentials.c", 
+      "src/core/lib/security/credentials.h", 
+      "src/core/lib/security/credentials_metadata.c", 
+      "src/core/lib/security/credentials_posix.c", 
+      "src/core/lib/security/credentials_win32.c", 
+      "src/core/lib/security/google_default_credentials.c", 
+      "src/core/lib/security/handshake.c", 
+      "src/core/lib/security/handshake.h", 
+      "src/core/lib/security/json_token.c", 
+      "src/core/lib/security/json_token.h", 
+      "src/core/lib/security/jwt_verifier.c", 
+      "src/core/lib/security/jwt_verifier.h", 
+      "src/core/lib/security/secure_endpoint.c", 
+      "src/core/lib/security/secure_endpoint.h", 
+      "src/core/lib/security/security_connector.c", 
+      "src/core/lib/security/security_connector.h", 
+      "src/core/lib/security/security_context.c", 
+      "src/core/lib/security/security_context.h", 
+      "src/core/lib/security/server_auth_filter.c", 
+      "src/core/lib/statistics/census_interface.h", 
+      "src/core/lib/statistics/census_rpc_stats.h", 
+      "src/core/lib/surface/alarm.c", 
+      "src/core/lib/surface/api_trace.c", 
+      "src/core/lib/surface/api_trace.h", 
+      "src/core/lib/surface/byte_buffer.c", 
+      "src/core/lib/surface/byte_buffer_reader.c", 
+      "src/core/lib/surface/call.c", 
+      "src/core/lib/surface/call.h", 
+      "src/core/lib/surface/call_details.c", 
+      "src/core/lib/surface/call_log_batch.c", 
+      "src/core/lib/surface/call_test_only.h", 
+      "src/core/lib/surface/channel.c", 
+      "src/core/lib/surface/channel.h", 
+      "src/core/lib/surface/channel_connectivity.c", 
+      "src/core/lib/surface/channel_init.c", 
+      "src/core/lib/surface/channel_init.h", 
+      "src/core/lib/surface/channel_ping.c", 
+      "src/core/lib/surface/channel_stack_type.c", 
+      "src/core/lib/surface/channel_stack_type.h", 
+      "src/core/lib/surface/completion_queue.c", 
+      "src/core/lib/surface/completion_queue.h", 
+      "src/core/lib/surface/event_string.c", 
+      "src/core/lib/surface/event_string.h", 
+      "src/core/lib/surface/init.c", 
+      "src/core/lib/surface/init.h", 
+      "src/core/lib/surface/init_secure.c", 
+      "src/core/lib/surface/lame_client.c", 
+      "src/core/lib/surface/lame_client.h", 
+      "src/core/lib/surface/metadata_array.c", 
+      "src/core/lib/surface/server.c", 
+      "src/core/lib/surface/server.h", 
+      "src/core/lib/surface/surface_trace.h", 
+      "src/core/lib/surface/validate_metadata.c", 
+      "src/core/lib/surface/version.c", 
+      "src/core/lib/transport/byte_stream.c", 
+      "src/core/lib/transport/byte_stream.h", 
+      "src/core/lib/transport/connectivity_state.c", 
+      "src/core/lib/transport/connectivity_state.h", 
+      "src/core/lib/transport/metadata.c", 
+      "src/core/lib/transport/metadata.h", 
+      "src/core/lib/transport/metadata_batch.c", 
+      "src/core/lib/transport/metadata_batch.h", 
+      "src/core/lib/transport/static_metadata.c", 
+      "src/core/lib/transport/static_metadata.h", 
+      "src/core/lib/transport/transport.c", 
+      "src/core/lib/transport/transport.h", 
+      "src/core/lib/transport/transport_impl.h", 
+      "src/core/lib/transport/transport_op_string.c", 
+      "src/core/lib/tsi/fake_transport_security.c", 
+      "src/core/lib/tsi/fake_transport_security.h", 
+      "src/core/lib/tsi/ssl_transport_security.c", 
+      "src/core/lib/tsi/ssl_transport_security.h", 
+      "src/core/lib/tsi/ssl_types.h", 
+      "src/core/lib/tsi/transport_security.c", 
+      "src/core/lib/tsi/transport_security.h", 
+      "src/core/lib/tsi/transport_security_interface.h"
+    ], 
+    "third_party": false, 
+    "type": "lib"
+  }, 
+  {
+    "deps": [], 
+    "headers": [
+      "include/grpc/impl/codegen/alloc.h", 
+      "include/grpc/impl/codegen/atm.h", 
+      "include/grpc/impl/codegen/atm_gcc_atomic.h", 
+      "include/grpc/impl/codegen/atm_gcc_sync.h", 
+      "include/grpc/impl/codegen/atm_win32.h", 
+      "include/grpc/impl/codegen/byte_buffer.h", 
+      "include/grpc/impl/codegen/compression_types.h", 
+      "include/grpc/impl/codegen/connectivity_state.h", 
+      "include/grpc/impl/codegen/grpc_types.h", 
+      "include/grpc/impl/codegen/log.h", 
+      "include/grpc/impl/codegen/port_platform.h", 
+      "include/grpc/impl/codegen/propagation_bits.h", 
+      "include/grpc/impl/codegen/slice.h", 
+      "include/grpc/impl/codegen/slice_buffer.h", 
+      "include/grpc/impl/codegen/status.h", 
+      "include/grpc/impl/codegen/sync.h", 
+      "include/grpc/impl/codegen/sync_generic.h", 
+      "include/grpc/impl/codegen/sync_posix.h", 
+      "include/grpc/impl/codegen/sync_win32.h", 
+      "include/grpc/impl/codegen/time.h"
+    ], 
+    "language": "c", 
+    "name": "grpc_codegen_lib", 
+    "src": [
+      "include/grpc/impl/codegen/alloc.h", 
+      "include/grpc/impl/codegen/atm.h", 
+      "include/grpc/impl/codegen/atm_gcc_atomic.h", 
+      "include/grpc/impl/codegen/atm_gcc_sync.h", 
+      "include/grpc/impl/codegen/atm_win32.h", 
+      "include/grpc/impl/codegen/byte_buffer.h", 
+      "include/grpc/impl/codegen/compression_types.h", 
+      "include/grpc/impl/codegen/connectivity_state.h", 
+      "include/grpc/impl/codegen/grpc_types.h", 
+      "include/grpc/impl/codegen/log.h", 
+      "include/grpc/impl/codegen/port_platform.h", 
+      "include/grpc/impl/codegen/propagation_bits.h", 
+      "include/grpc/impl/codegen/slice.h", 
+      "include/grpc/impl/codegen/slice_buffer.h", 
+      "include/grpc/impl/codegen/status.h", 
+      "include/grpc/impl/codegen/sync.h", 
+      "include/grpc/impl/codegen/sync_generic.h", 
+      "include/grpc/impl/codegen/sync_posix.h", 
+      "include/grpc/impl/codegen/sync_win32.h", 
+      "include/grpc/impl/codegen/time.h"
     ], 
     "third_party": false, 
     "type": "lib"
@@ -4327,6 +4526,7 @@
       "test/core/util/grpc_profiler.h", 
       "test/core/util/parse_hexstring.h", 
       "test/core/util/port.h", 
+      "test/core/util/port_server_client.h", 
       "test/core/util/slice_splitter.h"
     ], 
     "language": "c", 
@@ -4350,6 +4550,8 @@
       "test/core/util/parse_hexstring.h", 
       "test/core/util/port.h", 
       "test/core/util/port_posix.c", 
+      "test/core/util/port_server_client.c", 
+      "test/core/util/port_server_client.h", 
       "test/core/util/port_windows.c", 
       "test/core/util/slice_splitter.c", 
       "test/core/util/slice_splitter.h"
@@ -4370,6 +4572,7 @@
       "test/core/util/grpc_profiler.h", 
       "test/core/util/parse_hexstring.h", 
       "test/core/util/port.h", 
+      "test/core/util/port_server_client.h", 
       "test/core/util/slice_splitter.h"
     ], 
     "language": "c", 
@@ -4387,6 +4590,8 @@
       "test/core/util/parse_hexstring.h", 
       "test/core/util/port.h", 
       "test/core/util/port_posix.c", 
+      "test/core/util/port_server_client.c", 
+      "test/core/util/port_server_client.h", 
       "test/core/util/port_windows.c", 
       "test/core/util/slice_splitter.c", 
       "test/core/util/slice_splitter.h"
@@ -4411,124 +4616,129 @@
       "include/grpc/impl/codegen/propagation_bits.h", 
       "include/grpc/impl/codegen/status.h", 
       "include/grpc/status.h", 
-      "src/core/census/aggregation.h", 
-      "src/core/census/grpc_filter.h", 
-      "src/core/census/mlog.h", 
-      "src/core/census/rpc_metric_id.h", 
-      "src/core/channel/channel_args.h", 
-      "src/core/channel/channel_stack.h", 
-      "src/core/channel/client_channel.h", 
-      "src/core/channel/client_uchannel.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/subchannel_call_holder.h", 
-      "src/core/client_config/client_config.h", 
-      "src/core/client_config/connector.h", 
-      "src/core/client_config/initial_connect_string.h", 
-      "src/core/client_config/lb_policies/load_balancer_api.h", 
-      "src/core/client_config/lb_policies/pick_first.h", 
-      "src/core/client_config/lb_policies/round_robin.h", 
-      "src/core/client_config/lb_policy.h", 
-      "src/core/client_config/lb_policy_factory.h", 
-      "src/core/client_config/lb_policy_registry.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/sockaddr_resolver.h", 
-      "src/core/client_config/subchannel.h", 
-      "src/core/client_config/subchannel_factory.h", 
-      "src/core/client_config/subchannel_index.h", 
-      "src/core/client_config/uri_parser.h", 
-      "src/core/compression/algorithm_metadata.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/parser.h", 
-      "src/core/iomgr/closure.h", 
-      "src/core/iomgr/endpoint.h", 
-      "src/core/iomgr/endpoint_pair.h", 
-      "src/core/iomgr/exec_ctx.h", 
-      "src/core/iomgr/executor.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_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/timer.h", 
-      "src/core/iomgr/timer_heap.h", 
-      "src/core/iomgr/udp_server.h", 
-      "src/core/iomgr/wakeup_fd_pipe.h", 
-      "src/core/iomgr/wakeup_fd_posix.h", 
-      "src/core/iomgr/workqueue.h", 
-      "src/core/iomgr/workqueue_posix.h", 
-      "src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.h", 
-      "src/core/statistics/census_interface.h", 
-      "src/core/statistics/census_rpc_stats.h", 
-      "src/core/surface/api_trace.h", 
-      "src/core/surface/call.h", 
-      "src/core/surface/call_test_only.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/byte_stream.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_encoder.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_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/metadata_batch.h", 
-      "src/core/transport/static_metadata.h", 
-      "src/core/transport/transport.h", 
-      "src/core/transport/transport_impl.h", 
+      "src/core/ext/transport/chttp2/transport/alpn.h", 
+      "src/core/ext/transport/chttp2/transport/bin_encoder.h", 
+      "src/core/ext/transport/chttp2/transport/chttp2_transport.h", 
+      "src/core/ext/transport/chttp2/transport/frame.h", 
+      "src/core/ext/transport/chttp2/transport/frame_data.h", 
+      "src/core/ext/transport/chttp2/transport/frame_goaway.h", 
+      "src/core/ext/transport/chttp2/transport/frame_ping.h", 
+      "src/core/ext/transport/chttp2/transport/frame_rst_stream.h", 
+      "src/core/ext/transport/chttp2/transport/frame_settings.h", 
+      "src/core/ext/transport/chttp2/transport/frame_window_update.h", 
+      "src/core/ext/transport/chttp2/transport/hpack_encoder.h", 
+      "src/core/ext/transport/chttp2/transport/hpack_parser.h", 
+      "src/core/ext/transport/chttp2/transport/hpack_table.h", 
+      "src/core/ext/transport/chttp2/transport/http2_errors.h", 
+      "src/core/ext/transport/chttp2/transport/huffsyms.h", 
+      "src/core/ext/transport/chttp2/transport/incoming_metadata.h", 
+      "src/core/ext/transport/chttp2/transport/internal.h", 
+      "src/core/ext/transport/chttp2/transport/status_conversion.h", 
+      "src/core/ext/transport/chttp2/transport/stream_map.h", 
+      "src/core/ext/transport/chttp2/transport/timeout_encoding.h", 
+      "src/core/ext/transport/chttp2/transport/varint.h", 
+      "src/core/lib/census/aggregation.h", 
+      "src/core/lib/census/grpc_filter.h", 
+      "src/core/lib/census/grpc_plugin.h", 
+      "src/core/lib/census/mlog.h", 
+      "src/core/lib/census/rpc_metric_id.h", 
+      "src/core/lib/channel/channel_args.h", 
+      "src/core/lib/channel/channel_stack.h", 
+      "src/core/lib/channel/channel_stack_builder.h", 
+      "src/core/lib/channel/client_channel.h", 
+      "src/core/lib/channel/compress_filter.h", 
+      "src/core/lib/channel/connected_channel.h", 
+      "src/core/lib/channel/context.h", 
+      "src/core/lib/channel/http_client_filter.h", 
+      "src/core/lib/channel/http_server_filter.h", 
+      "src/core/lib/channel/subchannel_call_holder.h", 
+      "src/core/lib/client_config/client_config.h", 
+      "src/core/lib/client_config/connector.h", 
+      "src/core/lib/client_config/initial_connect_string.h", 
+      "src/core/lib/client_config/lb_policies/load_balancer_api.h", 
+      "src/core/lib/client_config/lb_policies/pick_first.h", 
+      "src/core/lib/client_config/lb_policies/round_robin.h", 
+      "src/core/lib/client_config/lb_policy.h", 
+      "src/core/lib/client_config/lb_policy_factory.h", 
+      "src/core/lib/client_config/lb_policy_registry.h", 
+      "src/core/lib/client_config/resolver.h", 
+      "src/core/lib/client_config/resolver_factory.h", 
+      "src/core/lib/client_config/resolver_registry.h", 
+      "src/core/lib/client_config/resolvers/dns_resolver.h", 
+      "src/core/lib/client_config/resolvers/sockaddr_resolver.h", 
+      "src/core/lib/client_config/subchannel.h", 
+      "src/core/lib/client_config/subchannel_factory.h", 
+      "src/core/lib/client_config/subchannel_index.h", 
+      "src/core/lib/client_config/uri_parser.h", 
+      "src/core/lib/compression/algorithm_metadata.h", 
+      "src/core/lib/compression/message_compress.h", 
+      "src/core/lib/debug/trace.h", 
+      "src/core/lib/http/format_request.h", 
+      "src/core/lib/http/httpcli.h", 
+      "src/core/lib/http/parser.h", 
+      "src/core/lib/iomgr/closure.h", 
+      "src/core/lib/iomgr/endpoint.h", 
+      "src/core/lib/iomgr/endpoint_pair.h", 
+      "src/core/lib/iomgr/exec_ctx.h", 
+      "src/core/lib/iomgr/executor.h", 
+      "src/core/lib/iomgr/fd_posix.h", 
+      "src/core/lib/iomgr/iocp_windows.h", 
+      "src/core/lib/iomgr/iomgr.h", 
+      "src/core/lib/iomgr/iomgr_internal.h", 
+      "src/core/lib/iomgr/iomgr_posix.h", 
+      "src/core/lib/iomgr/pollset.h", 
+      "src/core/lib/iomgr/pollset_posix.h", 
+      "src/core/lib/iomgr/pollset_set.h", 
+      "src/core/lib/iomgr/pollset_set_posix.h", 
+      "src/core/lib/iomgr/pollset_set_windows.h", 
+      "src/core/lib/iomgr/pollset_windows.h", 
+      "src/core/lib/iomgr/resolve_address.h", 
+      "src/core/lib/iomgr/sockaddr.h", 
+      "src/core/lib/iomgr/sockaddr_posix.h", 
+      "src/core/lib/iomgr/sockaddr_utils.h", 
+      "src/core/lib/iomgr/sockaddr_win32.h", 
+      "src/core/lib/iomgr/socket_utils_posix.h", 
+      "src/core/lib/iomgr/socket_windows.h", 
+      "src/core/lib/iomgr/tcp_client.h", 
+      "src/core/lib/iomgr/tcp_posix.h", 
+      "src/core/lib/iomgr/tcp_server.h", 
+      "src/core/lib/iomgr/tcp_windows.h", 
+      "src/core/lib/iomgr/time_averaged_stats.h", 
+      "src/core/lib/iomgr/timer.h", 
+      "src/core/lib/iomgr/timer_heap.h", 
+      "src/core/lib/iomgr/udp_server.h", 
+      "src/core/lib/iomgr/unix_sockets_posix.h", 
+      "src/core/lib/iomgr/wakeup_fd_pipe.h", 
+      "src/core/lib/iomgr/wakeup_fd_posix.h", 
+      "src/core/lib/iomgr/workqueue.h", 
+      "src/core/lib/iomgr/workqueue_posix.h", 
+      "src/core/lib/iomgr/workqueue_windows.h", 
+      "src/core/lib/json/json.h", 
+      "src/core/lib/json/json_common.h", 
+      "src/core/lib/json/json_reader.h", 
+      "src/core/lib/json/json_writer.h", 
+      "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h", 
+      "src/core/lib/statistics/census_interface.h", 
+      "src/core/lib/statistics/census_rpc_stats.h", 
+      "src/core/lib/surface/api_trace.h", 
+      "src/core/lib/surface/call.h", 
+      "src/core/lib/surface/call_test_only.h", 
+      "src/core/lib/surface/channel.h", 
+      "src/core/lib/surface/channel_init.h", 
+      "src/core/lib/surface/channel_stack_type.h", 
+      "src/core/lib/surface/completion_queue.h", 
+      "src/core/lib/surface/event_string.h", 
+      "src/core/lib/surface/init.h", 
+      "src/core/lib/surface/lame_client.h", 
+      "src/core/lib/surface/server.h", 
+      "src/core/lib/surface/surface_trace.h", 
+      "src/core/lib/transport/byte_stream.h", 
+      "src/core/lib/transport/connectivity_state.h", 
+      "src/core/lib/transport/metadata.h", 
+      "src/core/lib/transport/metadata_batch.h", 
+      "src/core/lib/transport/static_metadata.h", 
+      "src/core/lib/transport/transport.h", 
+      "src/core/lib/transport/transport_impl.h", 
       "third_party/nanopb/pb.h", 
       "third_party/nanopb/pb_common.h", 
       "third_party/nanopb/pb_decode.h", 
@@ -4549,261 +4759,270 @@
       "include/grpc/impl/codegen/propagation_bits.h", 
       "include/grpc/impl/codegen/status.h", 
       "include/grpc/status.h", 
-      "src/core/census/aggregation.h", 
-      "src/core/census/context.c", 
-      "src/core/census/grpc_context.c", 
-      "src/core/census/grpc_filter.c", 
-      "src/core/census/grpc_filter.h", 
-      "src/core/census/initialize.c", 
-      "src/core/census/mlog.c", 
-      "src/core/census/mlog.h", 
-      "src/core/census/operation.c", 
-      "src/core/census/placeholders.c", 
-      "src/core/census/rpc_metric_id.h", 
-      "src/core/census/tracing.c", 
-      "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/client_uchannel.c", 
-      "src/core/channel/client_uchannel.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/subchannel_call_holder.c", 
-      "src/core/channel/subchannel_call_holder.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/default_initial_connect_string.c", 
-      "src/core/client_config/initial_connect_string.c", 
-      "src/core/client_config/initial_connect_string.h", 
-      "src/core/client_config/lb_policies/load_balancer_api.c", 
-      "src/core/client_config/lb_policies/load_balancer_api.h", 
-      "src/core/client_config/lb_policies/pick_first.c", 
-      "src/core/client_config/lb_policies/pick_first.h", 
-      "src/core/client_config/lb_policies/round_robin.c", 
-      "src/core/client_config/lb_policies/round_robin.h", 
-      "src/core/client_config/lb_policy.c", 
-      "src/core/client_config/lb_policy.h", 
-      "src/core/client_config/lb_policy_factory.c", 
-      "src/core/client_config/lb_policy_factory.h", 
-      "src/core/client_config/lb_policy_registry.c", 
-      "src/core/client_config/lb_policy_registry.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/sockaddr_resolver.c", 
-      "src/core/client_config/resolvers/sockaddr_resolver.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/subchannel_index.c", 
-      "src/core/client_config/subchannel_index.h", 
-      "src/core/client_config/uri_parser.c", 
-      "src/core/client_config/uri_parser.h", 
-      "src/core/compression/algorithm_metadata.h", 
-      "src/core/compression/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/parser.c", 
-      "src/core/httpcli/parser.h", 
-      "src/core/iomgr/closure.c", 
-      "src/core/iomgr/closure.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/exec_ctx.c", 
-      "src/core/iomgr/exec_ctx.h", 
-      "src/core/iomgr/executor.c", 
-      "src/core/iomgr/executor.h", 
-      "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_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/timer.c", 
-      "src/core/iomgr/timer.h", 
-      "src/core/iomgr/timer_heap.c", 
-      "src/core/iomgr/timer_heap.h", 
-      "src/core/iomgr/udp_server.c", 
-      "src/core/iomgr/udp_server.h", 
-      "src/core/iomgr/wakeup_fd_eventfd.c", 
-      "src/core/iomgr/wakeup_fd_nospecial.c", 
-      "src/core/iomgr/wakeup_fd_pipe.c", 
-      "src/core/iomgr/wakeup_fd_pipe.h", 
-      "src/core/iomgr/wakeup_fd_posix.c", 
-      "src/core/iomgr/wakeup_fd_posix.h", 
-      "src/core/iomgr/workqueue.h", 
-      "src/core/iomgr/workqueue_posix.c", 
-      "src/core/iomgr/workqueue_posix.h", 
-      "src/core/iomgr/workqueue_windows.c", 
-      "src/core/iomgr/workqueue_windows.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/proto/grpc/lb/v0/load_balancer.pb.c", 
-      "src/core/proto/grpc/lb/v0/load_balancer.pb.h", 
-      "src/core/statistics/census_interface.h", 
-      "src/core/statistics/census_rpc_stats.h", 
-      "src/core/surface/alarm.c", 
-      "src/core/surface/api_trace.c", 
-      "src/core/surface/api_trace.h", 
-      "src/core/surface/byte_buffer.c", 
-      "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/call_test_only.h", 
-      "src/core/surface/channel.c", 
-      "src/core/surface/channel.h", 
-      "src/core/surface/channel_connectivity.c", 
-      "src/core/surface/channel_create.c", 
-      "src/core/surface/channel_ping.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.h", 
-      "src/core/surface/validate_metadata.c", 
-      "src/core/surface/version.c", 
-      "src/core/transport/byte_stream.c", 
-      "src/core/transport/byte_stream.h", 
-      "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_encoder.c", 
-      "src/core/transport/chttp2/hpack_encoder.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_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/metadata_batch.c", 
-      "src/core/transport/metadata_batch.h", 
-      "src/core/transport/static_metadata.c", 
-      "src/core/transport/static_metadata.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/ext/transport/chttp2/client/insecure/channel_create.c", 
+      "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c", 
+      "src/core/ext/transport/chttp2/transport/alpn.c", 
+      "src/core/ext/transport/chttp2/transport/alpn.h", 
+      "src/core/ext/transport/chttp2/transport/bin_encoder.c", 
+      "src/core/ext/transport/chttp2/transport/bin_encoder.h", 
+      "src/core/ext/transport/chttp2/transport/chttp2_transport.c", 
+      "src/core/ext/transport/chttp2/transport/chttp2_transport.h", 
+      "src/core/ext/transport/chttp2/transport/frame.h", 
+      "src/core/ext/transport/chttp2/transport/frame_data.c", 
+      "src/core/ext/transport/chttp2/transport/frame_data.h", 
+      "src/core/ext/transport/chttp2/transport/frame_goaway.c", 
+      "src/core/ext/transport/chttp2/transport/frame_goaway.h", 
+      "src/core/ext/transport/chttp2/transport/frame_ping.c", 
+      "src/core/ext/transport/chttp2/transport/frame_ping.h", 
+      "src/core/ext/transport/chttp2/transport/frame_rst_stream.c", 
+      "src/core/ext/transport/chttp2/transport/frame_rst_stream.h", 
+      "src/core/ext/transport/chttp2/transport/frame_settings.c", 
+      "src/core/ext/transport/chttp2/transport/frame_settings.h", 
+      "src/core/ext/transport/chttp2/transport/frame_window_update.c", 
+      "src/core/ext/transport/chttp2/transport/frame_window_update.h", 
+      "src/core/ext/transport/chttp2/transport/hpack_encoder.c", 
+      "src/core/ext/transport/chttp2/transport/hpack_encoder.h", 
+      "src/core/ext/transport/chttp2/transport/hpack_parser.c", 
+      "src/core/ext/transport/chttp2/transport/hpack_parser.h", 
+      "src/core/ext/transport/chttp2/transport/hpack_table.c", 
+      "src/core/ext/transport/chttp2/transport/hpack_table.h", 
+      "src/core/ext/transport/chttp2/transport/http2_errors.h", 
+      "src/core/ext/transport/chttp2/transport/huffsyms.c", 
+      "src/core/ext/transport/chttp2/transport/huffsyms.h", 
+      "src/core/ext/transport/chttp2/transport/incoming_metadata.c", 
+      "src/core/ext/transport/chttp2/transport/incoming_metadata.h", 
+      "src/core/ext/transport/chttp2/transport/internal.h", 
+      "src/core/ext/transport/chttp2/transport/parsing.c", 
+      "src/core/ext/transport/chttp2/transport/status_conversion.c", 
+      "src/core/ext/transport/chttp2/transport/status_conversion.h", 
+      "src/core/ext/transport/chttp2/transport/stream_lists.c", 
+      "src/core/ext/transport/chttp2/transport/stream_map.c", 
+      "src/core/ext/transport/chttp2/transport/stream_map.h", 
+      "src/core/ext/transport/chttp2/transport/timeout_encoding.c", 
+      "src/core/ext/transport/chttp2/transport/timeout_encoding.h", 
+      "src/core/ext/transport/chttp2/transport/varint.c", 
+      "src/core/ext/transport/chttp2/transport/varint.h", 
+      "src/core/ext/transport/chttp2/transport/writing.c", 
+      "src/core/lib/census/aggregation.h", 
+      "src/core/lib/census/context.c", 
+      "src/core/lib/census/grpc_context.c", 
+      "src/core/lib/census/grpc_filter.c", 
+      "src/core/lib/census/grpc_filter.h", 
+      "src/core/lib/census/grpc_plugin.c", 
+      "src/core/lib/census/grpc_plugin.h", 
+      "src/core/lib/census/initialize.c", 
+      "src/core/lib/census/mlog.c", 
+      "src/core/lib/census/mlog.h", 
+      "src/core/lib/census/operation.c", 
+      "src/core/lib/census/placeholders.c", 
+      "src/core/lib/census/rpc_metric_id.h", 
+      "src/core/lib/census/tracing.c", 
+      "src/core/lib/channel/channel_args.c", 
+      "src/core/lib/channel/channel_args.h", 
+      "src/core/lib/channel/channel_stack.c", 
+      "src/core/lib/channel/channel_stack.h", 
+      "src/core/lib/channel/channel_stack_builder.c", 
+      "src/core/lib/channel/channel_stack_builder.h", 
+      "src/core/lib/channel/client_channel.c", 
+      "src/core/lib/channel/client_channel.h", 
+      "src/core/lib/channel/compress_filter.c", 
+      "src/core/lib/channel/compress_filter.h", 
+      "src/core/lib/channel/connected_channel.c", 
+      "src/core/lib/channel/connected_channel.h", 
+      "src/core/lib/channel/context.h", 
+      "src/core/lib/channel/http_client_filter.c", 
+      "src/core/lib/channel/http_client_filter.h", 
+      "src/core/lib/channel/http_server_filter.c", 
+      "src/core/lib/channel/http_server_filter.h", 
+      "src/core/lib/channel/subchannel_call_holder.c", 
+      "src/core/lib/channel/subchannel_call_holder.h", 
+      "src/core/lib/client_config/client_config.c", 
+      "src/core/lib/client_config/client_config.h", 
+      "src/core/lib/client_config/connector.c", 
+      "src/core/lib/client_config/connector.h", 
+      "src/core/lib/client_config/default_initial_connect_string.c", 
+      "src/core/lib/client_config/initial_connect_string.c", 
+      "src/core/lib/client_config/initial_connect_string.h", 
+      "src/core/lib/client_config/lb_policies/load_balancer_api.c", 
+      "src/core/lib/client_config/lb_policies/load_balancer_api.h", 
+      "src/core/lib/client_config/lb_policies/pick_first.c", 
+      "src/core/lib/client_config/lb_policies/pick_first.h", 
+      "src/core/lib/client_config/lb_policies/round_robin.c", 
+      "src/core/lib/client_config/lb_policies/round_robin.h", 
+      "src/core/lib/client_config/lb_policy.c", 
+      "src/core/lib/client_config/lb_policy.h", 
+      "src/core/lib/client_config/lb_policy_factory.c", 
+      "src/core/lib/client_config/lb_policy_factory.h", 
+      "src/core/lib/client_config/lb_policy_registry.c", 
+      "src/core/lib/client_config/lb_policy_registry.h", 
+      "src/core/lib/client_config/resolver.c", 
+      "src/core/lib/client_config/resolver.h", 
+      "src/core/lib/client_config/resolver_factory.c", 
+      "src/core/lib/client_config/resolver_factory.h", 
+      "src/core/lib/client_config/resolver_registry.c", 
+      "src/core/lib/client_config/resolver_registry.h", 
+      "src/core/lib/client_config/resolvers/dns_resolver.c", 
+      "src/core/lib/client_config/resolvers/dns_resolver.h", 
+      "src/core/lib/client_config/resolvers/sockaddr_resolver.c", 
+      "src/core/lib/client_config/resolvers/sockaddr_resolver.h", 
+      "src/core/lib/client_config/subchannel.c", 
+      "src/core/lib/client_config/subchannel.h", 
+      "src/core/lib/client_config/subchannel_factory.c", 
+      "src/core/lib/client_config/subchannel_factory.h", 
+      "src/core/lib/client_config/subchannel_index.c", 
+      "src/core/lib/client_config/subchannel_index.h", 
+      "src/core/lib/client_config/uri_parser.c", 
+      "src/core/lib/client_config/uri_parser.h", 
+      "src/core/lib/compression/algorithm_metadata.h", 
+      "src/core/lib/compression/compression_algorithm.c", 
+      "src/core/lib/compression/message_compress.c", 
+      "src/core/lib/compression/message_compress.h", 
+      "src/core/lib/debug/trace.c", 
+      "src/core/lib/debug/trace.h", 
+      "src/core/lib/http/format_request.c", 
+      "src/core/lib/http/format_request.h", 
+      "src/core/lib/http/httpcli.c", 
+      "src/core/lib/http/httpcli.h", 
+      "src/core/lib/http/parser.c", 
+      "src/core/lib/http/parser.h", 
+      "src/core/lib/iomgr/closure.c", 
+      "src/core/lib/iomgr/closure.h", 
+      "src/core/lib/iomgr/endpoint.c", 
+      "src/core/lib/iomgr/endpoint.h", 
+      "src/core/lib/iomgr/endpoint_pair.h", 
+      "src/core/lib/iomgr/endpoint_pair_posix.c", 
+      "src/core/lib/iomgr/endpoint_pair_windows.c", 
+      "src/core/lib/iomgr/exec_ctx.c", 
+      "src/core/lib/iomgr/exec_ctx.h", 
+      "src/core/lib/iomgr/executor.c", 
+      "src/core/lib/iomgr/executor.h", 
+      "src/core/lib/iomgr/fd_posix.c", 
+      "src/core/lib/iomgr/fd_posix.h", 
+      "src/core/lib/iomgr/iocp_windows.c", 
+      "src/core/lib/iomgr/iocp_windows.h", 
+      "src/core/lib/iomgr/iomgr.c", 
+      "src/core/lib/iomgr/iomgr.h", 
+      "src/core/lib/iomgr/iomgr_internal.h", 
+      "src/core/lib/iomgr/iomgr_posix.c", 
+      "src/core/lib/iomgr/iomgr_posix.h", 
+      "src/core/lib/iomgr/iomgr_windows.c", 
+      "src/core/lib/iomgr/pollset.h", 
+      "src/core/lib/iomgr/pollset_multipoller_with_epoll.c", 
+      "src/core/lib/iomgr/pollset_multipoller_with_poll_posix.c", 
+      "src/core/lib/iomgr/pollset_posix.c", 
+      "src/core/lib/iomgr/pollset_posix.h", 
+      "src/core/lib/iomgr/pollset_set.h", 
+      "src/core/lib/iomgr/pollset_set_posix.c", 
+      "src/core/lib/iomgr/pollset_set_posix.h", 
+      "src/core/lib/iomgr/pollset_set_windows.c", 
+      "src/core/lib/iomgr/pollset_set_windows.h", 
+      "src/core/lib/iomgr/pollset_windows.c", 
+      "src/core/lib/iomgr/pollset_windows.h", 
+      "src/core/lib/iomgr/resolve_address.h", 
+      "src/core/lib/iomgr/resolve_address_posix.c", 
+      "src/core/lib/iomgr/resolve_address_windows.c", 
+      "src/core/lib/iomgr/sockaddr.h", 
+      "src/core/lib/iomgr/sockaddr_posix.h", 
+      "src/core/lib/iomgr/sockaddr_utils.c", 
+      "src/core/lib/iomgr/sockaddr_utils.h", 
+      "src/core/lib/iomgr/sockaddr_win32.h", 
+      "src/core/lib/iomgr/socket_utils_common_posix.c", 
+      "src/core/lib/iomgr/socket_utils_linux.c", 
+      "src/core/lib/iomgr/socket_utils_posix.c", 
+      "src/core/lib/iomgr/socket_utils_posix.h", 
+      "src/core/lib/iomgr/socket_windows.c", 
+      "src/core/lib/iomgr/socket_windows.h", 
+      "src/core/lib/iomgr/tcp_client.h", 
+      "src/core/lib/iomgr/tcp_client_posix.c", 
+      "src/core/lib/iomgr/tcp_client_windows.c", 
+      "src/core/lib/iomgr/tcp_posix.c", 
+      "src/core/lib/iomgr/tcp_posix.h", 
+      "src/core/lib/iomgr/tcp_server.h", 
+      "src/core/lib/iomgr/tcp_server_posix.c", 
+      "src/core/lib/iomgr/tcp_server_windows.c", 
+      "src/core/lib/iomgr/tcp_windows.c", 
+      "src/core/lib/iomgr/tcp_windows.h", 
+      "src/core/lib/iomgr/time_averaged_stats.c", 
+      "src/core/lib/iomgr/time_averaged_stats.h", 
+      "src/core/lib/iomgr/timer.c", 
+      "src/core/lib/iomgr/timer.h", 
+      "src/core/lib/iomgr/timer_heap.c", 
+      "src/core/lib/iomgr/timer_heap.h", 
+      "src/core/lib/iomgr/udp_server.c", 
+      "src/core/lib/iomgr/udp_server.h", 
+      "src/core/lib/iomgr/unix_sockets_posix.c", 
+      "src/core/lib/iomgr/unix_sockets_posix.h", 
+      "src/core/lib/iomgr/unix_sockets_posix_noop.c", 
+      "src/core/lib/iomgr/wakeup_fd_eventfd.c", 
+      "src/core/lib/iomgr/wakeup_fd_nospecial.c", 
+      "src/core/lib/iomgr/wakeup_fd_pipe.c", 
+      "src/core/lib/iomgr/wakeup_fd_pipe.h", 
+      "src/core/lib/iomgr/wakeup_fd_posix.c", 
+      "src/core/lib/iomgr/wakeup_fd_posix.h", 
+      "src/core/lib/iomgr/workqueue.h", 
+      "src/core/lib/iomgr/workqueue_posix.c", 
+      "src/core/lib/iomgr/workqueue_posix.h", 
+      "src/core/lib/iomgr/workqueue_windows.c", 
+      "src/core/lib/iomgr/workqueue_windows.h", 
+      "src/core/lib/json/json.c", 
+      "src/core/lib/json/json.h", 
+      "src/core/lib/json/json_common.h", 
+      "src/core/lib/json/json_reader.c", 
+      "src/core/lib/json/json_reader.h", 
+      "src/core/lib/json/json_string.c", 
+      "src/core/lib/json/json_writer.c", 
+      "src/core/lib/json/json_writer.h", 
+      "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.c", 
+      "src/core/lib/proto/grpc/lb/v0/load_balancer.pb.h", 
+      "src/core/lib/statistics/census_interface.h", 
+      "src/core/lib/statistics/census_rpc_stats.h", 
+      "src/core/lib/surface/alarm.c", 
+      "src/core/lib/surface/api_trace.c", 
+      "src/core/lib/surface/api_trace.h", 
+      "src/core/lib/surface/byte_buffer.c", 
+      "src/core/lib/surface/byte_buffer_reader.c", 
+      "src/core/lib/surface/call.c", 
+      "src/core/lib/surface/call.h", 
+      "src/core/lib/surface/call_details.c", 
+      "src/core/lib/surface/call_log_batch.c", 
+      "src/core/lib/surface/call_test_only.h", 
+      "src/core/lib/surface/channel.c", 
+      "src/core/lib/surface/channel.h", 
+      "src/core/lib/surface/channel_connectivity.c", 
+      "src/core/lib/surface/channel_init.c", 
+      "src/core/lib/surface/channel_init.h", 
+      "src/core/lib/surface/channel_ping.c", 
+      "src/core/lib/surface/channel_stack_type.c", 
+      "src/core/lib/surface/channel_stack_type.h", 
+      "src/core/lib/surface/completion_queue.c", 
+      "src/core/lib/surface/completion_queue.h", 
+      "src/core/lib/surface/event_string.c", 
+      "src/core/lib/surface/event_string.h", 
+      "src/core/lib/surface/init.c", 
+      "src/core/lib/surface/init.h", 
+      "src/core/lib/surface/init_unsecure.c", 
+      "src/core/lib/surface/lame_client.c", 
+      "src/core/lib/surface/lame_client.h", 
+      "src/core/lib/surface/metadata_array.c", 
+      "src/core/lib/surface/server.c", 
+      "src/core/lib/surface/server.h", 
+      "src/core/lib/surface/surface_trace.h", 
+      "src/core/lib/surface/validate_metadata.c", 
+      "src/core/lib/surface/version.c", 
+      "src/core/lib/transport/byte_stream.c", 
+      "src/core/lib/transport/byte_stream.h", 
+      "src/core/lib/transport/connectivity_state.c", 
+      "src/core/lib/transport/connectivity_state.h", 
+      "src/core/lib/transport/metadata.c", 
+      "src/core/lib/transport/metadata.h", 
+      "src/core/lib/transport/metadata_batch.c", 
+      "src/core/lib/transport/metadata_batch.h", 
+      "src/core/lib/transport/static_metadata.c", 
+      "src/core/lib/transport/static_metadata.h", 
+      "src/core/lib/transport/transport.c", 
+      "src/core/lib/transport/transport.h", 
+      "src/core/lib/transport/transport_impl.h", 
+      "src/core/lib/transport/transport_op_string.c"
     ], 
     "third_party": false, 
     "type": "lib"
@@ -4815,14 +5034,14 @@
     ], 
     "headers": [
       "include/grpc/grpc_zookeeper.h", 
-      "src/core/client_config/resolvers/zookeeper_resolver.h"
+      "src/core/lib/client_config/resolvers/zookeeper_resolver.h"
     ], 
     "language": "c", 
     "name": "grpc_zookeeper", 
     "src": [
       "include/grpc/grpc_zookeeper.h", 
-      "src/core/client_config/resolvers/zookeeper_resolver.c", 
-      "src/core/client_config/resolvers/zookeeper_resolver.h"
+      "src/core/lib/client_config/resolvers/zookeeper_resolver.c", 
+      "src/core/lib/client_config/resolvers/zookeeper_resolver.h"
     ], 
     "third_party": false, 
     "type": "lib"
@@ -4892,6 +5111,7 @@
       "include/grpc++/impl/codegen/completion_queue_tag.h", 
       "include/grpc++/impl/codegen/config.h", 
       "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpc++/impl/codegen/core_codegen_interface.h", 
       "include/grpc++/impl/codegen/grpc_library.h", 
       "include/grpc++/impl/codegen/method_handler_impl.h", 
       "include/grpc++/impl/codegen/proto_utils.h", 
@@ -4947,6 +5167,7 @@
       "include/grpc++/support/time.h", 
       "src/cpp/client/create_channel_internal.h", 
       "src/cpp/client/secure_credentials.h", 
+      "src/cpp/common/core_codegen.h", 
       "src/cpp/common/create_auth_context.h", 
       "src/cpp/common/secure_auth_context.h", 
       "src/cpp/server/dynamic_thread_pool.h", 
@@ -4977,6 +5198,7 @@
       "include/grpc++/impl/codegen/completion_queue_tag.h", 
       "include/grpc++/impl/codegen/config.h", 
       "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpc++/impl/codegen/core_codegen_interface.h", 
       "include/grpc++/impl/codegen/grpc_library.h", 
       "include/grpc++/impl/codegen/method_handler_impl.h", 
       "include/grpc++/impl/codegen/proto_utils.h", 
@@ -5040,18 +5262,18 @@
       "src/cpp/client/insecure_credentials.cc", 
       "src/cpp/client/secure_credentials.cc", 
       "src/cpp/client/secure_credentials.h", 
-      "src/cpp/codegen/grpc_library.cc", 
+      "src/cpp/codegen/codegen_init.cc", 
       "src/cpp/common/auth_property_iterator.cc", 
-      "src/cpp/common/call.cc", 
       "src/cpp/common/channel_arguments.cc", 
       "src/cpp/common/completion_queue.cc", 
+      "src/cpp/common/core_codegen.cc", 
+      "src/cpp/common/core_codegen.h", 
       "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_channel_arguments.cc", 
       "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/dynamic_thread_pool.cc", 
@@ -5076,6 +5298,120 @@
   {
     "deps": [], 
     "headers": [
+      "include/grpc++/impl/codegen/async_stream.h", 
+      "include/grpc++/impl/codegen/async_unary_call.h", 
+      "include/grpc++/impl/codegen/call.h", 
+      "include/grpc++/impl/codegen/call_hook.h", 
+      "include/grpc++/impl/codegen/channel_interface.h", 
+      "include/grpc++/impl/codegen/client_context.h", 
+      "include/grpc++/impl/codegen/client_unary_call.h", 
+      "include/grpc++/impl/codegen/completion_queue.h", 
+      "include/grpc++/impl/codegen/completion_queue_tag.h", 
+      "include/grpc++/impl/codegen/config.h", 
+      "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpc++/impl/codegen/core_codegen_interface.h", 
+      "include/grpc++/impl/codegen/grpc_library.h", 
+      "include/grpc++/impl/codegen/method_handler_impl.h", 
+      "include/grpc++/impl/codegen/proto_utils.h", 
+      "include/grpc++/impl/codegen/rpc_method.h", 
+      "include/grpc++/impl/codegen/rpc_service_method.h", 
+      "include/grpc++/impl/codegen/security/auth_context.h", 
+      "include/grpc++/impl/codegen/serialization_traits.h", 
+      "include/grpc++/impl/codegen/server_context.h", 
+      "include/grpc++/impl/codegen/server_interface.h", 
+      "include/grpc++/impl/codegen/service_type.h", 
+      "include/grpc++/impl/codegen/status.h", 
+      "include/grpc++/impl/codegen/status_code_enum.h", 
+      "include/grpc++/impl/codegen/string_ref.h", 
+      "include/grpc++/impl/codegen/stub_options.h", 
+      "include/grpc++/impl/codegen/sync.h", 
+      "include/grpc++/impl/codegen/sync_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_no_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_stream.h", 
+      "include/grpc++/impl/codegen/time.h", 
+      "include/grpc/impl/codegen/alloc.h", 
+      "include/grpc/impl/codegen/atm.h", 
+      "include/grpc/impl/codegen/atm_gcc_atomic.h", 
+      "include/grpc/impl/codegen/atm_gcc_sync.h", 
+      "include/grpc/impl/codegen/atm_win32.h", 
+      "include/grpc/impl/codegen/byte_buffer.h", 
+      "include/grpc/impl/codegen/compression_types.h", 
+      "include/grpc/impl/codegen/connectivity_state.h", 
+      "include/grpc/impl/codegen/grpc_types.h", 
+      "include/grpc/impl/codegen/log.h", 
+      "include/grpc/impl/codegen/port_platform.h", 
+      "include/grpc/impl/codegen/propagation_bits.h", 
+      "include/grpc/impl/codegen/slice.h", 
+      "include/grpc/impl/codegen/slice_buffer.h", 
+      "include/grpc/impl/codegen/status.h", 
+      "include/grpc/impl/codegen/sync.h", 
+      "include/grpc/impl/codegen/sync_generic.h", 
+      "include/grpc/impl/codegen/sync_posix.h", 
+      "include/grpc/impl/codegen/sync_win32.h", 
+      "include/grpc/impl/codegen/time.h"
+    ], 
+    "language": "c++", 
+    "name": "grpc++_codegen_lib", 
+    "src": [
+      "include/grpc++/impl/codegen/async_stream.h", 
+      "include/grpc++/impl/codegen/async_unary_call.h", 
+      "include/grpc++/impl/codegen/call.h", 
+      "include/grpc++/impl/codegen/call_hook.h", 
+      "include/grpc++/impl/codegen/channel_interface.h", 
+      "include/grpc++/impl/codegen/client_context.h", 
+      "include/grpc++/impl/codegen/client_unary_call.h", 
+      "include/grpc++/impl/codegen/completion_queue.h", 
+      "include/grpc++/impl/codegen/completion_queue_tag.h", 
+      "include/grpc++/impl/codegen/config.h", 
+      "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpc++/impl/codegen/core_codegen_interface.h", 
+      "include/grpc++/impl/codegen/grpc_library.h", 
+      "include/grpc++/impl/codegen/method_handler_impl.h", 
+      "include/grpc++/impl/codegen/proto_utils.h", 
+      "include/grpc++/impl/codegen/rpc_method.h", 
+      "include/grpc++/impl/codegen/rpc_service_method.h", 
+      "include/grpc++/impl/codegen/security/auth_context.h", 
+      "include/grpc++/impl/codegen/serialization_traits.h", 
+      "include/grpc++/impl/codegen/server_context.h", 
+      "include/grpc++/impl/codegen/server_interface.h", 
+      "include/grpc++/impl/codegen/service_type.h", 
+      "include/grpc++/impl/codegen/status.h", 
+      "include/grpc++/impl/codegen/status_code_enum.h", 
+      "include/grpc++/impl/codegen/string_ref.h", 
+      "include/grpc++/impl/codegen/stub_options.h", 
+      "include/grpc++/impl/codegen/sync.h", 
+      "include/grpc++/impl/codegen/sync_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_no_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_stream.h", 
+      "include/grpc++/impl/codegen/time.h", 
+      "include/grpc/impl/codegen/alloc.h", 
+      "include/grpc/impl/codegen/atm.h", 
+      "include/grpc/impl/codegen/atm_gcc_atomic.h", 
+      "include/grpc/impl/codegen/atm_gcc_sync.h", 
+      "include/grpc/impl/codegen/atm_win32.h", 
+      "include/grpc/impl/codegen/byte_buffer.h", 
+      "include/grpc/impl/codegen/compression_types.h", 
+      "include/grpc/impl/codegen/connectivity_state.h", 
+      "include/grpc/impl/codegen/grpc_types.h", 
+      "include/grpc/impl/codegen/log.h", 
+      "include/grpc/impl/codegen/port_platform.h", 
+      "include/grpc/impl/codegen/propagation_bits.h", 
+      "include/grpc/impl/codegen/slice.h", 
+      "include/grpc/impl/codegen/slice_buffer.h", 
+      "include/grpc/impl/codegen/status.h", 
+      "include/grpc/impl/codegen/sync.h", 
+      "include/grpc/impl/codegen/sync_generic.h", 
+      "include/grpc/impl/codegen/sync_posix.h", 
+      "include/grpc/impl/codegen/sync_win32.h", 
+      "include/grpc/impl/codegen/time.h", 
+      "src/cpp/codegen/codegen_init.cc"
+    ], 
+    "third_party": false, 
+    "type": "lib"
+  }, 
+  {
+    "deps": [], 
+    "headers": [
       "test/cpp/util/test_config.h"
     ], 
     "language": "c++", 
@@ -5155,6 +5491,7 @@
       "include/grpc++/impl/codegen/completion_queue_tag.h", 
       "include/grpc++/impl/codegen/config.h", 
       "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpc++/impl/codegen/core_codegen_interface.h", 
       "include/grpc++/impl/codegen/grpc_library.h", 
       "include/grpc++/impl/codegen/method_handler_impl.h", 
       "include/grpc++/impl/codegen/proto_utils.h", 
@@ -5209,6 +5546,7 @@
       "include/grpc++/support/sync_stream.h", 
       "include/grpc++/support/time.h", 
       "src/cpp/client/create_channel_internal.h", 
+      "src/cpp/common/core_codegen.h", 
       "src/cpp/common/create_auth_context.h", 
       "src/cpp/server/dynamic_thread_pool.h", 
       "src/cpp/server/thread_pool_interface.h"
@@ -5237,6 +5575,7 @@
       "include/grpc++/impl/codegen/completion_queue_tag.h", 
       "include/grpc++/impl/codegen/config.h", 
       "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpc++/impl/codegen/core_codegen_interface.h", 
       "include/grpc++/impl/codegen/grpc_library.h", 
       "include/grpc++/impl/codegen/method_handler_impl.h", 
       "include/grpc++/impl/codegen/proto_utils.h", 
@@ -5298,14 +5637,14 @@
       "src/cpp/client/credentials.cc", 
       "src/cpp/client/generic_stub.cc", 
       "src/cpp/client/insecure_credentials.cc", 
-      "src/cpp/codegen/grpc_library.cc", 
-      "src/cpp/common/call.cc", 
+      "src/cpp/codegen/codegen_init.cc", 
       "src/cpp/common/channel_arguments.cc", 
       "src/cpp/common/completion_queue.cc", 
+      "src/cpp/common/core_codegen.cc", 
+      "src/cpp/common/core_codegen.h", 
       "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/dynamic_thread_pool.cc", 
@@ -5326,38 +5665,10 @@
     "type": "lib"
   }, 
   {
-    "deps": [], 
+    "deps": [
+      "grpc++_codegen_lib"
+    ], 
     "headers": [
-      "include/grpc++/impl/codegen/async_stream.h", 
-      "include/grpc++/impl/codegen/async_unary_call.h", 
-      "include/grpc++/impl/codegen/call.h", 
-      "include/grpc++/impl/codegen/call_hook.h", 
-      "include/grpc++/impl/codegen/channel_interface.h", 
-      "include/grpc++/impl/codegen/client_context.h", 
-      "include/grpc++/impl/codegen/client_unary_call.h", 
-      "include/grpc++/impl/codegen/completion_queue.h", 
-      "include/grpc++/impl/codegen/completion_queue_tag.h", 
-      "include/grpc++/impl/codegen/config.h", 
-      "include/grpc++/impl/codegen/config_protobuf.h", 
-      "include/grpc++/impl/codegen/grpc_library.h", 
-      "include/grpc++/impl/codegen/method_handler_impl.h", 
-      "include/grpc++/impl/codegen/proto_utils.h", 
-      "include/grpc++/impl/codegen/rpc_method.h", 
-      "include/grpc++/impl/codegen/rpc_service_method.h", 
-      "include/grpc++/impl/codegen/security/auth_context.h", 
-      "include/grpc++/impl/codegen/serialization_traits.h", 
-      "include/grpc++/impl/codegen/server_context.h", 
-      "include/grpc++/impl/codegen/server_interface.h", 
-      "include/grpc++/impl/codegen/service_type.h", 
-      "include/grpc++/impl/codegen/status.h", 
-      "include/grpc++/impl/codegen/status_code_enum.h", 
-      "include/grpc++/impl/codegen/string_ref.h", 
-      "include/grpc++/impl/codegen/stub_options.h", 
-      "include/grpc++/impl/codegen/sync.h", 
-      "include/grpc++/impl/codegen/sync_cxx11.h", 
-      "include/grpc++/impl/codegen/sync_no_cxx11.h", 
-      "include/grpc++/impl/codegen/sync_stream.h", 
-      "include/grpc++/impl/codegen/time.h", 
       "include/grpc++/support/config.h", 
       "include/grpc++/support/config_protobuf.h", 
       "include/grpc/impl/codegen/alloc.h", 
@@ -5365,16 +5676,10 @@
       "include/grpc/impl/codegen/atm_gcc_atomic.h", 
       "include/grpc/impl/codegen/atm_gcc_sync.h", 
       "include/grpc/impl/codegen/atm_win32.h", 
-      "include/grpc/impl/codegen/byte_buffer.h", 
-      "include/grpc/impl/codegen/compression_types.h", 
-      "include/grpc/impl/codegen/connectivity_state.h", 
-      "include/grpc/impl/codegen/grpc_types.h", 
       "include/grpc/impl/codegen/log.h", 
       "include/grpc/impl/codegen/port_platform.h", 
-      "include/grpc/impl/codegen/propagation_bits.h", 
       "include/grpc/impl/codegen/slice.h", 
       "include/grpc/impl/codegen/slice_buffer.h", 
-      "include/grpc/impl/codegen/status.h", 
       "include/grpc/impl/codegen/sync.h", 
       "include/grpc/impl/codegen/sync_generic.h", 
       "include/grpc/impl/codegen/sync_posix.h", 
@@ -5397,36 +5702,6 @@
     "language": "c++", 
     "name": "grpc_plugin_support", 
     "src": [
-      "include/grpc++/impl/codegen/async_stream.h", 
-      "include/grpc++/impl/codegen/async_unary_call.h", 
-      "include/grpc++/impl/codegen/call.h", 
-      "include/grpc++/impl/codegen/call_hook.h", 
-      "include/grpc++/impl/codegen/channel_interface.h", 
-      "include/grpc++/impl/codegen/client_context.h", 
-      "include/grpc++/impl/codegen/client_unary_call.h", 
-      "include/grpc++/impl/codegen/completion_queue.h", 
-      "include/grpc++/impl/codegen/completion_queue_tag.h", 
-      "include/grpc++/impl/codegen/config.h", 
-      "include/grpc++/impl/codegen/config_protobuf.h", 
-      "include/grpc++/impl/codegen/grpc_library.h", 
-      "include/grpc++/impl/codegen/method_handler_impl.h", 
-      "include/grpc++/impl/codegen/proto_utils.h", 
-      "include/grpc++/impl/codegen/rpc_method.h", 
-      "include/grpc++/impl/codegen/rpc_service_method.h", 
-      "include/grpc++/impl/codegen/security/auth_context.h", 
-      "include/grpc++/impl/codegen/serialization_traits.h", 
-      "include/grpc++/impl/codegen/server_context.h", 
-      "include/grpc++/impl/codegen/server_interface.h", 
-      "include/grpc++/impl/codegen/service_type.h", 
-      "include/grpc++/impl/codegen/status.h", 
-      "include/grpc++/impl/codegen/status_code_enum.h", 
-      "include/grpc++/impl/codegen/string_ref.h", 
-      "include/grpc++/impl/codegen/stub_options.h", 
-      "include/grpc++/impl/codegen/sync.h", 
-      "include/grpc++/impl/codegen/sync_cxx11.h", 
-      "include/grpc++/impl/codegen/sync_no_cxx11.h", 
-      "include/grpc++/impl/codegen/sync_stream.h", 
-      "include/grpc++/impl/codegen/time.h", 
       "include/grpc++/support/config.h", 
       "include/grpc++/support/config_protobuf.h", 
       "include/grpc/impl/codegen/alloc.h", 
@@ -5434,16 +5709,10 @@
       "include/grpc/impl/codegen/atm_gcc_atomic.h", 
       "include/grpc/impl/codegen/atm_gcc_sync.h", 
       "include/grpc/impl/codegen/atm_win32.h", 
-      "include/grpc/impl/codegen/byte_buffer.h", 
-      "include/grpc/impl/codegen/compression_types.h", 
-      "include/grpc/impl/codegen/connectivity_state.h", 
-      "include/grpc/impl/codegen/grpc_types.h", 
       "include/grpc/impl/codegen/log.h", 
       "include/grpc/impl/codegen/port_platform.h", 
-      "include/grpc/impl/codegen/propagation_bits.h", 
       "include/grpc/impl/codegen/slice.h", 
       "include/grpc/impl/codegen/slice_buffer.h", 
-      "include/grpc/impl/codegen/status.h", 
       "include/grpc/impl/codegen/sync.h", 
       "include/grpc/impl/codegen/sync_generic.h", 
       "include/grpc/impl/codegen/sync_posix.h", 
@@ -5466,8 +5735,7 @@
       "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", 
-      "src/cpp/codegen/grpc_library.cc"
+      "src/compiler/ruby_generator_string-inl.h"
     ], 
     "third_party": false, 
     "type": "lib"
@@ -5793,6 +6061,18 @@
     ], 
     "headers": [], 
     "language": "c++", 
+    "name": "boringssl_asn1_test_lib", 
+    "src": [], 
+    "third_party": true, 
+    "type": "lib"
+  }, 
+  {
+    "deps": [
+      "boringssl", 
+      "boringssl_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
     "name": "boringssl_base64_test_lib", 
     "src": [], 
     "third_party": true, 
@@ -6267,7 +6547,6 @@
   }, 
   {
     "deps": [
-      "end2end_certs", 
       "gpr", 
       "gpr_test_util", 
       "grpc", 
@@ -6378,18 +6657,5 @@
     ], 
     "third_party": false, 
     "type": "lib"
-  }, 
-  {
-    "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"
-    ], 
-    "third_party": false, 
-    "type": "lib"
   }
 ]
diff --git a/tools/run_tests/stress_test/README.md b/tools/run_tests/stress_test/README.md
new file mode 100644
index 0000000..84f9719
--- /dev/null
+++ b/tools/run_tests/stress_test/README.md
@@ -0,0 +1,76 @@
+Running Stress tests on Google Container Engine

+=======================================

+

+### **Glossary**:

+* GCP: Google Cloud Platform

+* GCE: Google Compute Engine

+* GKE: Google Container Engine

+* GCP console: https://console.cloud.google.com

+

+### **Setup Instructions**

+#### *On GCP:*

+1. Login to GCP with your Google account (for example, your @gmail account) at https://cloud.google.com. If do not have a Google account, you will have to create an account first.

+2. Enable billing on Google cloud platform. Instructions [here](https://cloud.google.com/container-engine/docs/before-you-begin)  (see the '*Enable billing*' section).

+3. Create a Project from the [GCP console](https://console.cloud.google.com).i.e Click on the project dropdown box on the top right (to the right of the search box) and click '*Create a project*' option.

+4. Enable the Container Engine API. Instructions [here](https://cloud.google.com/container-engine/docs/before-you-begin)  (See the '*Enable the Container Engine API*’ section). Alternatively, you can do the following:

+    - Click on the '*Products & Services*' icon on the top left (i.e the icon with three small horizontal bars) and select '*API Manager*'

+    - Select the '*Container Engine API*' under '*Google Cloud APIs*' on the main page. Note that you might have to click on '*More*' under '*Google Cloud APIs*' to see the '*Container Engine API*' link

+    - Click on the '*Enable*' button. If the API is already enabled, the button's label would be '*Disable*' instead (do NOT click the button if its label is '*Disable*')

+5. Create a Cluster from the GCP console.

+    - Go to the Container Engine section from GCP console i.e: Click on the '*Products & Services*' icon on the top left (i.e the icon with three small horizontal bars) and click on '*Container Engine*'

+    - Click '*Create Container Cluster*' and follow the instructions.

+    - The instructions for 'Name/Zone/MachineType' etc are [here](https://cloud.google.com/container-engine/docs/clusters/operations) (**NOTE**: The page also has instructions to setting up default clusters and configuring `kubectl`. We will be doing that later)

+    - For the cluster size, a smaller size of < 10 GCE instances is good enough for our use cases - assuming that we are planning to run a reasonably small number of stress client instances. For the machine type, something like '2 vCPUs 7.5 GB' (available in the drop down box) should be good enough.

+    - **IMPORTANT**: Before hitting the '*Create*' button, click on '*More*' link just above the '*Create*' button and Select '*Enabled*' for BigQuery , '*Enabled*' for Cloud Platform and '*Read/Write*' for Cloud User Accounts.

+    - Create the cluster by clicking '*Create*' button.

+

+#### *On your machine* (or the machine from which stress tests on GKE are launched):

+1. You need a working gRPC repository on your machine. If you do not have it, clone the grpc repository from github (https://github.com/grpc/grpc) and follow the instructions [here](https://github.com/grpc/grpc/blob/master/INSTALL.md)

+2. Install Docker. Instructions [here](https://docs.docker.com/engine/installation/)

+3. Install Google Cloud SDK. Instructions [here](https://cloud.google.com/sdk/). This installs the `gcloud` tool

+4. Install `kubectl`, Kubernetes command line tool using `gcloud`. i.e

+    - `$ gcloud components update kubectl`

+    - NOTE: If you are running this from a GCE instance, the command may fail with the following error:

+    ```

+     You cannot perform this action because this Cloud SDK installation is 

+     managed by an external package manager. If you would like to get the

+     latest version, please see our main download page at:

+

+     https://developers.google.com/cloud/sdk/

+

+     ERROR: (gcloud.components.update) The component manager is disabled for this installation

+    ```

+    -- If so, you will have to manually install Cloud SDK by doing the following

+    ```shell

+      $ # The following installs latest Cloud SDK and updates the PATH

+      $ # (Accept the default values when prompted)

+      $ curl https://sdk.cloud.google.com | bash

+      $ exec -l $SHELL

+      $ # Set the defaults. Pick the default GCE credentials when prompted (The service account

+      $ # name will have a name similar to: "xxx-compute@developer.gserviceaccount.com")

+      $ gcloud init

+    ``` 

+

+5. Install Google python client apis:

+    - `‘$ sudo pip install --upgrade google-api-python-client’`

+    -  **Note**: Do `$ sudo apt-get install python-pip` (or `$ easy_install -U pip`) if you do not have pip

+6. Install the `requests` Python package if you don’t have it already by doing `sudo pip install requests`. More details regarding `requests` package are [here](http://docs.python-requests.org/en/master/user/install/)

+7. Set the `gcloud` defaults: See the instructions [here](https://cloud.google.com/container-engine/docs/before-you-begin) under "*Set gcloud defaults*" section)

+    - Make sure you also fetch the cluster credentials for `kubectl` command to use. I.e `$ gcloud container clusters get-credentials CLUSTER_NAME`

+

+### **Launching Stress tests**

+

+The stress tests are launched by the following script (path is relative to GRPC root directory) :

+`tools/run_tests/stress_test/run_stress_tests_on_gke.py`

+

+The script has several parameters and you can find out more details by using the `--help` flag.

+  - `<grpc_root_dir>$ tools/run_tests/stress_test/run_stress_tests_on_gke.py --help`

+

+> **Example**

+> ```bash

+> $ # Change to the grpc root directory

+> $ cd $GRPC_ROOT

+> $ tools/run_tests/stress_test/run_on_gke.py --project_id=sree-gce --config_file=tools/run_tests/stress_test/configs/opt.json

+> ```

+

+> The above runs the stress test on GKE under the project `sree-gce` in the default cluster (that you set by `gcloud` command earlier). The test settings (like number of client instances, servers, the parmeters to pass, test cases etc) are all loaded from the config file `$GRPC_ROOT/tools/run_tests/stress_test/opt.json`

diff --git a/tools/run_tests/stress_test/STRESS_CLIENT_SPEC.md b/tools/run_tests/stress_test/STRESS_CLIENT_SPEC.md
new file mode 100644
index 0000000..c4c9f14
--- /dev/null
+++ b/tools/run_tests/stress_test/STRESS_CLIENT_SPEC.md
@@ -0,0 +1,25 @@
+Stress Test client Specification

+=========================

+This document specifies the features a stress test client should implement in order to work with the stress testing framework. The stress test clients are executed against the existing interop test servers.

+

+**Requirements**

+--------------

+**1.** A stress test client should be able to repeatedly execute one or more of the existing 'interop test cases'. It may just be a wrapper around the existing interop test client. The exact command line arguments the client should support are listed in _Table 1_ below.

+

+**2.** The stress test client must implement a metrics server defined by _[metrics.proto](https://github.com/grpc/grpc/blob/master/src/proto/grpc/testing/metrics.proto)_ and must expose _qps_ as a long-valued Gauge. The client can track the overall _qps_ in one Gauge or in multiple Gagues (for example: One per Channel or Stub). 

+ The framework periodically queries the _qps_ by calling the `GetAllGauges()` method (the framework assumes that all the returned Gauges are _qps_ Gauges) and uses this to determine if the stress test client is running or crashed or stalled.

+> *Note:* In this context, the term  _**qps**_  means _interop test cases per second_  (not _messages per second_ or _rpc calls per second_)

+

+

+**Table 1:** Command line arguments that should be supported by the stress test client.

+

+>_**Note** The current C++ [stress client](https://github.com/grpc/grpc/blob/master/test/cpp/interop/stress_test.cc) supports more flags than those listed here but those flags will soon be deprecated_|

+

+Parameter             |                    Description

+----------------------|---------------------------------

+`--server_address`    | The stress client should accept a list of server addresses in the following format:<br> ```<name_1>:<port_1>,<name_2>:<port_2>..<name_N>:<port_N>``` <br> _Note:_ `<name>` can be either server name or IP address.<br><br>_Type:_ string <br>_default:_ ```localhost:8080``` <br>_Example:_ ``foo.foobar.com:8080,bar.foobar.com:8080`` <br><br> Currently, the stress test framework only passes one server address to the client.

+`--test_cases`        |   List of test cases along with the relative weights in the following format:<br> `<testcase_1:w_1>,<testcase_2:w_2>...<testcase_n:w_n>`. <br> The test cases names are the same as those currently used by the interop clients<br><br>_Type:_ string <br>_Example:_ `empty_unary:20,large_unary:10,empty_stream:70` <br>(The stress client would then make `empty_unary` calls 20% of the time, `large_unary` calls 10% of the time and `empty_stream` calls 70% of the time.) <br>_Note:_ The weights need not add up to 100.

+`--test_duration-secs`      | The test duration in seconds. A value of -1 means that the test should run forever until forcefully terminated. <br>_Type:_ int <br>_default:_ -1

+`--num_channels_per_server` | Number of channels (i.e connections) to each server. <br> _Type:_ int <br> _default:_ 1 <br><br> _Note:_ Unfortunately, the term `channel` is used differently in `grpc-java` and `C based grpc`. In this context, this really means "number of connections to the server"

+`--num_stubs_per_channel `  | Number of client stubs per each connection to server.<br>_Type:_ int <br>_default:_ 1

+`--metrics_port`            | The port at which the stress client exposes [QPS metrics](https://github.com/grpc/grpc/blob/master/src/proto/grpc/testing/metrics.proto). <br>_Type:_ int <br>_default:_ 8081

diff --git a/tools/run_tests/stress_test/configs/opt-tsan-asan.json b/tools/run_tests/stress_test/configs/opt-tsan-asan.json
new file mode 100644
index 0000000..1dc2d3f
--- /dev/null
+++ b/tools/run_tests/stress_test/configs/opt-tsan-asan.json
@@ -0,0 +1,135 @@
+{
+  "dockerImages": {
+    "grpc_stress_cxx_opt" : {
+      "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+      "dockerFileDir": "grpc_interop_stress_cxx",
+      "buildType": "opt"
+    },
+    "grpc_stress_cxx_tsan": {
+      "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+      "dockerFileDir": "grpc_interop_stress_cxx",
+      "buildType": "tsan"
+    },
+    "grpc_stress_cxx_asan": {
+      "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+      "dockerFileDir": "grpc_interop_stress_cxx",
+      "buildType": "asan"
+    }
+  },
+
+  "clientTemplates": {
+    "baseTemplates": {
+      "default": {
+        "wrapperScriptPath": "/var/local/git/grpc/tools/gcp/stress_test/run_client.py",
+        "pollIntervalSecs": 60,
+        "clientArgs": {
+          "num_channels_per_server":5,
+          "num_stubs_per_channel":10,
+          "test_cases": "empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1",
+          "metrics_port": 8081,
+          "metrics_collection_interval_secs":60
+        },
+        "metricsPort": 8081,
+        "metricsArgs": {
+          "metrics_server_address": "localhost:8081",
+          "total_only": "true"
+        }
+      }
+    },
+    "templates": {
+      "cxx_client_opt": {
+        "baseTemplate": "default",
+        "clientImagePath": "/var/local/git/grpc/bins/opt/stress_test",
+        "metricsClientImagePath": "/var/local/git/grpc/bins/opt/metrics_client"
+      },
+      "cxx_client_tsan": {
+        "baseTemplate": "default",
+        "clientImagePath": "/var/local/git/grpc/bins/tsan/stress_test",
+        "metricsClientImagePath": "/var/local/git/grpc/bins/tsan/metrics_client"
+      },
+    "cxx_client_asan": {
+        "baseTemplate": "default",
+        "clientImagePath": "/var/local/git/grpc/bins/asan/stress_test",
+        "metricsClientImagePath": "/var/local/git/grpc/bins/asan/metrics_client"
+      }
+    }
+  },
+
+  "serverTemplates": {
+    "baseTemplates":{
+      "default": {
+        "wrapperScriptPath": "/var/local/git/grpc/tools/gcp/stress_test/run_server.py",
+        "serverPort": 8080,
+        "serverArgs": {
+          "port": 8080
+        }
+      }
+    },
+    "templates": {
+      "cxx_server_opt": {
+        "baseTemplate": "default",
+        "serverImagePath": "/var/local/git/grpc/bins/opt/interop_server"
+      },
+      "cxx_server_tsan": {
+        "baseTemplate": "default",
+        "serverImagePath": "/var/local/git/grpc/bins/tsan/interop_server"
+      },
+    "cxx_server_asan": {
+        "baseTemplate": "default",
+        "serverImagePath": "/var/local/git/grpc/bins/asan/interop_server"
+      }
+    }
+  },
+
+  "testMatrix": {
+    "serverPodSpecs": {
+      "stress-server-opt": {
+        "serverTemplate": "cxx_server_opt",
+        "dockerImage": "grpc_stress_cxx_opt",
+        "numInstances": 1
+      },
+      "stress-server-tsan": {
+        "serverTemplate": "cxx_server_tsan",
+        "dockerImage": "grpc_stress_cxx_tsan",
+        "numInstances": 1
+      },
+      "stress-server-asan": {
+        "serverTemplate": "cxx_server_asan",
+        "dockerImage": "grpc_stress_cxx_asan",
+        "numInstances": 1
+      }
+   },
+
+    "clientPodSpecs": {
+      "stress-client-opt": {
+        "clientTemplate": "cxx_client_opt",
+        "dockerImage": "grpc_stress_cxx_opt",
+        "numInstances": 3,
+        "serverPodSpec": "stress-server-opt"
+      },
+      "stress-client-tsan": {
+        "clientTemplate": "cxx_client_tsan",
+        "dockerImage": "grpc_stress_cxx_tsan",
+        "numInstances": 3,
+        "serverPodSpec": "stress-server-tsan"
+      },
+      "stress-client-asan": {
+        "clientTemplate": "cxx_client_asan",
+        "dockerImage": "grpc_stress_cxx_asan",
+        "numInstances": 3,
+        "serverPodSpec": "stress-server-asan"
+      }
+    }
+  },
+
+  "globalSettings": {
+    "buildDockerImages": true,
+    "pollIntervalSecs": 60,
+    "testDurationSecs": 7200,
+    "kubernetesProxyPort": 8001,
+    "datasetIdNamePrefix": "stress_test_opt_tsan",
+    "summaryTableId": "summary",
+    "qpsTableId": "qps",
+    "podWarmupSecs": 60
+  }
+}
diff --git a/tools/run_tests/stress_test/configs/opt.json b/tools/run_tests/stress_test/configs/opt.json
new file mode 100644
index 0000000..7fc0240
--- /dev/null
+++ b/tools/run_tests/stress_test/configs/opt.json
@@ -0,0 +1,86 @@
+{
+  "dockerImages": {
+    "grpc_stress_cxx_opt" : {
+      "buildScript": "tools/jenkins/build_interop_stress_image.sh",
+      "dockerFileDir": "grpc_interop_stress_cxx",
+      "buildType": "opt"
+    }
+  },
+
+  "clientTemplates": {
+    "baseTemplates": {
+      "default": {
+        "wrapperScriptPath": "/var/local/git/grpc/tools/gcp/stress_test/run_client.py",
+        "pollIntervalSecs": 60,
+        "clientArgs": {
+          "num_channels_per_server":5,
+          "num_stubs_per_channel":10,
+          "test_cases": "empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1",
+          "metrics_port": 8081,
+          "metrics_collection_interval_secs":60
+        },
+        "metricsPort": 8081,
+        "metricsArgs": {
+          "metrics_server_address": "localhost:8081",
+          "total_only": "true"
+        }
+      }
+    },
+    "templates": {
+      "cxx_client_opt": {
+        "baseTemplate": "default",
+        "clientImagePath": "/var/local/git/grpc/bins/opt/stress_test",
+        "metricsClientImagePath": "/var/local/git/grpc/bins/opt/metrics_client"
+      }
+    }
+  },
+
+  "serverTemplates": {
+    "baseTemplates":{
+      "default": {
+        "wrapperScriptPath": "/var/local/git/grpc/tools/gcp/stress_test/run_server.py",
+        "serverPort": 8080,
+        "serverArgs": {
+          "port": 8080
+        }
+      }
+    },
+    "templates": {
+      "cxx_server_opt": {
+        "baseTemplate": "default",
+        "serverImagePath": "/var/local/git/grpc/bins/opt/interop_server"
+      }
+    }
+  },
+
+  "testMatrix": {
+    "serverPodSpecs": {
+      "stress-server-opt": {
+        "serverTemplate": "cxx_server_opt",
+        "dockerImage": "grpc_stress_cxx_opt",
+        "numInstances": 1
+      }
+    },
+
+    "clientPodSpecs": {
+      "stress-client-opt": {
+        "clientTemplate": "cxx_client_opt",
+        "dockerImage": "grpc_stress_cxx_opt",
+        "numInstances": 10,
+        "serverPodSpec": "stress-server-opt"
+      }
+    }
+  },
+
+  "globalSettings": {
+    "buildDockerImages": true,
+    "pollIntervalSecs": 10,
+    "testDurationSecs": 120,
+    "kubernetesProxyPort": 8001,
+    "datasetIdNamePrefix": "stress_test_opt",
+    "summaryTableId": "summary",
+    "qpsTableId": "qps",
+    "podWarmupSecs": 60
+  }
+}
+
diff --git a/tools/run_tests/stress_test/run_on_gke.py b/tools/run_tests/stress_test/run_on_gke.py
new file mode 100755
index 0000000..3a81c1a
--- /dev/null
+++ b/tools/run_tests/stress_test/run_on_gke.py
@@ -0,0 +1,636 @@
+#!/usr/bin/env python2.7
+# Copyright 2015-2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+import argparse
+import datetime
+import json
+import os
+import subprocess
+import sys
+import time
+
+stress_test_utils_dir = os.path.abspath(os.path.join(
+    os.path.dirname(__file__), '../../gcp/stress_test'))
+sys.path.append(stress_test_utils_dir)
+from stress_test_utils import BigQueryHelper
+
+kubernetes_api_dir = os.path.abspath(os.path.join(
+    os.path.dirname(__file__), '../../gcp/utils'))
+sys.path.append(kubernetes_api_dir)
+
+import kubernetes_api
+
+
+class GlobalSettings:
+
+  def __init__(self, gcp_project_id, build_docker_images,
+               test_poll_interval_secs, test_duration_secs,
+               kubernetes_proxy_port, dataset_id_prefix, summary_table_id,
+               qps_table_id, pod_warmup_secs):
+    self.gcp_project_id = gcp_project_id
+    self.build_docker_images = build_docker_images
+    self.test_poll_interval_secs = test_poll_interval_secs
+    self.test_duration_secs = test_duration_secs
+    self.kubernetes_proxy_port = kubernetes_proxy_port
+    self.dataset_id_prefix = dataset_id_prefix
+    self.summary_table_id = summary_table_id
+    self.qps_table_id = qps_table_id
+    self.pod_warmup_secs = pod_warmup_secs
+
+
+class ClientTemplate:
+  """ Contains all the common settings that are used by a stress client """
+
+  def __init__(self, name, client_image_path, metrics_client_image_path,
+               metrics_port, wrapper_script_path, poll_interval_secs,
+               client_args_dict, metrics_args_dict):
+    self.name = name
+    self.client_image_path = client_image_path
+    self.metrics_client_image_path = metrics_client_image_path
+    self.metrics_port = metrics_port
+    self.wrapper_script_path = wrapper_script_path
+    self.poll_interval_secs = poll_interval_secs
+    self.client_args_dict = client_args_dict
+    self.metrics_args_dict = metrics_args_dict
+
+
+class ServerTemplate:
+  """ Contains all the common settings used by a stress server """
+
+  def __init__(self, name, server_image_path, wrapper_script_path, server_port,
+               server_args_dict):
+    self.name = name
+    self.server_image_path = server_image_path
+    self.wrapper_script_path = wrapper_script_path
+    self.server_port = server_port
+    self.server_args_dict = server_args_dict
+
+
+class DockerImage:
+  """ Represents properties of a Docker image. Provides methods to build the
+  image and push it to GKE registry
+  """
+
+  def __init__(self, gcp_project_id, image_name, build_script_path,
+               dockerfile_dir, build_type):
+    """Args:
+
+      image_name: The docker image name
+      tag_name: The additional tag name. This is the name used when pushing the
+        docker image to GKE registry
+      build_script_path: The path to the build script that builds this docker
+      image
+      dockerfile_dir: The name of the directory under
+      '<grpc_root>/tools/dockerfile' that contains the dockerfile
+    """
+    self.image_name = image_name
+    self.gcp_project_id = gcp_project_id
+    self.build_script_path = build_script_path
+    self.dockerfile_dir = dockerfile_dir
+    self.build_type = build_type
+    self.tag_name = self._make_tag_name(gcp_project_id, image_name)
+
+  def _make_tag_name(self, project_id, image_name):
+    return 'gcr.io/%s/%s' % (project_id, image_name)
+
+  def build_image(self):
+    print 'Building docker image: %s (tag: %s)' % (self.image_name,
+                                                   self.tag_name)
+    os.environ['INTEROP_IMAGE'] = self.image_name
+    os.environ['INTEROP_IMAGE_REPOSITORY_TAG'] = self.tag_name
+    os.environ['BASE_NAME'] = self.dockerfile_dir
+    os.environ['BUILD_TYPE'] = self.build_type
+    print 'DEBUG: path: ', self.build_script_path
+    if subprocess.call(args=[self.build_script_path]) != 0:
+      print 'Error in building the Docker image'
+      return False
+    return True
+
+  def push_to_gke_registry(self):
+    cmd = ['gcloud', 'docker', 'push', self.tag_name]
+    print 'Pushing %s to the GKE registry..' % self.tag_name
+    if subprocess.call(args=cmd) != 0:
+      print 'Error in pushing the image %s to the GKE registry' % self.tag_name
+      return False
+    return True
+
+
+class ServerPodSpec:
+  """ Contains the information required to launch server pods. """
+
+  def __init__(self, name, server_template, docker_image, num_instances):
+    self.name = name
+    self.template = server_template
+    self.docker_image = docker_image
+    self.num_instances = num_instances
+
+  def pod_names(self):
+    """ Return a list of names of server pods to create. """
+    return ['%s-%d' % (self.name, i) for i in range(1, self.num_instances + 1)]
+
+  def server_addresses(self):
+    """ Return string of server addresses in the following format:
+      '<server_pod_name_1>:<server_port>,<server_pod_name_2>:<server_port>...'
+    """
+    return ','.join(['%s:%d' % (pod_name, self.template.server_port)
+                     for pod_name in self.pod_names()])
+
+
+class ClientPodSpec:
+  """ Contains the information required to launch client pods """
+
+  def __init__(self, name, client_template, docker_image, num_instances,
+               server_addresses):
+    self.name = name
+    self.template = client_template
+    self.docker_image = docker_image
+    self.num_instances = num_instances
+    self.server_addresses = server_addresses
+
+  def pod_names(self):
+    """ Return a list of names of client pods to create """
+    return ['%s-%d' % (self.name, i) for i in range(1, self.num_instances + 1)]
+
+  # The client args in the template do not have server addresses. This function
+  # adds the server addresses and returns the updated client args
+  def get_client_args_dict(self):
+    args_dict = self.template.client_args_dict.copy()
+    args_dict['server_addresses'] = self.server_addresses
+    return args_dict
+
+
+class Gke:
+  """ Class that has helper methods to interact with GKE """
+
+  class KubernetesProxy:
+    """Class to start a proxy on localhost to talk to the Kubernetes API server"""
+
+    def __init__(self, port):
+      cmd = ['kubectl', 'proxy', '--port=%d' % port]
+      self.p = subprocess.Popen(args=cmd)
+      time.sleep(2)
+      print '\nStarted kubernetes proxy on port: %d' % port
+
+    def __del__(self):
+      if self.p is not None:
+        print 'Shutting down Kubernetes proxy..'
+        self.p.kill()
+
+  def __init__(self, project_id, run_id, dataset_id, summary_table_id,
+               qps_table_id, kubernetes_port):
+    self.project_id = project_id
+    self.run_id = run_id
+    self.dataset_id = dataset_id
+    self.summary_table_id = summary_table_id
+    self.qps_table_id = qps_table_id
+
+    # The environment variables we would like to pass to every pod (both client
+    # and server) launched in GKE
+    self.gke_env = {
+        'RUN_ID': self.run_id,
+        'GCP_PROJECT_ID': self.project_id,
+        'DATASET_ID': self.dataset_id,
+        'SUMMARY_TABLE_ID': self.summary_table_id,
+        'QPS_TABLE_ID': self.qps_table_id
+    }
+
+    self.kubernetes_port = kubernetes_port
+    # Start kubernetes proxy
+    self.kubernetes_proxy = Gke.KubernetesProxy(kubernetes_port)
+
+  def _args_dict_to_str(self, args_dict):
+    return ' '.join('--%s=%s' % (k, args_dict[k]) for k in args_dict.keys())
+
+  def launch_servers(self, server_pod_spec):
+    is_success = True
+
+    # The command to run inside the container is the wrapper script (which then
+    # launches the actual server)
+    container_cmd = server_pod_spec.template.wrapper_script_path
+
+    # The parameters to the wrapper script (defined in
+    # server_pod_spec.template.wrapper_script_path) are are injected into the
+    # container via environment variables
+    server_env = self.gke_env.copy()
+    server_env.update({
+        'STRESS_TEST_IMAGE_TYPE': 'SERVER',
+        'STRESS_TEST_IMAGE': server_pod_spec.template.server_image_path,
+        'STRESS_TEST_ARGS_STR': self._args_dict_to_str(
+            server_pod_spec.template.server_args_dict)
+    })
+
+    for pod_name in server_pod_spec.pod_names():
+      server_env['POD_NAME'] = pod_name
+      print 'Creating server: %s' % pod_name
+      is_success = kubernetes_api.create_pod_and_service(
+          'localhost',
+          self.kubernetes_port,
+          'default',  # Use 'default' namespace
+          pod_name,
+          server_pod_spec.docker_image.tag_name,
+          [server_pod_spec.template.server_port],  # Ports to expose on the pod
+          [container_cmd],
+          [],  # Args list is empty since we are passing all args via env variables
+          server_env,
+          True  # Headless = True for server to that GKE creates a DNS record for pod_name
+      )
+      if not is_success:
+        print 'Error in launching server: %s' % pod_name
+        break
+
+    if is_success:
+      print 'Successfully created server(s)'
+
+    return is_success
+
+  def launch_clients(self, client_pod_spec):
+    is_success = True
+
+    # The command to run inside the container is the wrapper script (which then
+    # launches the actual stress client)
+    container_cmd = client_pod_spec.template.wrapper_script_path
+
+    # The parameters to the wrapper script (defined in
+    # client_pod_spec.template.wrapper_script_path) are are injected into the
+    # container via environment variables
+    client_env = self.gke_env.copy()
+    client_env.update({
+        'STRESS_TEST_IMAGE_TYPE': 'CLIENT',
+        'STRESS_TEST_IMAGE': client_pod_spec.template.client_image_path,
+        'STRESS_TEST_ARGS_STR': self._args_dict_to_str(
+            client_pod_spec.get_client_args_dict()),
+        'METRICS_CLIENT_IMAGE':
+            client_pod_spec.template.metrics_client_image_path,
+        'METRICS_CLIENT_ARGS_STR': self._args_dict_to_str(
+            client_pod_spec.template.metrics_args_dict),
+        'POLL_INTERVAL_SECS': str(client_pod_spec.template.poll_interval_secs)
+    })
+
+    for pod_name in client_pod_spec.pod_names():
+      client_env['POD_NAME'] = pod_name
+      print 'Creating client: %s' % pod_name
+      is_success = kubernetes_api.create_pod_and_service(
+          'localhost',
+          self.kubernetes_port,
+          'default',  # default namespace,
+          pod_name,
+          client_pod_spec.docker_image.tag_name,
+          [client_pod_spec.template.metrics_port],  # Ports to expose on the pod
+          [container_cmd],
+          [],  # Empty args list since all args are passed via env variables
+          client_env,
+          False  # Client is not a headless service.
+      )
+
+      if not is_success:
+        print 'Error in launching client %s' % pod_name
+        break
+
+    if is_success:
+      print 'Successfully created all client(s)'
+
+    return is_success
+
+  def _delete_pods(self, pod_name_list):
+    is_success = True
+    for pod_name in pod_name_list:
+      print 'Deleting %s' % pod_name
+      is_success = kubernetes_api.delete_pod_and_service(
+          'localhost',
+          self.kubernetes_port,
+          'default',  # default namespace
+          pod_name)
+
+      if not is_success:
+        print 'Error in deleting pod %s' % pod_name
+        break
+
+    if is_success:
+      print 'Successfully deleted all pods'
+
+    return is_success
+
+  def delete_servers(self, server_pod_spec):
+    return self._delete_pods(server_pod_spec.pod_names())
+
+  def delete_clients(self, client_pod_spec):
+    return self._delete_pods(client_pod_spec.pod_names())
+
+
+class Config:
+
+  def __init__(self, config_filename, gcp_project_id):
+    print 'Loading configuration...'
+    config_dict = self._load_config(config_filename)
+
+    self.global_settings = self._parse_global_settings(config_dict,
+                                                       gcp_project_id)
+    self.docker_images_dict = self._parse_docker_images(
+        config_dict, self.global_settings.gcp_project_id)
+    self.client_templates_dict = self._parse_client_templates(config_dict)
+    self.server_templates_dict = self._parse_server_templates(config_dict)
+    self.server_pod_specs_dict = self._parse_server_pod_specs(
+        config_dict, self.docker_images_dict, self.server_templates_dict)
+    self.client_pod_specs_dict = self._parse_client_pod_specs(
+        config_dict, self.docker_images_dict, self.client_templates_dict,
+        self.server_pod_specs_dict)
+    print 'Loaded Configuaration.'
+
+  def _parse_global_settings(self, config_dict, gcp_project_id):
+    global_settings_dict = config_dict['globalSettings']
+    return GlobalSettings(gcp_project_id,
+                          global_settings_dict['buildDockerImages'],
+                          global_settings_dict['pollIntervalSecs'],
+                          global_settings_dict['testDurationSecs'],
+                          global_settings_dict['kubernetesProxyPort'],
+                          global_settings_dict['datasetIdNamePrefix'],
+                          global_settings_dict['summaryTableId'],
+                          global_settings_dict['qpsTableId'],
+                          global_settings_dict['podWarmupSecs'])
+
+  def _parse_docker_images(self, config_dict, gcp_project_id):
+    """Parses the 'dockerImages' section of the config file and returns a
+    Dictionary of 'DockerImage' objects keyed by docker image names"""
+    docker_images_dict = {}
+
+    docker_config_dict = config_dict['dockerImages']
+    for image_name in docker_config_dict.keys():
+      build_script_path = docker_config_dict[image_name]['buildScript']
+      dockerfile_dir = docker_config_dict[image_name]['dockerFileDir']
+      build_type = docker_config_dict[image_name]['buildType']
+      docker_images_dict[image_name] = DockerImage(gcp_project_id, image_name,
+                                                   build_script_path,
+                                                   dockerfile_dir, build_type)
+    return docker_images_dict
+
+  def _parse_client_templates(self, config_dict):
+    """Parses the 'clientTemplates' section of the config file and returns a
+    Dictionary of 'ClientTemplate' objects keyed by client template names.
+
+    Note: The 'baseTemplates' sub section of the config file contains templates
+    with default values  and the 'templates' sub section contains the actual
+    client templates (which refer to the base template name to use for default
+    values).
+    """
+    client_templates_dict = {}
+
+    templates_dict = config_dict['clientTemplates']['templates']
+    base_templates_dict = config_dict['clientTemplates'].get('baseTemplates',
+                                                             {})
+    for template_name in templates_dict.keys():
+      # temp_dict is a temporary dictionary that merges base template dictionary
+      # and client template dictionary (with client template dictionary values
+      # overriding base template values)
+      temp_dict = {}
+
+      base_template_name = templates_dict[template_name].get('baseTemplate')
+      if not base_template_name is None:
+        temp_dict = base_templates_dict[base_template_name].copy()
+
+      temp_dict.update(templates_dict[template_name])
+
+      # Create and add ClientTemplate object to the final client_templates_dict
+      client_templates_dict[template_name] = ClientTemplate(
+          template_name, temp_dict['clientImagePath'],
+          temp_dict['metricsClientImagePath'], temp_dict['metricsPort'],
+          temp_dict['wrapperScriptPath'], temp_dict['pollIntervalSecs'],
+          temp_dict['clientArgs'].copy(), temp_dict['metricsArgs'].copy())
+
+    return client_templates_dict
+
+  def _parse_server_templates(self, config_dict):
+    """Parses the 'serverTemplates' section of the config file and returns a
+    Dictionary of 'serverTemplate' objects keyed by server template names.
+
+    Note: The 'baseTemplates' sub section of the config file contains templates
+    with default values  and the 'templates' sub section contains the actual
+    server templates (which refer to the base template name to use for default
+    values).
+    """
+    server_templates_dict = {}
+
+    templates_dict = config_dict['serverTemplates']['templates']
+    base_templates_dict = config_dict['serverTemplates'].get('baseTemplates',
+                                                             {})
+
+    for template_name in templates_dict.keys():
+      # temp_dict is a temporary dictionary that merges base template dictionary
+      # and server template dictionary (with server template dictionary values
+      # overriding base template values)
+      temp_dict = {}
+
+      base_template_name = templates_dict[template_name].get('baseTemplate')
+      if not base_template_name is None:
+        temp_dict = base_templates_dict[base_template_name].copy()
+
+      temp_dict.update(templates_dict[template_name])
+
+      # Create and add ServerTemplate object to the final server_templates_dict
+      server_templates_dict[template_name] = ServerTemplate(
+          template_name, temp_dict['serverImagePath'],
+          temp_dict['wrapperScriptPath'], temp_dict['serverPort'],
+          temp_dict['serverArgs'].copy())
+
+    return server_templates_dict
+
+  def _parse_server_pod_specs(self, config_dict, docker_images_dict,
+                              server_templates_dict):
+    """Parses the 'serverPodSpecs' sub-section (under 'testMatrix' section) of
+    the config file and returns a Dictionary of 'ServerPodSpec' objects keyed
+    by server pod spec names"""
+    server_pod_specs_dict = {}
+
+    pod_specs_dict = config_dict['testMatrix'].get('serverPodSpecs', {})
+
+    for pod_name in pod_specs_dict.keys():
+      server_template_name = pod_specs_dict[pod_name]['serverTemplate']
+      docker_image_name = pod_specs_dict[pod_name]['dockerImage']
+      num_instances = pod_specs_dict[pod_name].get('numInstances', 1)
+
+      # Create and add the ServerPodSpec object to the final
+      # server_pod_specs_dict
+      server_pod_specs_dict[pod_name] = ServerPodSpec(
+          pod_name, server_templates_dict[server_template_name],
+          docker_images_dict[docker_image_name], num_instances)
+
+    return server_pod_specs_dict
+
+  def _parse_client_pod_specs(self, config_dict, docker_images_dict,
+                              client_templates_dict, server_pod_specs_dict):
+    """Parses the 'clientPodSpecs' sub-section (under 'testMatrix' section) of
+    the config file and returns a Dictionary of 'ClientPodSpec' objects keyed
+    by client pod spec names"""
+    client_pod_specs_dict = {}
+
+    pod_specs_dict = config_dict['testMatrix'].get('clientPodSpecs', {})
+    for pod_name in pod_specs_dict.keys():
+      client_template_name = pod_specs_dict[pod_name]['clientTemplate']
+      docker_image_name = pod_specs_dict[pod_name]['dockerImage']
+      num_instances = pod_specs_dict[pod_name]['numInstances']
+
+      # Get the server addresses from the server pod spec object
+      server_pod_spec_name = pod_specs_dict[pod_name]['serverPodSpec']
+      server_addresses = server_pod_specs_dict[
+          server_pod_spec_name].server_addresses()
+
+      client_pod_specs_dict[pod_name] = ClientPodSpec(
+          pod_name, client_templates_dict[client_template_name],
+          docker_images_dict[docker_image_name], num_instances,
+          server_addresses)
+
+    return client_pod_specs_dict
+
+  def _load_config(self, config_filename):
+    """Opens the config file and converts the Json text to Dictionary"""
+    if not os.path.isabs(config_filename):
+      raise Exception('Config objects expects an absolute file path. '
+                      'config file name passed: %s' % config_filename)
+    with open(config_filename) as config_file:
+      return json.load(config_file)
+
+
+def run_tests(config):
+  """ The main function that launches the stress tests """
+  # Build docker images and push to GKE registry
+  if config.global_settings.build_docker_images:
+    for name, docker_image in config.docker_images_dict.iteritems():
+      if not (docker_image.build_image() and
+              docker_image.push_to_gke_registry()):
+        return False
+
+  # Create a unique id for this run (Note: Using timestamp instead of UUID to
+  # make it easier to deduce the date/time of the run just by looking at the run
+  # run id. This is useful in debugging when looking at records in Biq query)
+  run_id = datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S')
+  dataset_id = '%s_%s' % (config.global_settings.dataset_id_prefix, run_id)
+
+  bq_helper = BigQueryHelper(run_id, '', '',
+                             config.global_settings.gcp_project_id, dataset_id,
+                             config.global_settings.summary_table_id,
+                             config.global_settings.qps_table_id)
+  bq_helper.initialize()
+
+  gke = Gke(config.global_settings.gcp_project_id, run_id, dataset_id,
+            config.global_settings.summary_table_id,
+            config.global_settings.qps_table_id,
+            config.global_settings.kubernetes_proxy_port)
+
+  is_success = True
+
+  try:
+    print 'Launching servers..'
+    for name, server_pod_spec in config.server_pod_specs_dict.iteritems():
+      if not gke.launch_servers(server_pod_spec):
+        is_success = False  # is_success is checked in the 'finally' block
+        return False
+
+    print('Launched servers. Waiting for %d seconds for the server pods to be '
+          'fully online') % config.global_settings.pod_warmup_secs
+    time.sleep(config.global_settings.pod_warmup_secs)
+
+    for name, client_pod_spec in config.client_pod_specs_dict.iteritems():
+      if not gke.launch_clients(client_pod_spec):
+        is_success = False  # is_success is checked in the 'finally' block
+        return False
+
+    print('Launched all clients. Waiting for %d seconds for the client pods to '
+          'be fully online') % config.global_settings.pod_warmup_secs
+    time.sleep(config.global_settings.pod_warmup_secs)
+
+    start_time = datetime.datetime.now()
+    end_time = start_time + datetime.timedelta(
+        seconds=config.global_settings.test_duration_secs)
+    print 'Running the test until %s' % end_time.isoformat()
+
+    while True:
+      if datetime.datetime.now() > end_time:
+        print 'Test was run for %d seconds' % config.global_settings.test_duration_secs
+        break
+
+      # Check if either stress server or clients have failed (btw, the bq_helper
+      # monitors all the rows in the summary table and checks if any of them
+      # have a failure status)
+      if bq_helper.check_if_any_tests_failed():
+        is_success = False
+        print 'Some tests failed.'
+        break  # Don't 'return' here. We still want to call bq_helper to print qps/summary tables
+
+      # Tests running fine. Wait until next poll time to check the status
+      print 'Sleeping for %d seconds..' % config.global_settings.test_poll_interval_secs
+      time.sleep(config.global_settings.test_poll_interval_secs)
+
+    # Print BiqQuery tables
+    bq_helper.print_qps_records()
+    bq_helper.print_summary_records()
+
+  finally:
+    # If there was a test failure, we should not delete the pods since they
+    # would contain useful debug information (logs, core dumps etc)
+    if is_success:
+      for name, server_pod_spec in config.server_pod_specs_dict.iteritems():
+        gke.delete_servers(server_pod_spec)
+      for name, client_pod_spec in config.client_pod_specs_dict.iteritems():
+        gke.delete_clients(client_pod_spec)
+
+  return is_success
+
+
+argp = argparse.ArgumentParser(
+    description='Launch stress tests in GKE',
+    formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+argp.add_argument('--gcp_project_id',
+                  required=True,
+                  help='The Google Cloud Platform Project Id')
+argp.add_argument('--config_file',
+                  required=True,
+                  type=str,
+                  help='The test config file')
+
+if __name__ == '__main__':
+  args = argp.parse_args()
+
+  config_filename = args.config_file
+
+  # Since we will be changing the current working directory to grpc root in the
+  # next step, we should check if the config filename path is a relative path
+  # (i.e a path relative to the current working directory) and if so, convert it
+  # to abosulte path
+  if not os.path.isabs(config_filename):
+    config_filename = os.path.abspath(config_filename)
+
+  config = Config(config_filename, args.gcp_project_id)
+
+  # Change current working directory to grpc root
+  # (This is important because all relative file paths in the config file are
+  # supposed to interpreted as relative to the GRPC root)
+  grpc_root = os.path.abspath(os.path.join(
+      os.path.dirname(sys.argv[0]), '../../..'))
+  os.chdir(grpc_root)
+
+  run_tests(config)
diff --git a/tools/run_tests/stress_test/run_stress_tests_on_gke.py b/tools/run_tests/stress_test/run_stress_tests_on_gke.py
deleted file mode 100755
index 634eb1a..0000000
--- a/tools/run_tests/stress_test/run_stress_tests_on_gke.py
+++ /dev/null
@@ -1,556 +0,0 @@
-#!/usr/bin/env python2.7
-# Copyright 2015-2016, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-import argparse
-import datetime
-import os
-import subprocess
-import sys
-import time
-
-stress_test_utils_dir = os.path.abspath(os.path.join(
-    os.path.dirname(__file__), '../../gcp/stress_test'))
-sys.path.append(stress_test_utils_dir)
-from stress_test_utils import BigQueryHelper
-
-kubernetes_api_dir = os.path.abspath(os.path.join(
-    os.path.dirname(__file__), '../../gcp/utils'))
-sys.path.append(kubernetes_api_dir)
-
-import kubernetes_api
-
-_GRPC_ROOT = os.path.abspath(os.path.join(
-    os.path.dirname(sys.argv[0]), '../../..'))
-os.chdir(_GRPC_ROOT)
-
-# num of seconds to wait for the GKE image to start and warmup
-_GKE_IMAGE_WARMUP_WAIT_SECS = 60
-
-_SERVER_POD_NAME = 'stress-server'
-_CLIENT_POD_NAME_PREFIX = 'stress-client'
-_DATASET_ID_PREFIX = 'stress_test'
-_SUMMARY_TABLE_ID = 'summary'
-_QPS_TABLE_ID = 'qps'
-
-_DEFAULT_DOCKER_IMAGE_NAME = 'grpc_stress_test'
-
-# The default port on which the kubernetes proxy server is started on localhost
-# (i.e kubectl proxy --port=<port>)
-_DEFAULT_KUBERNETES_PROXY_PORT = 8001
-
-# How frequently should the stress client wrapper script (running inside a GKE
-# container) poll the health of the stress client (also running inside the GKE
-# container) and upload metrics to BigQuery
-_DEFAULT_STRESS_CLIENT_POLL_INTERVAL_SECS = 60
-
-# The default setting for stress test server and client
-_DEFAULT_STRESS_SERVER_PORT = 8080
-_DEFAULT_METRICS_PORT = 8081
-_DEFAULT_TEST_CASES_STR = 'empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1'
-_DEFAULT_NUM_CHANNELS_PER_SERVER = 5
-_DEFAULT_NUM_STUBS_PER_CHANNEL = 10
-_DEFAULT_METRICS_COLLECTION_INTERVAL_SECS = 30
-
-# Number of stress client instances to launch
-_DEFAULT_NUM_CLIENTS = 3
-
-# How frequently should this test monitor the health of Stress clients and
-# Servers running in GKE
-_DEFAULT_TEST_POLL_INTERVAL_SECS = 60
-
-# Default run time for this test (2 hour)
-_DEFAULT_TEST_DURATION_SECS = 7200
-
-# The number of seconds it would take a GKE pod to warm up (i.e get to 'Running'
-# state from the time of creation). Ideally this is something the test should
-# automatically determine by using Kubernetes API to poll the pods status.
-_DEFAULT_GKE_WARMUP_SECS = 60
-
-
-class KubernetesProxy:
-  """ Class to start a proxy on localhost to the Kubernetes API server """
-
-  def __init__(self, api_port):
-    self.port = api_port
-    self.p = None
-    self.started = False
-
-  def start(self):
-    cmd = ['kubectl', 'proxy', '--port=%d' % self.port]
-    self.p = subprocess.Popen(args=cmd)
-    self.started = True
-    time.sleep(2)
-    print '..Started'
-
-  def get_port(self):
-    return self.port
-
-  def is_started(self):
-    return self.started
-
-  def __del__(self):
-    if self.p is not None:
-      print 'Shutting down Kubernetes proxy..'
-      self.p.kill()
-
-
-class TestSettings:
-
-  def __init__(self, build_docker_image, test_poll_interval_secs,
-               test_duration_secs, kubernetes_proxy_port):
-    self.build_docker_image = build_docker_image
-    self.test_poll_interval_secs = test_poll_interval_secs
-    self.test_duration_secs = test_duration_secs
-    self.kubernetes_proxy_port = kubernetes_proxy_port
-
-
-class GkeSettings:
-
-  def __init__(self, project_id, docker_image_name):
-    self.project_id = project_id
-    self.docker_image_name = docker_image_name
-    self.tag_name = 'gcr.io/%s/%s' % (project_id, docker_image_name)
-
-
-class BigQuerySettings:
-
-  def __init__(self, run_id, dataset_id, summary_table_id, qps_table_id):
-    self.run_id = run_id
-    self.dataset_id = dataset_id
-    self.summary_table_id = summary_table_id
-    self.qps_table_id = qps_table_id
-
-
-class StressServerSettings:
-
-  def __init__(self, server_pod_name, server_port):
-    self.server_pod_name = server_pod_name
-    self.server_port = server_port
-
-
-class StressClientSettings:
-
-  def __init__(self, num_clients, client_pod_name_prefix, server_pod_name,
-               server_port, metrics_port, metrics_collection_interval_secs,
-               stress_client_poll_interval_secs, num_channels_per_server,
-               num_stubs_per_channel, test_cases_str):
-    self.num_clients = num_clients
-    self.client_pod_name_prefix = client_pod_name_prefix
-    self.server_pod_name = server_pod_name
-    self.server_port = server_port
-    self.metrics_port = metrics_port
-    self.metrics_collection_interval_secs = metrics_collection_interval_secs
-    self.stress_client_poll_interval_secs = stress_client_poll_interval_secs
-    self.num_channels_per_server = num_channels_per_server
-    self.num_stubs_per_channel = num_stubs_per_channel
-    self.test_cases_str = test_cases_str
-
-    # == Derived properties ==
-    # Note: Client can accept a list of server addresses (a comma separated list
-    # of 'server_name:server_port'). In this case, we only have one server
-    # address to pass
-    self.server_addresses = '%s.default.svc.cluster.local:%d' % (
-        server_pod_name, server_port)
-    self.client_pod_names_list = ['%s-%d' % (client_pod_name_prefix, i)
-                                  for i in range(1, num_clients + 1)]
-
-
-def _build_docker_image(image_name, tag_name):
-  """ Build the docker image and add tag it to the GKE repository """
-  print 'Building docker image: %s' % image_name
-  os.environ['INTEROP_IMAGE'] = image_name
-  os.environ['INTEROP_IMAGE_REPOSITORY_TAG'] = tag_name
-  # Note that 'BASE_NAME' HAS to be 'grpc_interop_stress_cxx' since the script
-  # build_interop_stress_image.sh invokes the following script:
-  #   tools/dockerfile/$BASE_NAME/build_interop_stress.sh
-  os.environ['BASE_NAME'] = 'grpc_interop_stress_cxx'
-  cmd = ['tools/jenkins/build_interop_stress_image.sh']
-  retcode = subprocess.call(args=cmd)
-  if retcode != 0:
-    print 'Error in building docker image'
-    return False
-  return True
-
-
-def _push_docker_image_to_gke_registry(docker_tag_name):
-  """Executes 'gcloud docker push <docker_tag_name>' to push the image to GKE registry"""
-  cmd = ['gcloud', 'docker', 'push', docker_tag_name]
-  print 'Pushing %s to GKE registry..' % docker_tag_name
-  retcode = subprocess.call(args=cmd)
-  if retcode != 0:
-    print 'Error in pushing docker image %s to the GKE registry' % docker_tag_name
-    return False
-  return True
-
-
-def _launch_server(gke_settings, stress_server_settings, bq_settings,
-                   kubernetes_proxy):
-  """ Launches a stress test server instance in GKE cluster """
-  if not kubernetes_proxy.is_started:
-    print 'Kubernetes proxy must be started before calling this function'
-    return False
-
-  # This is the wrapper script that is run in the container. This script runs
-  # the actual stress test server
-  server_cmd_list = ['/var/local/git/grpc/tools/gcp/stress_test/run_server.py']
-
-  # run_server.py does not take any args from the command line. The args are
-  # instead passed via environment variables (see server_env below)
-  server_arg_list = []
-
-  # The parameters to the script run_server.py are injected into the container
-  # via environment variables
-  server_env = {
-      'STRESS_TEST_IMAGE_TYPE': 'SERVER',
-      'STRESS_TEST_IMAGE': '/var/local/git/grpc/bins/opt/interop_server',
-      'STRESS_TEST_ARGS_STR': '--port=%s' % stress_server_settings.server_port,
-      'RUN_ID': bq_settings.run_id,
-      'POD_NAME': stress_server_settings.server_pod_name,
-      'GCP_PROJECT_ID': gke_settings.project_id,
-      'DATASET_ID': bq_settings.dataset_id,
-      'SUMMARY_TABLE_ID': bq_settings.summary_table_id,
-      'QPS_TABLE_ID': bq_settings.qps_table_id
-  }
-
-  # Launch Server
-  is_success = kubernetes_api.create_pod_and_service(
-      'localhost',
-      kubernetes_proxy.get_port(),
-      'default',  # Use 'default' namespace
-      stress_server_settings.server_pod_name,
-      gke_settings.tag_name,
-      [stress_server_settings.server_port],  # Port that should be exposed
-      server_cmd_list,
-      server_arg_list,
-      server_env,
-      True  # Headless = True for server. Since we want DNS records to be created by GKE
-  )
-
-  return is_success
-
-
-def _launch_client(gke_settings, stress_server_settings, stress_client_settings,
-                   bq_settings, kubernetes_proxy):
-  """ Launches a configurable number of stress test clients on GKE cluster """
-  if not kubernetes_proxy.is_started:
-    print 'Kubernetes proxy must be started before calling this function'
-    return False
-
-  stress_client_arg_list = [
-      '--server_addresses=%s' % stress_client_settings.server_addresses,
-      '--test_cases=%s' % stress_client_settings.test_cases_str,
-      '--num_stubs_per_channel=%d' %
-      stress_client_settings.num_stubs_per_channel
-  ]
-
-  # This is the wrapper script that is run in the container. This script runs
-  # the actual stress client
-  client_cmd_list = ['/var/local/git/grpc/tools/gcp/stress_test/run_client.py']
-
-  # run_client.py takes no args. All args are passed as env variables (see
-  # client_env)
-  client_arg_list = []
-
-  metrics_server_address = 'localhost:%d' % stress_client_settings.metrics_port
-  metrics_client_arg_list = [
-      '--metrics_server_address=%s' % metrics_server_address,
-      '--total_only=true'
-  ]
-
-  # The parameters to the script run_client.py are injected into the container
-  # via environment variables
-  client_env = {
-      'STRESS_TEST_IMAGE_TYPE': 'CLIENT',
-      'STRESS_TEST_IMAGE': '/var/local/git/grpc/bins/opt/stress_test',
-      'STRESS_TEST_ARGS_STR': ' '.join(stress_client_arg_list),
-      'METRICS_CLIENT_IMAGE': '/var/local/git/grpc/bins/opt/metrics_client',
-      'METRICS_CLIENT_ARGS_STR': ' '.join(metrics_client_arg_list),
-      'RUN_ID': bq_settings.run_id,
-      'POLL_INTERVAL_SECS':
-          str(stress_client_settings.stress_client_poll_interval_secs),
-      'GCP_PROJECT_ID': gke_settings.project_id,
-      'DATASET_ID': bq_settings.dataset_id,
-      'SUMMARY_TABLE_ID': bq_settings.summary_table_id,
-      'QPS_TABLE_ID': bq_settings.qps_table_id
-  }
-
-  for pod_name in stress_client_settings.client_pod_names_list:
-    client_env['POD_NAME'] = pod_name
-    is_success = kubernetes_api.create_pod_and_service(
-        'localhost',  # Since proxy is running on localhost
-        kubernetes_proxy.get_port(),
-        'default',  # default namespace
-        pod_name,
-        gke_settings.tag_name,
-        [stress_client_settings.metrics_port
-        ],  # Client pods expose metrics port
-        client_cmd_list,
-        client_arg_list,
-        client_env,
-        False  # Client is not a headless service
-    )
-    if not is_success:
-      print 'Error in launching client %s' % pod_name
-      return False
-
-  return True
-
-
-def _launch_server_and_client(gke_settings, stress_server_settings,
-                              stress_client_settings, bq_settings,
-                              kubernetes_proxy_port):
-  # Start kubernetes proxy
-  print 'Kubernetes proxy'
-  kubernetes_proxy = KubernetesProxy(kubernetes_proxy_port)
-  kubernetes_proxy.start()
-
-  print 'Launching server..'
-  is_success = _launch_server(gke_settings, stress_server_settings, bq_settings,
-                              kubernetes_proxy)
-  if not is_success:
-    print 'Error in launching server'
-    return False
-
-  # Server takes a while to start.
-  # TODO(sree) Use Kubernetes API to query the status of the server instead of
-  # sleeping
-  print 'Waiting for %s seconds for the server to start...' % _GKE_IMAGE_WARMUP_WAIT_SECS
-  time.sleep(_GKE_IMAGE_WARMUP_WAIT_SECS)
-
-  # Launch client
-  client_pod_name_prefix = 'stress-client'
-  is_success = _launch_client(gke_settings, stress_server_settings,
-                              stress_client_settings, bq_settings,
-                              kubernetes_proxy)
-
-  if not is_success:
-    print 'Error in launching client(s)'
-    return False
-
-  print 'Waiting for %s seconds for the client images to start...' % _GKE_IMAGE_WARMUP_WAIT_SECS
-  time.sleep(_GKE_IMAGE_WARMUP_WAIT_SECS)
-  return True
-
-
-def _delete_server_and_client(stress_server_settings, stress_client_settings,
-                              kubernetes_proxy_port):
-  kubernetes_proxy = KubernetesProxy(kubernetes_proxy_port)
-  kubernetes_proxy.start()
-
-  # Delete clients first
-  is_success = True
-  for pod_name in stress_client_settings.client_pod_names_list:
-    is_success = kubernetes_api.delete_pod_and_service(
-        'localhost', kubernetes_proxy_port, 'default', pod_name)
-    if not is_success:
-      return False
-
-  # Delete server
-  is_success = kubernetes_api.delete_pod_and_service(
-      'localhost', kubernetes_proxy_port, 'default',
-      stress_server_settings.server_pod_name)
-  return is_success
-
-
-def run_test_main(test_settings, gke_settings, stress_server_settings,
-                  stress_client_clients):
-  is_success = True
-
-  if test_settings.build_docker_image:
-    is_success = _build_docker_image(gke_settings.docker_image_name,
-                                     gke_settings.tag_name)
-    if not is_success:
-      return False
-
-    is_success = _push_docker_image_to_gke_registry(gke_settings.tag_name)
-    if not is_success:
-      return False
-
-  # Create a unique id for this run (Note: Using timestamp instead of UUID to
-  # make it easier to deduce the date/time of the run just by looking at the run
-  # run id. This is useful in debugging when looking at records in Biq query)
-  run_id = datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S')
-  dataset_id = '%s_%s' % (_DATASET_ID_PREFIX, run_id)
-
-  # Big Query settings (common for both Stress Server and Client)
-  bq_settings = BigQuerySettings(run_id, dataset_id, _SUMMARY_TABLE_ID,
-                                 _QPS_TABLE_ID)
-
-  bq_helper = BigQueryHelper(run_id, '', '', args.project_id, dataset_id,
-                             _SUMMARY_TABLE_ID, _QPS_TABLE_ID)
-  bq_helper.initialize()
-
-  try:
-    is_success = _launch_server_and_client(gke_settings, stress_server_settings,
-                                           stress_client_settings, bq_settings,
-                                           test_settings.kubernetes_proxy_port)
-    if not is_success:
-      return False
-
-    start_time = datetime.datetime.now()
-    end_time = start_time + datetime.timedelta(
-        seconds=test_settings.test_duration_secs)
-    print 'Running the test until %s' % end_time.isoformat()
-
-    while True:
-      if datetime.datetime.now() > end_time:
-        print 'Test was run for %d seconds' % test_settings.test_duration_secs
-        break
-
-      # Check if either stress server or clients have failed
-      if bq_helper.check_if_any_tests_failed():
-        is_success = False
-        print 'Some tests failed.'
-        break
-
-      # Things seem to be running fine. Wait until next poll time to check the
-      # status
-      print 'Sleeping for %d seconds..' % test_settings.test_poll_interval_secs
-      time.sleep(test_settings.test_poll_interval_secs)
-
-    # Print BiqQuery tables
-    bq_helper.print_summary_records()
-    bq_helper.print_qps_records()
-
-  finally:
-    # If is_success is False at this point, it means that the stress tests were
-    # started successfully but failed while running the tests. In this case we
-    # do should not delete the pods (since they contain all the failure
-    # information)
-    if is_success:
-      _delete_server_and_client(stress_server_settings, stress_client_settings,
-                                test_settings.kubernetes_proxy_port)
-
-  return is_success
-
-
-argp = argparse.ArgumentParser(
-    description='Launch stress tests in GKE',
-    formatter_class=argparse.ArgumentDefaultsHelpFormatter)
-argp.add_argument('--project_id',
-                  required=True,
-                  help='The Google Cloud Platform Project Id')
-argp.add_argument('--num_clients',
-                  default=1,
-                  type=int,
-                  help='Number of client instances to start')
-argp.add_argument('--docker_image_name',
-                  default=_DEFAULT_DOCKER_IMAGE_NAME,
-                  help='The name of the docker image containing stress client '
-                  'and stress servers')
-argp.add_argument('--build_docker_image',
-                  dest='build_docker_image',
-                  action='store_true',
-                  help='Build a docker image and push to Google Container '
-                  'Registry')
-argp.add_argument('--do_not_build_docker_image',
-                  dest='build_docker_image',
-                  action='store_false',
-                  help='Do not build and push docker image to Google Container '
-                  'Registry')
-argp.set_defaults(build_docker_image=True)
-
-argp.add_argument('--test_poll_interval_secs',
-                  default=_DEFAULT_TEST_POLL_INTERVAL_SECS,
-                  type=int,
-                  help='How frequently should this script should monitor the '
-                  'health of stress clients and servers running in the GKE '
-                  'cluster')
-argp.add_argument('--test_duration_secs',
-                  default=_DEFAULT_TEST_DURATION_SECS,
-                  type=int,
-                  help='How long should this test be run')
-argp.add_argument('--kubernetes_proxy_port',
-                  default=_DEFAULT_KUBERNETES_PROXY_PORT,
-                  type=int,
-                  help='The port on which the kubernetes proxy (on localhost)'
-                  ' is started')
-argp.add_argument('--stress_server_port',
-                  default=_DEFAULT_STRESS_SERVER_PORT,
-                  type=int,
-                  help='The port on which the stress server (in GKE '
-                  'containers) listens')
-argp.add_argument('--stress_client_metrics_port',
-                  default=_DEFAULT_METRICS_PORT,
-                  type=int,
-                  help='The port on which the stress clients (in GKE '
-                  'containers) expose metrics')
-argp.add_argument('--stress_client_poll_interval_secs',
-                  default=_DEFAULT_STRESS_CLIENT_POLL_INTERVAL_SECS,
-                  type=int,
-                  help='How frequently should the stress client wrapper script'
-                  ' running inside GKE should monitor health of the actual '
-                  ' stress client process and upload the metrics to BigQuery')
-argp.add_argument('--stress_client_metrics_collection_interval_secs',
-                  default=_DEFAULT_METRICS_COLLECTION_INTERVAL_SECS,
-                  type=int,
-                  help='How frequently should metrics be collected in-memory on'
-                  ' the stress clients (running inside GKE containers). Note '
-                  'that this is NOT the same as the upload-to-BigQuery '
-                  'frequency. The metrics upload frequency is controlled by the'
-                  ' --stress_client_poll_interval_secs flag')
-argp.add_argument('--stress_client_num_channels_per_server',
-                  default=_DEFAULT_NUM_CHANNELS_PER_SERVER,
-                  type=int,
-                  help='The number of channels created to each server from a '
-                  'stress client')
-argp.add_argument('--stress_client_num_stubs_per_channel',
-                  default=_DEFAULT_NUM_STUBS_PER_CHANNEL,
-                  type=int,
-                  help='The number of stubs created per channel. This number '
-                  'indicates the max number of RPCs that can be made in '
-                  'parallel on each channel at any given time')
-argp.add_argument('--stress_client_test_cases',
-                  default=_DEFAULT_TEST_CASES_STR,
-                  help='List of test cases (with weights) to be executed by the'
-                  ' stress test client. The list is in the following format:\n'
-                  '  <testcase_1:w_1,<test_case2:w_2>..<testcase_n:w_n>\n'
-                  ' (Note: The weights do not have to add up to 100)')
-
-if __name__ == '__main__':
-  args = argp.parse_args()
-
-  test_settings = TestSettings(
-      args.build_docker_image, args.test_poll_interval_secs,
-      args.test_duration_secs, args.kubernetes_proxy_port)
-
-  gke_settings = GkeSettings(args.project_id, args.docker_image_name)
-
-  stress_server_settings = StressServerSettings(_SERVER_POD_NAME,
-                                                args.stress_server_port)
-  stress_client_settings = StressClientSettings(
-      args.num_clients, _CLIENT_POD_NAME_PREFIX, _SERVER_POD_NAME,
-      args.stress_server_port, args.stress_client_metrics_port,
-      args.stress_client_metrics_collection_interval_secs,
-      args.stress_client_poll_interval_secs,
-      args.stress_client_num_channels_per_server,
-      args.stress_client_num_stubs_per_channel, args.stress_client_test_cases)
-
-  run_test_main(test_settings, gke_settings, stress_server_settings,
-                stress_client_settings)
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index d91245c..5f72b8c 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -266,6 +266,48 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c", 
+    "name": "concurrent_connectivity_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
+    "name": "dns_resolver_connectivity_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
     "name": "dns_resolver_test", 
     "platforms": [
       "linux", 
@@ -424,6 +466,27 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c", 
+    "name": "gpr_backoff_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
     "name": "gpr_cmdline_test", 
     "platforms": [
       "linux", 
@@ -1031,7 +1094,7 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c", 
-    "name": "httpcli_format_request_test", 
+    "name": "http_parser_test", 
     "platforms": [
       "linux", 
       "mac", 
@@ -1052,7 +1115,7 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c", 
-    "name": "httpcli_parser_test", 
+    "name": "httpcli_format_request_test", 
     "platforms": [
       "linux", 
       "mac", 
@@ -1230,7 +1293,7 @@
     ], 
     "cpu_cost": 0.1, 
     "exclude_configs": [], 
-    "flaky": false, 
+    "flaky": true, 
     "gtest": false, 
     "language": "c", 
     "name": "lb_policies_test", 
@@ -1272,7 +1335,7 @@
     ], 
     "cpu_cost": 1.0, 
     "exclude_configs": [], 
-    "flaky": false, 
+    "flaky": true, 
     "gtest": false, 
     "language": "c", 
     "name": "mlog_test", 
@@ -1990,6 +2053,27 @@
     "flaky": false, 
     "gtest": true, 
     "language": "c++", 
+    "name": "codegen_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
     "name": "credentials_test", 
     "platforms": [
       "linux", 
@@ -2232,7 +2316,7 @@
       "mac", 
       "posix"
     ], 
-    "cpu_cost": 10, 
+    "cpu_cost": 0.5, 
     "exclude_configs": [], 
     "flaky": false, 
     "gtest": false, 
@@ -2709,6 +2793,30 @@
     ], 
     "flaky": false, 
     "language": "c++", 
+    "name": "boringssl_asn1_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan"
+    ], 
+    "flaky": false, 
+    "language": "c++", 
     "name": "boringssl_base64_test", 
     "platforms": [
       "linux", 
@@ -9034,6 +9142,776 @@
     "ci_platforms": [
       "windows", 
       "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "binary_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "call_creds"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_accept"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_client_done"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_invoke"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_before_invoke"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_in_a_vacuum"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_with_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "compressed_payload"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "connectivity"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "default_host"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "disappearing_server"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "empty_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "graceful_server_shutdown"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "high_initial_seqno"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "invoke_large_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "large_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "max_concurrent_streams"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "max_message_length"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "negative_deadline"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "no_op"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "payload"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "ping_pong_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "registered_call"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "request_with_flags"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "request_with_payload"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "server_finishes_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "shutdown_finishes_calls"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "shutdown_finishes_tags"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_delayed_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "trailing_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "bad_hostname"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11071,7 +11949,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11093,7 +11970,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11115,7 +11991,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11137,7 +12012,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -11159,7 +12033,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -11181,7 +12054,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -11203,7 +12075,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -11225,7 +12096,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -11247,7 +12117,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -11269,7 +12138,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -11291,7 +12159,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11313,7 +12180,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -11335,7 +12201,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11357,7 +12222,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11379,7 +12243,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11401,7 +12264,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11423,7 +12285,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -11445,7 +12306,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11467,7 +12327,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11489,7 +12348,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -11511,7 +12369,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11533,7 +12390,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11555,7 +12411,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11577,7 +12432,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11599,7 +12453,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11621,7 +12474,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11643,7 +12495,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11665,7 +12516,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11687,7 +12537,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -11709,7 +12558,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -14378,688 +15226,6 @@
       "bad_hostname"
     ], 
     "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "binary_metadata"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "call_creds"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "cancel_after_accept"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "cancel_after_client_done"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "cancel_after_invoke"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "cancel_before_invoke"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "cancel_in_a_vacuum"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "cancel_with_status"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "compressed_payload"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "empty_batch"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "graceful_server_shutdown"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "high_initial_seqno"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "hpack_size"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "invoke_large_request"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "large_metadata"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "max_concurrent_streams"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "max_message_length"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "negative_deadline"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "no_op"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "payload"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "ping_pong_streaming"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "registered_call"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "request_with_flags"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "request_with_payload"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "server_finishes_request"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "shutdown_finishes_calls"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "shutdown_finishes_tags"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "simple_metadata"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "simple_request"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "trailing_metadata"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "bad_hostname"
-    ], 
-    "ci_platforms": [
       "linux", 
       "mac", 
       "posix"
@@ -20312,6 +20478,754 @@
     "ci_platforms": [
       "windows", 
       "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "binary_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_accept"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_client_done"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_invoke"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_before_invoke"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_in_a_vacuum"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_with_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "compressed_payload"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "connectivity"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "default_host"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "disappearing_server"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "empty_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "graceful_server_shutdown"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "high_initial_seqno"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "invoke_large_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "large_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "max_concurrent_streams"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "max_message_length"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "negative_deadline"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "no_op"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "payload"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "ping_pong_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "registered_call"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "request_with_flags"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "request_with_payload"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "server_finishes_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "shutdown_finishes_calls"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "shutdown_finishes_tags"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_delayed_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "trailing_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "bad_hostname"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -21551,7 +22465,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -21573,7 +22486,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -21595,7 +22507,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -21617,7 +22528,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -21639,7 +22549,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -21661,7 +22570,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -21683,7 +22591,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -21705,7 +22612,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -21727,7 +22633,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -21749,7 +22654,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -21771,7 +22675,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -21793,7 +22696,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -21815,7 +22717,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -21837,7 +22738,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -21859,7 +22759,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -21881,7 +22780,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -21903,7 +22801,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -21925,7 +22822,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -21947,7 +22843,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -21969,7 +22864,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -21991,7 +22885,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -22013,7 +22906,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -22035,7 +22927,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -22057,7 +22948,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -22079,7 +22969,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -22101,7 +22990,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -22123,7 +23011,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -22145,7 +23032,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -22167,7 +23053,6 @@
     "ci_platforms": [
       "windows", 
       "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -22817,666 +23702,6 @@
       "bad_hostname"
     ], 
     "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "binary_metadata"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "cancel_after_accept"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "cancel_after_client_done"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "cancel_after_invoke"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "cancel_before_invoke"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "cancel_in_a_vacuum"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "cancel_with_status"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "compressed_payload"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "empty_batch"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "graceful_server_shutdown"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "high_initial_seqno"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "hpack_size"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "invoke_large_request"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "large_metadata"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "max_concurrent_streams"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "max_message_length"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "negative_deadline"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "no_op"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "payload"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 0.1, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "ping_pong_streaming"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "registered_call"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "request_with_flags"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "request_with_payload"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "server_finishes_request"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "shutdown_finishes_calls"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "shutdown_finishes_tags"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "simple_metadata"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "simple_request"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "trailing_metadata"
-    ], 
-    "ci_platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "h2_uchannel_nosec_test", 
-    "platforms": [
-      "windows", 
-      "linux", 
-      "mac", 
-      "posix"
-    ]
-  }, 
-  {
-    "args": [
-      "bad_hostname"
-    ], 
-    "ci_platforms": [
       "linux", 
       "mac", 
       "posix"
diff --git a/vsprojects/build_vs2010.bat b/vsprojects/build_vs2010.bat
index 64b0ed5..1bc3c86 100644
--- a/vsprojects/build_vs2010.bat
+++ b/vsprojects/build_vs2010.bat
@@ -1,5 +1,5 @@
 @rem Convenience wrapper that runs specified gRPC target using msbuild
-@rem Usage: build.bat TARGET_NAME
+@rem Usage: build_vs2010.bat TARGET_NAME
 
 setlocal
 @rem Set VS variables (uses Visual Studio 2010)
diff --git a/vsprojects/build_vs2013.bat b/vsprojects/build_vs2013.bat
index be3caa9..82c0a3a 100644
--- a/vsprojects/build_vs2013.bat
+++ b/vsprojects/build_vs2013.bat
@@ -1,5 +1,5 @@
 @rem Convenience wrapper that runs specified gRPC target using msbuild
-@rem Usage: build.bat TARGET_NAME
+@rem Usage: build_vs2013.bat TARGET_NAME
 
 setlocal
 @rem Set VS variables (uses Visual Studio 2013)
diff --git a/vsprojects/build_vs2015.bat b/vsprojects/build_vs2015.bat
index 50485a3..c6e1b43 100644
--- a/vsprojects/build_vs2015.bat
+++ b/vsprojects/build_vs2015.bat
@@ -1,5 +1,5 @@
 @rem Convenience wrapper that runs specified gRPC target using msbuild
-@rem Usage: build.bat TARGET_NAME
+@rem Usage: build_vs2015.bat TARGET_NAME
 
 setlocal
 @rem Set VS variables (uses Visual Studio 2015)
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index 7cdc3b7..96dc4eb 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -100,7 +100,6 @@
         	lib = "True"
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
@@ -118,11 +117,6 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "end2end_certs", "vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj", "{80EA2691-C037-6DD3-D3AB-21510BF0E64B}"
-	ProjectSection(myProperties) = preProject
-        	lib = "True"
-	EndProjectSection
-EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "alarm_test", "vcxproj\test\alarm_test\alarm_test.vcxproj", "{AFD362D7-0E2A-E700-1F27-9D90F76166DF}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -251,6 +245,28 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "concurrent_connectivity_test", "vcxproj\test\concurrent_connectivity_test\concurrent_connectivity_test.vcxproj", "{391B366C-D916-45AA-3FE5-67363A46193B}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dns_resolver_connectivity_test", "vcxproj\test\dns_resolver_connectivity_test\dns_resolver_connectivity_test.vcxproj", "{F7B6FE68-E847-D7CA-4062-E737E542BCC3}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dns_resolver_test", "vcxproj\test\dns_resolver_test\dns_resolver_test.vcxproj", "{D06E10DC-272A-5203-7066-2698A247DF26}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -318,6 +334,15 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpr_backoff_test", "vcxproj\test\gpr_backoff_test\gpr_backoff_test.vcxproj", "{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpr_cmdline_test", "vcxproj\test\gpr_cmdline_test\gpr_cmdline_test.vcxproj", "{10668A5D-65CD-F530-22D0-747B395B4C26}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -638,7 +663,7 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "httpcli_format_request_test", "vcxproj\test\httpcli_format_request_test\httpcli_format_request_test.vcxproj", "{A43C3292-CAE7-1B8C-A5FD-52D9E3DCFD82}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_parser_test", "vcxproj\test\http_parser_test\http_parser_test.vcxproj", "{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
 	EndProjectSection
@@ -649,7 +674,7 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "httpcli_parser_test", "vcxproj\test\httpcli_parser_test\httpcli_parser_test.vcxproj", "{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "httpcli_format_request_test", "vcxproj\test\httpcli_format_request_test\httpcli_format_request_test.vcxproj", "{A43C3292-CAE7-1B8C-A5FD-52D9E3DCFD82}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
 	EndProjectSection
@@ -1078,7 +1103,6 @@
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
 		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
@@ -1091,7 +1115,6 @@
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
 		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
@@ -1104,7 +1127,6 @@
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
 		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
@@ -1117,7 +1139,18 @@
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
 		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h2_full+trace_test", "vcxproj\test/end2end/fixtures\h2_full+trace_test\h2_full+trace_test.vcxproj", "{16C713C6-062E-F71F-A44C-52DC35494B27}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
@@ -1130,7 +1163,6 @@
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
 		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
@@ -1143,7 +1175,6 @@
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
 		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
@@ -1156,7 +1187,6 @@
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
 		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
@@ -1169,7 +1199,6 @@
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
 		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
@@ -1182,7 +1211,6 @@
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
 		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
@@ -1195,7 +1223,6 @@
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
 		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
@@ -1208,20 +1235,6 @@
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
 		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
-		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
-		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
-		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
-		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h2_uchannel_test", "vcxproj\test/end2end/fixtures\h2_uchannel_test\h2_uchannel_test.vcxproj", "{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}"
-	ProjectSection(myProperties) = preProject
-        	lib = "False"
-	EndProjectSection
-	ProjectSection(ProjectDependencies) = postProject
-		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B} = {80EA2691-C037-6DD3-D3AB-21510BF0E64B}
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
@@ -1264,6 +1277,18 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h2_full+trace_nosec_test", "vcxproj\test/end2end/fixtures\h2_full+trace_nosec_test\h2_full+trace_nosec_test.vcxproj", "{DFD51943-4906-8051-7D66-6A7D50E0D87E}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{47C2CB41-4E9F-58B6-F606-F6FAED5D00ED} = {47C2CB41-4E9F-58B6-F606-F6FAED5D00ED}
+		{0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF} = {0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF}
+		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5} = {46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h2_proxy_nosec_test", "vcxproj\test/end2end/fixtures\h2_proxy_nosec_test\h2_proxy_nosec_test.vcxproj", "{6EC72045-98CB-8A8D-9788-BC94209E23C8}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -1312,18 +1337,6 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h2_uchannel_nosec_test", "vcxproj\test/end2end/fixtures\h2_uchannel_nosec_test\h2_uchannel_nosec_test.vcxproj", "{BD79A629-4181-DB5E-C28F-44EB280A6F91}"
-	ProjectSection(myProperties) = preProject
-        	lib = "False"
-	EndProjectSection
-	ProjectSection(ProjectDependencies) = postProject
-		{47C2CB41-4E9F-58B6-F606-F6FAED5D00ED} = {47C2CB41-4E9F-58B6-F606-F6FAED5D00ED}
-		{0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF} = {0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF}
-		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5} = {46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}
-		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
-		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
-	EndProjectSection
-EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
@@ -1528,22 +1541,6 @@
 		{47C2CB41-4E9F-58B6-F606-F6FAED5D00ED}.Release-DLL|Win32.Build.0 = Release|Win32
 		{47C2CB41-4E9F-58B6-F606-F6FAED5D00ED}.Release-DLL|x64.ActiveCfg = Release|x64
 		{47C2CB41-4E9F-58B6-F606-F6FAED5D00ED}.Release-DLL|x64.Build.0 = Release|x64
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Debug|Win32.ActiveCfg = Debug|Win32
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Debug|x64.ActiveCfg = Debug|x64
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Release|Win32.ActiveCfg = Release|Win32
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Release|x64.ActiveCfg = Release|x64
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Debug|Win32.Build.0 = Debug|Win32
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Debug|x64.Build.0 = Debug|x64
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Release|Win32.Build.0 = Release|Win32
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Release|x64.Build.0 = Release|x64
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Debug-DLL|Win32.Build.0 = Debug|Win32
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Debug-DLL|x64.ActiveCfg = Debug|x64
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Debug-DLL|x64.Build.0 = Debug|x64
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Release-DLL|Win32.ActiveCfg = Release|Win32
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Release-DLL|Win32.Build.0 = Release|Win32
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Release-DLL|x64.ActiveCfg = Release|x64
-		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Release-DLL|x64.Build.0 = Release|x64
 		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Debug|Win32.ActiveCfg = Debug|Win32
 		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Debug|x64.ActiveCfg = Debug|x64
 		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Release|Win32.ActiveCfg = Release|Win32
@@ -1736,6 +1733,38 @@
 		{5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}.Release-DLL|Win32.Build.0 = Release|Win32
 		{5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}.Release-DLL|x64.ActiveCfg = Release|x64
 		{5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}.Release-DLL|x64.Build.0 = Release|x64
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Debug|x64.ActiveCfg = Debug|x64
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Release|Win32.ActiveCfg = Release|Win32
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Release|x64.ActiveCfg = Release|x64
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Debug|Win32.Build.0 = Debug|Win32
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Debug|x64.Build.0 = Debug|x64
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Release|Win32.Build.0 = Release|Win32
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Release|x64.Build.0 = Release|x64
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Debug-DLL|x64.Build.0 = Debug|x64
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Release-DLL|Win32.Build.0 = Release|Win32
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Release-DLL|x64.ActiveCfg = Release|x64
+		{391B366C-D916-45AA-3FE5-67363A46193B}.Release-DLL|x64.Build.0 = Release|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug|x64.ActiveCfg = Debug|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release|Win32.ActiveCfg = Release|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release|x64.ActiveCfg = Release|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug|Win32.Build.0 = Debug|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug|x64.Build.0 = Debug|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release|Win32.Build.0 = Release|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release|x64.Build.0 = Release|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug-DLL|x64.Build.0 = Debug|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release-DLL|Win32.Build.0 = Release|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release-DLL|x64.ActiveCfg = Release|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release-DLL|x64.Build.0 = Release|x64
 		{D06E10DC-272A-5203-7066-2698A247DF26}.Debug|Win32.ActiveCfg = Debug|Win32
 		{D06E10DC-272A-5203-7066-2698A247DF26}.Debug|x64.ActiveCfg = Debug|x64
 		{D06E10DC-272A-5203-7066-2698A247DF26}.Release|Win32.ActiveCfg = Release|Win32
@@ -1848,6 +1877,22 @@
 		{144D8CFF-2737-A18A-DCFD-01603533D63F}.Release-DLL|Win32.Build.0 = Release|Win32
 		{144D8CFF-2737-A18A-DCFD-01603533D63F}.Release-DLL|x64.ActiveCfg = Release|x64
 		{144D8CFF-2737-A18A-DCFD-01603533D63F}.Release-DLL|x64.Build.0 = Release|x64
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Debug|Win32.ActiveCfg = Debug|Win32
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Debug|x64.ActiveCfg = Debug|x64
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Release|Win32.ActiveCfg = Release|Win32
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Release|x64.ActiveCfg = Release|x64
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Debug|Win32.Build.0 = Debug|Win32
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Debug|x64.Build.0 = Debug|x64
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Release|Win32.Build.0 = Release|Win32
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Release|x64.Build.0 = Release|x64
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Debug-DLL|x64.Build.0 = Debug|x64
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Release-DLL|Win32.Build.0 = Release|Win32
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Release-DLL|x64.ActiveCfg = Release|x64
+		{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}.Release-DLL|x64.Build.0 = Release|x64
 		{10668A5D-65CD-F530-22D0-747B395B4C26}.Debug|Win32.ActiveCfg = Debug|Win32
 		{10668A5D-65CD-F530-22D0-747B395B4C26}.Debug|x64.ActiveCfg = Debug|x64
 		{10668A5D-65CD-F530-22D0-747B395B4C26}.Release|Win32.ActiveCfg = Release|Win32
@@ -2360,6 +2405,22 @@
 		{FF2CEE6D-850F-E22C-53A0-8C5912B14B20}.Release-DLL|Win32.Build.0 = Release|Win32
 		{FF2CEE6D-850F-E22C-53A0-8C5912B14B20}.Release-DLL|x64.ActiveCfg = Release|x64
 		{FF2CEE6D-850F-E22C-53A0-8C5912B14B20}.Release-DLL|x64.Build.0 = Release|x64
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Debug|Win32.ActiveCfg = Debug|Win32
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Debug|x64.ActiveCfg = Debug|x64
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Release|Win32.ActiveCfg = Release|Win32
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Release|x64.ActiveCfg = Release|x64
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Debug|Win32.Build.0 = Debug|Win32
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Debug|x64.Build.0 = Debug|x64
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Release|Win32.Build.0 = Release|Win32
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Release|x64.Build.0 = Release|x64
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Debug-DLL|x64.Build.0 = Debug|x64
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Release-DLL|Win32.Build.0 = Release|Win32
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Release-DLL|x64.ActiveCfg = Release|x64
+		{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}.Release-DLL|x64.Build.0 = Release|x64
 		{A43C3292-CAE7-1B8C-A5FD-52D9E3DCFD82}.Debug|Win32.ActiveCfg = Debug|Win32
 		{A43C3292-CAE7-1B8C-A5FD-52D9E3DCFD82}.Debug|x64.ActiveCfg = Debug|x64
 		{A43C3292-CAE7-1B8C-A5FD-52D9E3DCFD82}.Release|Win32.ActiveCfg = Release|Win32
@@ -2376,22 +2437,6 @@
 		{A43C3292-CAE7-1B8C-A5FD-52D9E3DCFD82}.Release-DLL|Win32.Build.0 = Release|Win32
 		{A43C3292-CAE7-1B8C-A5FD-52D9E3DCFD82}.Release-DLL|x64.ActiveCfg = Release|x64
 		{A43C3292-CAE7-1B8C-A5FD-52D9E3DCFD82}.Release-DLL|x64.Build.0 = Release|x64
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Debug|Win32.ActiveCfg = Debug|Win32
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Debug|x64.ActiveCfg = Debug|x64
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Release|Win32.ActiveCfg = Release|Win32
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Release|x64.ActiveCfg = Release|x64
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Debug|Win32.Build.0 = Debug|Win32
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Debug|x64.Build.0 = Debug|x64
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Release|Win32.Build.0 = Release|Win32
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Release|x64.Build.0 = Release|x64
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Debug-DLL|Win32.Build.0 = Debug|Win32
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Debug-DLL|x64.ActiveCfg = Debug|x64
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Debug-DLL|x64.Build.0 = Debug|x64
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Release-DLL|Win32.ActiveCfg = Release|Win32
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Release-DLL|Win32.Build.0 = Release|Win32
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Release-DLL|x64.ActiveCfg = Release|x64
-		{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}.Release-DLL|x64.Build.0 = Release|x64
 		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Debug|Win32.ActiveCfg = Debug|Win32
 		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Debug|x64.ActiveCfg = Debug|x64
 		{117CA7AD-C42B-9217-6C95-42A801777BC5}.Release|Win32.ActiveCfg = Release|Win32
@@ -3048,6 +3093,22 @@
 		{EEBEFA75-C625-C823-FE96-9AD64887B57D}.Release-DLL|Win32.Build.0 = Release|Win32
 		{EEBEFA75-C625-C823-FE96-9AD64887B57D}.Release-DLL|x64.ActiveCfg = Release|x64
 		{EEBEFA75-C625-C823-FE96-9AD64887B57D}.Release-DLL|x64.Build.0 = Release|x64
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Debug|Win32.ActiveCfg = Debug|Win32
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Debug|x64.ActiveCfg = Debug|x64
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Release|Win32.ActiveCfg = Release|Win32
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Release|x64.ActiveCfg = Release|x64
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Debug|Win32.Build.0 = Debug|Win32
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Debug|x64.Build.0 = Debug|x64
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Release|Win32.Build.0 = Release|Win32
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Release|x64.Build.0 = Release|x64
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Debug-DLL|x64.Build.0 = Debug|x64
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Release-DLL|Win32.Build.0 = Release|Win32
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Release-DLL|x64.ActiveCfg = Release|x64
+		{16C713C6-062E-F71F-A44C-52DC35494B27}.Release-DLL|x64.Build.0 = Release|x64
 		{0F761FF3-342A-C429-711F-F76181BAA52D}.Debug|Win32.ActiveCfg = Debug|Win32
 		{0F761FF3-342A-C429-711F-F76181BAA52D}.Debug|x64.ActiveCfg = Debug|x64
 		{0F761FF3-342A-C429-711F-F76181BAA52D}.Release|Win32.ActiveCfg = Release|Win32
@@ -3160,22 +3221,6 @@
 		{A9092608-E45E-AC96-6533-A6E7DD98211D}.Release-DLL|Win32.Build.0 = Release|Win32
 		{A9092608-E45E-AC96-6533-A6E7DD98211D}.Release-DLL|x64.ActiveCfg = Release|x64
 		{A9092608-E45E-AC96-6533-A6E7DD98211D}.Release-DLL|x64.Build.0 = Release|x64
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Debug|Win32.ActiveCfg = Debug|Win32
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Debug|x64.ActiveCfg = Debug|x64
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Release|Win32.ActiveCfg = Release|Win32
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Release|x64.ActiveCfg = Release|x64
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Debug|Win32.Build.0 = Debug|Win32
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Debug|x64.Build.0 = Debug|x64
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Release|Win32.Build.0 = Release|Win32
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Release|x64.Build.0 = Release|x64
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Debug-DLL|Win32.Build.0 = Debug|Win32
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Debug-DLL|x64.ActiveCfg = Debug|x64
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Debug-DLL|x64.Build.0 = Debug|x64
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Release-DLL|Win32.ActiveCfg = Release|Win32
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Release-DLL|Win32.Build.0 = Release|Win32
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Release-DLL|x64.ActiveCfg = Release|x64
-		{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}.Release-DLL|x64.Build.0 = Release|x64
 		{A8039D43-910E-4248-2A22-74366E8C4DCD}.Debug|Win32.ActiveCfg = Debug|Win32
 		{A8039D43-910E-4248-2A22-74366E8C4DCD}.Debug|x64.ActiveCfg = Debug|x64
 		{A8039D43-910E-4248-2A22-74366E8C4DCD}.Release|Win32.ActiveCfg = Release|Win32
@@ -3224,6 +3269,22 @@
 		{345EA50E-BCD4-DAC7-E1C8-DDA6291B75E2}.Release-DLL|Win32.Build.0 = Release|Win32
 		{345EA50E-BCD4-DAC7-E1C8-DDA6291B75E2}.Release-DLL|x64.ActiveCfg = Release|x64
 		{345EA50E-BCD4-DAC7-E1C8-DDA6291B75E2}.Release-DLL|x64.Build.0 = Release|x64
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Debug|Win32.ActiveCfg = Debug|Win32
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Debug|x64.ActiveCfg = Debug|x64
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Release|Win32.ActiveCfg = Release|Win32
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Release|x64.ActiveCfg = Release|x64
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Debug|Win32.Build.0 = Debug|Win32
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Debug|x64.Build.0 = Debug|x64
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Release|Win32.Build.0 = Release|Win32
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Release|x64.Build.0 = Release|x64
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Debug-DLL|x64.Build.0 = Debug|x64
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Release-DLL|Win32.Build.0 = Release|Win32
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Release-DLL|x64.ActiveCfg = Release|x64
+		{DFD51943-4906-8051-7D66-6A7D50E0D87E}.Release-DLL|x64.Build.0 = Release|x64
 		{6EC72045-98CB-8A8D-9788-BC94209E23C8}.Debug|Win32.ActiveCfg = Debug|Win32
 		{6EC72045-98CB-8A8D-9788-BC94209E23C8}.Debug|x64.ActiveCfg = Debug|x64
 		{6EC72045-98CB-8A8D-9788-BC94209E23C8}.Release|Win32.ActiveCfg = Release|Win32
@@ -3288,22 +3349,6 @@
 		{485E6713-487D-F274-BDE7-5D29300C93FE}.Release-DLL|Win32.Build.0 = Release|Win32
 		{485E6713-487D-F274-BDE7-5D29300C93FE}.Release-DLL|x64.ActiveCfg = Release|x64
 		{485E6713-487D-F274-BDE7-5D29300C93FE}.Release-DLL|x64.Build.0 = Release|x64
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Debug|Win32.ActiveCfg = Debug|Win32
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Debug|x64.ActiveCfg = Debug|x64
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Release|Win32.ActiveCfg = Release|Win32
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Release|x64.ActiveCfg = Release|x64
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Debug|Win32.Build.0 = Debug|Win32
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Debug|x64.Build.0 = Debug|x64
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Release|Win32.Build.0 = Release|Win32
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Release|x64.Build.0 = Release|x64
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Debug-DLL|Win32.Build.0 = Debug|Win32
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Debug-DLL|x64.ActiveCfg = Debug|x64
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Debug-DLL|x64.Build.0 = Debug|x64
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Release-DLL|Win32.ActiveCfg = Release|Win32
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Release-DLL|Win32.Build.0 = Release|Win32
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Release-DLL|x64.ActiveCfg = Release|x64
-		{BD79A629-4181-DB5E-C28F-44EB280A6F91}.Release-DLL|x64.Build.0 = Release|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/vsprojects/grpc.sln b/vsprojects/grpc.sln
index 3f6b337..851bca0 100644
--- a/vsprojects/grpc.sln
+++ b/vsprojects/grpc.sln
@@ -92,6 +92,11 @@
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc++_codegen_lib", "vcxproj\.\grpc++_codegen_lib\grpc++_codegen_lib.vcxproj", "{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}"
+	ProjectSection(myProperties) = preProject
+        	lib = "True"
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc++_unsecure", "vcxproj\.\grpc++_unsecure\grpc++_unsecure.vcxproj", "{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}"
 	ProjectSection(myProperties) = preProject
         	lib = "True"
@@ -341,6 +346,22 @@
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release-DLL|Win32.Build.0 = Release-DLL|Win32
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release-DLL|x64.ActiveCfg = Release-DLL|x64
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release-DLL|x64.Build.0 = Release-DLL|x64
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Debug|Win32.ActiveCfg = Debug|Win32
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Debug|x64.ActiveCfg = Debug|x64
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Release|Win32.ActiveCfg = Release|Win32
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Release|x64.ActiveCfg = Release|x64
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Debug|Win32.Build.0 = Debug|Win32
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Debug|x64.Build.0 = Debug|x64
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Release|Win32.Build.0 = Release|Win32
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Release|x64.Build.0 = Release|x64
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Debug-DLL|x64.Build.0 = Debug|x64
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Release-DLL|Win32.Build.0 = Release|Win32
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Release-DLL|x64.ActiveCfg = Release|x64
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}.Release-DLL|x64.Build.0 = Release|x64
 		{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}.Debug|Win32.ActiveCfg = Debug|Win32
 		{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}.Debug|x64.ActiveCfg = Debug|x64
 		{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/grpc_protoc_plugins.sln b/vsprojects/grpc_protoc_plugins.sln
index ef1cbb8..444cb26 100644
--- a/vsprojects/grpc_protoc_plugins.sln
+++ b/vsprojects/grpc_protoc_plugins.sln
@@ -3,10 +3,18 @@
 # Visual Studio 2013
 VisualStudioVersion = 12.0.21005.1
 MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_codegen_lib", "vcxproj\.\grpc_codegen_lib\grpc_codegen_lib.vcxproj", "{A828FD72-44CE-4EA5-8966-6E4624458D58}"
+	ProjectSection(myProperties) = preProject
+        	lib = "True"
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_plugin_support", "vcxproj\.\grpc_plugin_support\grpc_plugin_support.vcxproj", "{B6E81D84-2ACB-41B8-8781-493A944C7817}"
 	ProjectSection(myProperties) = preProject
         	lib = "True"
 	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500} = {AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}
+	EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_cpp_plugin", "vcxproj\.\grpc_cpp_plugin\grpc_cpp_plugin.vcxproj", "{7E51A25F-AC59-488F-906C-C60FAAE706AA}"
 	ProjectSection(myProperties) = preProject
@@ -56,6 +64,14 @@
 		Release|x64 = Release|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{A828FD72-44CE-4EA5-8966-6E4624458D58}.Debug|Win32.ActiveCfg = Debug|Win32
+		{A828FD72-44CE-4EA5-8966-6E4624458D58}.Debug|x64.ActiveCfg = Debug|x64
+		{A828FD72-44CE-4EA5-8966-6E4624458D58}.Release|Win32.ActiveCfg = Release|Win32
+		{A828FD72-44CE-4EA5-8966-6E4624458D58}.Release|x64.ActiveCfg = Release|x64
+		{A828FD72-44CE-4EA5-8966-6E4624458D58}.Debug|Win32.Build.0 = Debug|Win32
+		{A828FD72-44CE-4EA5-8966-6E4624458D58}.Debug|x64.Build.0 = Debug|x64
+		{A828FD72-44CE-4EA5-8966-6E4624458D58}.Release|Win32.Build.0 = Release|Win32
+		{A828FD72-44CE-4EA5-8966-6E4624458D58}.Release|x64.Build.0 = Release|x64
 		{B6E81D84-2ACB-41B8-8781-493A944C7817}.Debug|Win32.ActiveCfg = Debug|Win32
 		{B6E81D84-2ACB-41B8-8781-493A944C7817}.Debug|x64.ActiveCfg = Debug|x64
 		{B6E81D84-2ACB-41B8-8781-493A944C7817}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/vcxproj/gpr/gpr.vcxproj b/vsprojects/vcxproj/gpr/gpr.vcxproj
index dae8e62..870246c 100644
--- a/vsprojects/vcxproj/gpr/gpr.vcxproj
+++ b/vsprojects/vcxproj/gpr/gpr.vcxproj
@@ -147,6 +147,20 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\alloc.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\atm.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\atm_gcc_atomic.h" />
@@ -175,120 +189,109 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\tls_msvc.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\tls_pthread.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\useful.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\src\core\profiling\timers.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\block_annotate.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\env.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\load_file.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\murmur_hash.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\stack_lockfree.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\string.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\string_win32.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\thd_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\time_precise.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\tmpfile.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\profiling\timers.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\backoff.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\block_annotate.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\env.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\load_file.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\murmur_hash.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\stack_lockfree.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\string.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\string_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\thd_internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\time_precise.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\tmpfile.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\core\profiling\basic_timers.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\profiling\basic_timers.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\profiling\stap_timers.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\profiling\stap_timers.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\alloc.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\alloc.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\avl.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\avl.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cmdline.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\backoff.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cpu_iphone.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cmdline.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cpu_linux.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cpu_iphone.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cpu_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cpu_linux.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cpu_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cpu_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\env_linux.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cpu_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\env_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\env_linux.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\env_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\env_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\histogram.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\env_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\host_port.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\histogram.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\load_file.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\host_port.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\load_file.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log_android.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log_linux.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_android.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_linux.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\murmur_hash.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\slice.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\murmur_hash.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\slice_buffer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\slice.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\stack_lockfree.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\slice_buffer.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\stack_lockfree.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\string_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\string_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\string_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\subprocess_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\string_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\subprocess_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\subprocess_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\sync.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\subprocess_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\sync_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\sync.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\sync_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\sync_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\thd.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\sync_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\thd_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\thd.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\thd_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\thd_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\time.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\thd_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\time_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\time.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\time_precise.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\time_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\time_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\time_precise.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\tls_pthread.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\time_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\tmpfile_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\tls_pthread.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\tmpfile_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\tmpfile_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\wrap_memcpy.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\tmpfile_win32.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\wrap_memcpy.c">
     </ClCompile>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff --git a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters
index 055b29f..b932420 100644
--- a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters
+++ b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters
@@ -1,137 +1,182 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\core\profiling\basic_timers.c">
-      <Filter>src\core\profiling</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\profiling\basic_timers.c">
+      <Filter>src\core\lib\profiling</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\profiling\stap_timers.c">
-      <Filter>src\core\profiling</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\profiling\stap_timers.c">
+      <Filter>src\core\lib\profiling</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\alloc.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\alloc.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\avl.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\avl.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cmdline.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\backoff.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cpu_iphone.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cmdline.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cpu_linux.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cpu_iphone.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cpu_posix.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cpu_linux.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\cpu_windows.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cpu_posix.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\env_linux.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\cpu_windows.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\env_posix.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\env_linux.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\env_win32.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\env_posix.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\histogram.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\env_win32.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\host_port.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\histogram.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\load_file.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\host_port.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\load_file.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log_android.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log_linux.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_android.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log_posix.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_linux.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\log_win32.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_posix.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\murmur_hash.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_win32.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\slice.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\murmur_hash.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\slice_buffer.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\slice.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\stack_lockfree.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\slice_buffer.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\string.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\stack_lockfree.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\string_posix.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\string.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\string_win32.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\string_posix.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\subprocess_posix.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\string_win32.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\subprocess_windows.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\subprocess_posix.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\sync.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\subprocess_windows.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\sync_posix.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\sync.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\sync_win32.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\sync_posix.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\thd.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\sync_win32.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\thd_posix.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\thd.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\thd_win32.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\thd_posix.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\time.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\thd_win32.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\time_posix.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\time.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\time_precise.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\time_posix.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\time_win32.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\time_precise.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\tls_pthread.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\time_win32.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\tmpfile_posix.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\tls_pthread.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\tmpfile_win32.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\tmpfile_posix.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\support\wrap_memcpy.c">
-      <Filter>src\core\support</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\tmpfile_win32.c">
+      <Filter>src\core\lib\support</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\wrap_memcpy.c">
+      <Filter>src\core\lib\support</Filter>
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\alloc.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
@@ -216,82 +261,43 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\useful.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\src\core\profiling\timers.h">
-      <Filter>src\core\profiling</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\profiling\timers.h">
+      <Filter>src\core\lib\profiling</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\block_annotate.h">
-      <Filter>src\core\support</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\backoff.h">
+      <Filter>src\core\lib\support</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\env.h">
-      <Filter>src\core\support</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\block_annotate.h">
+      <Filter>src\core\lib\support</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\load_file.h">
-      <Filter>src\core\support</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\env.h">
+      <Filter>src\core\lib\support</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\murmur_hash.h">
-      <Filter>src\core\support</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\load_file.h">
+      <Filter>src\core\lib\support</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\stack_lockfree.h">
-      <Filter>src\core\support</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\murmur_hash.h">
+      <Filter>src\core\lib\support</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\string.h">
-      <Filter>src\core\support</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\stack_lockfree.h">
+      <Filter>src\core\lib\support</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\string_win32.h">
-      <Filter>src\core\support</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\string.h">
+      <Filter>src\core\lib\support</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\thd_internal.h">
-      <Filter>src\core\support</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\string_win32.h">
+      <Filter>src\core\lib\support</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\time_precise.h">
-      <Filter>src\core\support</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\thd_internal.h">
+      <Filter>src\core\lib\support</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\support\tmpfile.h">
-      <Filter>src\core\support</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\time_precise.h">
+      <Filter>src\core\lib\support</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\tmpfile.h">
+      <Filter>src\core\lib\support</Filter>
     </ClInclude>
   </ItemGroup>
 
@@ -317,11 +323,14 @@
     <Filter Include="src\core">
       <UniqueIdentifier>{c5e1baa7-de77-beb1-9675-942261648f79}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\profiling">
-      <UniqueIdentifier>{93b7086c-8c8a-6bbf-fb14-1f166bf0146a}</UniqueIdentifier>
+    <Filter Include="src\core\lib">
+      <UniqueIdentifier>{52037bcb-5719-a548-224d-834fbe569045}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\support">
-      <UniqueIdentifier>{bb116f2a-ea2a-c233-82da-0c54e3cbfec1}</UniqueIdentifier>
+    <Filter Include="src\core\lib\profiling">
+      <UniqueIdentifier>{ba38d79d-d5de-a89e-9ca2-c5235a03ca7f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\support">
+      <UniqueIdentifier>{a4812158-7fba-959e-4e09-50167fe38df8}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
 </Project>
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
index 0b8c345..2c64421 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
@@ -268,6 +268,37 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\grpc++.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\call.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\client_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\core_codegen_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\grpc_library.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\method_handler_impl.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\proto_utils.h" />
@@ -302,59 +333,18 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\stub_options.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\sync_stream.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\time.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\src\cpp\client\secure_credentials.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\cpp\common\secure_auth_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\cpp\server\secure_server_credentials.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\client\secure_credentials.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\common\core_codegen.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\common\create_auth_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\common\secure_auth_context.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\dynamic_thread_pool.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\server\secure_server_credentials.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\thread_pool_interface.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\client\secure_credentials.cc">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\auth_property_iterator.cc">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\secure_auth_context.cc">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\secure_channel_arguments.cc">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\secure_create_auth_context.cc">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\server\secure_server_credentials.cc">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\channel.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\client_context.cc">
@@ -369,15 +359,25 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\insecure_credentials.cc">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\call.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\client\secure_credentials.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\auth_property_iterator.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_arguments.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\completion_queue.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\core_codegen.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\proto\proto_utils.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\secure_auth_context.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\secure_channel_arguments.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\secure_create_auth_context.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\async_generic_service.cc">
     </ClCompile>
@@ -387,6 +387,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\insecure_server_credentials.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\server\secure_server_credentials.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\server.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\server_builder.cc">
@@ -405,8 +407,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\grpc_library.cc">
-    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
index 0f3dccf..35468ea 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
@@ -1,24 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\client\secure_credentials.cc">
-      <Filter>src\cpp\client</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\auth_property_iterator.cc">
-      <Filter>src\cpp\common</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\secure_auth_context.cc">
-      <Filter>src\cpp\common</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\secure_channel_arguments.cc">
-      <Filter>src\cpp\common</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\secure_create_auth_context.cc">
-      <Filter>src\cpp\common</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\server\secure_server_credentials.cc">
-      <Filter>src\cpp\server</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\channel.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
@@ -40,7 +22,13 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\insecure_credentials.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\call.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\client\secure_credentials.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.cc">
+      <Filter>src\cpp\codegen</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\auth_property_iterator.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_arguments.cc">
@@ -49,11 +37,20 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\completion_queue.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\core_codegen.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\proto\proto_utils.cc">
-      <Filter>src\cpp\proto</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\secure_auth_context.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\secure_channel_arguments.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\secure_create_auth_context.cc">
+      <Filter>src\cpp\common</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\async_generic_service.cc">
       <Filter>src\cpp\server</Filter>
@@ -67,6 +64,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\insecure_server_credentials.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\server\secure_server_credentials.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\server.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
@@ -94,9 +94,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
       <Filter>src\cpp\util</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\grpc_library.cc">
-      <Filter>src\cpp\codegen</Filter>
-    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\alarm.h">
@@ -129,6 +126,99 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\client_unary_call.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\core_codegen_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h">
+      <Filter>include\grpc++\impl\codegen\security</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\grpc_library.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
@@ -231,116 +321,29 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\time.h">
       <Filter>include\grpc++\support</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h">
-      <Filter>include\grpc++\impl\codegen\security</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h">
+      <Filter>src\cpp\client</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\secure_credentials.h">
       <Filter>src\cpp\client</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\cpp\common\secure_auth_context.h">
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\common\core_codegen.h">
       <Filter>src\cpp\common</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\cpp\server\secure_server_credentials.h">
-      <Filter>src\cpp\server</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h">
-      <Filter>src\cpp\client</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\common\create_auth_context.h">
       <Filter>src\cpp\common</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\common\secure_auth_context.h">
+      <Filter>src\cpp\common</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\dynamic_thread_pool.h">
       <Filter>src\cpp\server</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\server\secure_server_credentials.h">
+      <Filter>src\cpp\server</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\thread_pool_interface.h">
       <Filter>src\cpp\server</Filter>
     </ClInclude>
@@ -386,9 +389,6 @@
     <Filter Include="src\cpp\common">
       <UniqueIdentifier>{2336e396-7e0b-8bf9-3b09-adc6ad1f0e5b}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\cpp\proto">
-      <UniqueIdentifier>{c22e8b9b-d2eb-a2e8-0cb8-3f7e3c902a7b}</UniqueIdentifier>
-    </Filter>
     <Filter Include="src\cpp\server">
       <UniqueIdentifier>{321b0980-74ad-e8ca-f23b-deffa5d6bb8f}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj b/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj
new file mode 100644
index 0000000..fa56d2a
--- /dev/null
+++ b/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>grpc++_codegen_lib</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>grpc++_codegen_lib</TargetName>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\core_codegen_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.cc">
+    </ClCompile>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj.filters b/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj.filters
new file mode 100644
index 0000000..3259e98
--- /dev/null
+++ b/vsprojects/vcxproj/grpc++_codegen_lib/grpc++_codegen_lib.vcxproj.filters
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.cc">
+      <Filter>src\cpp\codegen</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\core_codegen_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h">
+      <Filter>include\grpc++\impl\codegen\security</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="include">
+      <UniqueIdentifier>{cf409044-341b-37b5-03f3-0b09c3c474c4}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc">
+      <UniqueIdentifier>{cddccffd-da89-18ad-da57-0c9d704a4633}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++">
+      <UniqueIdentifier>{cb8cb5ad-cf23-a491-046c-1c0688be53ac}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl">
+      <UniqueIdentifier>{a734ff7f-2489-0c04-3fc6-35e361240cf1}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl\codegen">
+      <UniqueIdentifier>{ffc473f2-ece4-fedf-238f-f161e5c3d5e7}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl\codegen\security">
+      <UniqueIdentifier>{89065a9e-e4a0-e5e4-32e9-51cd4cadab46}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl">
+      <UniqueIdentifier>{45ab28cb-74e7-1a53-77c1-bbf2ec383fa2}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl\codegen">
+      <UniqueIdentifier>{311586c5-1a08-e1ba-8dd8-d1cbe10156b3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src">
+      <UniqueIdentifier>{e9bdb195-1cf9-a0f4-231c-fcee59eb54ca}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\cpp">
+      <UniqueIdentifier>{d2e57ea3-c758-0f7c-3bc9-e71dd87bd654}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\cpp\codegen">
+      <UniqueIdentifier>{f93ade18-7c50-7ed9-b8e7-383b11f077c2}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
index 33860af..0b4498f 100644
--- a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
@@ -156,13 +156,13 @@
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\test_credentials_provider.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.pb.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\duplicate\echo_duplicate.pb.cc">
     </ClCompile>
-    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.pb.h">
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\duplicate\echo_duplicate.pb.h">
     </ClInclude>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.grpc.pb.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\duplicate\echo_duplicate.grpc.pb.cc">
     </ClCompile>
-    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.grpc.pb.h">
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\duplicate\echo_duplicate.grpc.pb.h">
     </ClInclude>
     <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo.pb.cc">
     </ClCompile>
@@ -172,13 +172,13 @@
     </ClCompile>
     <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo.grpc.pb.h">
     </ClInclude>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\duplicate\echo_duplicate.pb.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.pb.cc">
     </ClCompile>
-    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\duplicate\echo_duplicate.pb.h">
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.pb.h">
     </ClInclude>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\duplicate\echo_duplicate.grpc.pb.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.grpc.pb.cc">
     </ClCompile>
-    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\duplicate\echo_duplicate.grpc.pb.h">
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.grpc.pb.h">
     </ClInclude>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\end2end\test_service_impl.cc">
     </ClCompile>
diff --git a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
index b35ba1f..3a16c65 100644
--- a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
@@ -1,14 +1,14 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.proto">
-      <Filter>src\proto\grpc\testing</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\duplicate\echo_duplicate.proto">
+      <Filter>src\proto\grpc\testing\duplicate</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo.proto">
       <Filter>src\proto\grpc\testing</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\duplicate\echo_duplicate.proto">
-      <Filter>src\proto\grpc\testing\duplicate</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.proto">
+      <Filter>src\proto\grpc\testing</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\end2end\test_service_impl.cc">
       <Filter>test\cpp\end2end</Filter>
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
index 2dcadba..7455e88 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -268,6 +268,37 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\grpc++.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\call.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\client_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\core_codegen_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\grpc_library.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\method_handler_impl.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\proto_utils.h" />
@@ -302,46 +333,15 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\stub_options.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\sync_stream.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\time.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\common\core_codegen.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\common\create_auth_context.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\dynamic_thread_pool.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\thread_pool_interface.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\insecure_create_auth_context.cc">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\channel.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\client_context.cc">
@@ -356,15 +356,17 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\insecure_credentials.cc">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\call.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_arguments.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\completion_queue.cc">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\core_codegen.cc">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\proto\proto_utils.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\insecure_create_auth_context.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\async_generic_service.cc">
     </ClCompile>
@@ -392,8 +394,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\grpc_library.cc">
-    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index 3572c65..dda90b1 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -1,9 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\insecure_create_auth_context.cc">
-      <Filter>src\cpp\common</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\channel.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
@@ -25,8 +22,8 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\insecure_credentials.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\call.cc">
-      <Filter>src\cpp\common</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.cc">
+      <Filter>src\cpp\codegen</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_arguments.cc">
       <Filter>src\cpp\common</Filter>
@@ -34,11 +31,14 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\completion_queue.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\core_codegen.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\proto\proto_utils.cc">
-      <Filter>src\cpp\proto</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\insecure_create_auth_context.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\rpc_method.cc">
+      <Filter>src\cpp\common</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\server\async_generic_service.cc">
       <Filter>src\cpp\server</Filter>
@@ -79,9 +79,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
       <Filter>src\cpp\util</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\grpc_library.cc">
-      <Filter>src\cpp\codegen</Filter>
-    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\alarm.h">
@@ -114,6 +111,99 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\client_unary_call.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\core_codegen_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h">
+      <Filter>include\grpc++\impl\codegen\security</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\grpc_library.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
@@ -216,101 +306,14 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\time.h">
       <Filter>include\grpc++\support</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h">
-      <Filter>include\grpc++\impl\codegen\security</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h">
       <Filter>src\cpp\client</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\common\core_codegen.h">
+      <Filter>src\cpp\common</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\common\create_auth_context.h">
       <Filter>src\cpp\common</Filter>
     </ClInclude>
@@ -362,9 +365,6 @@
     <Filter Include="src\cpp\common">
       <UniqueIdentifier>{ed8e4daa-825f-fbe5-2a45-846ad9165d3d}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\cpp\proto">
-      <UniqueIdentifier>{10b51a99-2e57-249e-ce23-3ab8c6b99ffb}</UniqueIdentifier>
-    </Filter>
     <Filter Include="src\cpp\server">
       <UniqueIdentifier>{8a54a279-d14b-4237-0df3-1ffe1ef5a7af}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index c2635c3..c20f8d7 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -267,6 +267,11 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
@@ -274,465 +279,473 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\grpc_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\channel_args.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\channel_stack.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\client_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\client_uchannel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\compress_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\connected_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\http_client_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\subchannel_call_holder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\client_config.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\connector.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\initial_connect_string.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policies\load_balancer_api.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policies\pick_first.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policies\round_robin.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policy.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policy_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policy_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolver_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolver_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolvers\dns_resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolvers\sockaddr_resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\subchannel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\subchannel_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\subchannel_index.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\uri_parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\compression\algorithm_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\compression\message_compress.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\debug\trace.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\httpcli\format_request.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\httpcli\httpcli.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\httpcli\parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\closure.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\endpoint.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\exec_ctx.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\executor.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\fd_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iocp_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iomgr.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iomgr_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iomgr_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_set.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\resolve_address.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_win32.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\socket_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_client.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\time_averaged_stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\udp_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_pipe.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\workqueue.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\workqueue_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\workqueue_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json_common.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json_writer.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\proto\grpc\lb\v0\load_balancer.pb.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\statistics\census_interface.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\statistics\census_rpc_stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\api_trace.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\call.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\call_test_only.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\completion_queue.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\event_string.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\init.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\surface_trace.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\byte_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\alpn.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\bin_encoder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_data.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_goaway.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_ping.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_rst_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_settings.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_window_update.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_encoder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_table.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\http2_errors.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\huffsyms.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\incoming_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\status_conversion.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\stream_map.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\timeout_encoding.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\varint.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2_transport.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\connectivity_state.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\metadata_batch.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\static_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\transport.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\transport_impl.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\auth_filters.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\b64.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\credentials.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\handshake.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\json_token.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\jwt_verifier.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\secure_endpoint.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\security_connector.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\security_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\fake_transport_security.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\ssl_transport_security.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\ssl_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security_interface.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\aggregation.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\mlog.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\rpc_metric_id.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\alpn.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_errors.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\status_conversion.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\aggregation.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\grpc_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\grpc_plugin.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\mlog.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\rpc_metric_id.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\subchannel_call_holder.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\client_config.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\connector.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\initial_connect_string.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\load_balancer_api.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\pick_first.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\round_robin.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_registry.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolver.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_registry.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\dns_resolver.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\sockaddr_resolver.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_index.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\uri_parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\fd_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\proto\grpc\lb\v0\load_balancer.pb.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\auth_filters.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\b64.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\handshake.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\json_token.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\jwt_verifier.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\secure_endpoint.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\security_connector.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\security_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\statistics\census_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\statistics\census_rpc_stats.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\surface_trace.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\fake_transport_security.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\ssl_transport_security.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\ssl_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security_interface.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_common.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\grpc_context.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\grpc_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\secure\secure_channel_create.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_args.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_stack.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\secure\server_secure_chttp2.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\client_channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\alpn.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\client_uchannel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\compress_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\connected_channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\http_client_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\http_server_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\subchannel_call_holder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\client_config.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\connector.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\default_initial_connect_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\initial_connect_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\load_balancer_api.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\pick_first.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\round_robin.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\parsing.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\status_conversion.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_lists.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolvers\dns_resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\writing.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolvers\sockaddr_resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\context.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_context.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel_index.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_plugin.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\uri_parser.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\initialize.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\compression_algorithm.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\mlog.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\message_compress.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\operation.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\debug\trace.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\placeholders.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\format_request.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\tracing.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\httpcli.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\parser.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\closure.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\exec_ctx.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\executor.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\fd_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\subchannel_call_holder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iocp_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\client_config.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\connector.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\default_initial_connect_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\initial_connect_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\load_balancer_api.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\pick_first.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\round_robin.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\resolve_address_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\resolve_address_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_utils.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_common_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\dns_resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_linux.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\sockaddr_resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_client_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_index.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_client_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\uri_parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression_algorithm.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_server_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_server_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\time_averaged_stats.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\timer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli_security_connector.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\udp_server.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_eventfd.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_nospecial.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_pipe.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\workqueue_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\workqueue_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\fd_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_multipoller_with_epoll.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_reader.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_multipoller_with_poll_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_writer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\proto\grpc\lb\v0\load_balancer.pb.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\alarm.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\api_trace.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer_reader.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call_details.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call_log_batch.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_connectivity.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_create.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_ping.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\completion_queue.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\event_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\init.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\lame_client.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\metadata_array.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server_chttp2.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server_create.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\validate_metadata.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\version.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\byte_stream.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\alpn.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\bin_encoder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_data.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_goaway.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_ping.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_rst_stream.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_settings.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_window_update.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_encoder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\proto\grpc\lb\v0\load_balancer.pb.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_parser.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\b64.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_table.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\client_auth_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\huffsyms.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\incoming_metadata.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials_metadata.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\parsing.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\status_conversion.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials_win32.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\stream_lists.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\google_default_credentials.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\stream_map.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\handshake.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\timeout_encoding.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\json_token.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\varint.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\jwt_verifier.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\writing.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\secure_endpoint.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2_transport.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\security_connector.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\connectivity_state.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\security_context.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\metadata.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\server_auth_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\metadata_batch.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\static_metadata.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\transport.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\transport_op_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\httpcli_security_connector.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\b64.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\client_auth_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\credentials.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\credentials_metadata.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_connectivity.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\credentials_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\credentials_win32.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\google_default_credentials.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\handshake.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\json_token.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\jwt_verifier.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\secure_endpoint.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init_secure.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\security_connector.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\security_context.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\server_auth_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\server_secure_chttp2.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\init_secure.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\secure_channel_create.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\fake_transport_security.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\ssl_transport_security.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\transport_security.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\context.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\initialize.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\mlog.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\operation.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\tsi\fake_transport_security.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\placeholders.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\tsi\ssl_transport_security.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\tracing.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_common.c">
     </ClCompile>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 6dd10d3..f03b207 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -1,476 +1,488 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\grpc_context.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
+      <Filter>src\core\ext\transport\chttp2\client\insecure</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\grpc_filter.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\secure\secure_channel_create.c">
+      <Filter>src\core\ext\transport\chttp2\client\secure</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_args.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2.c">
+      <Filter>src\core\ext\transport\chttp2\server\insecure</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_stack.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\secure\server_secure_chttp2.c">
+      <Filter>src\core\ext\transport\chttp2\server\secure</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\client_channel.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\alpn.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\client_uchannel.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\compress_filter.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\connected_channel.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\http_client_filter.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\http_server_filter.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\subchannel_call_holder.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\client_config.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\connector.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\default_initial_connect_string.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\initial_connect_string.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\load_balancer_api.c">
-      <Filter>src\core\client_config\lb_policies</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\pick_first.c">
-      <Filter>src\core\client_config\lb_policies</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\round_robin.c">
-      <Filter>src\core\client_config\lb_policies</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\parsing.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy_factory.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\status_conversion.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy_registry.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_lists.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver_factory.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver_registry.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolvers\dns_resolver.c">
-      <Filter>src\core\client_config\resolvers</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\writing.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolvers\sockaddr_resolver.c">
-      <Filter>src\core\client_config\resolvers</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\context.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_context.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel_factory.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_filter.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel_index.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_plugin.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\uri_parser.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\initialize.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\compression_algorithm.c">
-      <Filter>src\core\compression</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\mlog.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\message_compress.c">
-      <Filter>src\core\compression</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\operation.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\debug\trace.c">
-      <Filter>src\core\debug</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\placeholders.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\format_request.c">
-      <Filter>src\core\httpcli</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\tracing.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\httpcli.c">
-      <Filter>src\core\httpcli</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\parser.c">
-      <Filter>src\core\httpcli</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\closure.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\exec_ctx.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\executor.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\fd_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\subchannel_call_holder.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iocp_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\client_config.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\connector.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\default_initial_connect_string.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\initial_connect_string.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\load_balancer_api.c">
+      <Filter>src\core\lib\client_config\lb_policies</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\pick_first.c">
+      <Filter>src\core\lib\client_config\lb_policies</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\round_robin.c">
+      <Filter>src\core\lib\client_config\lb_policies</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_factory.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_registry.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\resolve_address_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\resolve_address_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_factory.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_utils.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_registry.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_common_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\dns_resolver.c">
+      <Filter>src\core\lib\client_config\resolvers</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_linux.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\sockaddr_resolver.c">
+      <Filter>src\core\lib\client_config\resolvers</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_factory.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_client_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_index.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_client_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\uri_parser.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression_algorithm.c">
+      <Filter>src\core\lib\compression</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_server_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
+      <Filter>src\core\lib\compression</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_server_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
+      <Filter>src\core\lib\debug</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
+      <Filter>src\core\lib\http</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\time_averaged_stats.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
+      <Filter>src\core\lib\http</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\timer.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli_security_connector.c">
+      <Filter>src\core\lib\http</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
+      <Filter>src\core\lib\http</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\udp_server.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_eventfd.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_nospecial.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_pipe.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\workqueue_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\workqueue_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\fd_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json.c">
-      <Filter>src\core\json</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_reader.c">
-      <Filter>src\core\json</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_multipoller_with_epoll.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_multipoller_with_poll_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_string.c">
-      <Filter>src\core\json</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_writer.c">
-      <Filter>src\core\json</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\proto\grpc\lb\v0\load_balancer.pb.c">
-      <Filter>src\core\proto\grpc\lb\v0</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\alarm.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\api_trace.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer_reader.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call_details.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call_log_batch.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_connectivity.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_create.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_ping.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\completion_queue.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\event_string.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\init.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\lame_client.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\metadata_array.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server_chttp2.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server_create.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\validate_metadata.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\version.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\byte_stream.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\alpn.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\bin_encoder.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_data.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_goaway.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_ping.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
+      <Filter>src\core\lib\json</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_rst_stream.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
+      <Filter>src\core\lib\json</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_settings.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
+      <Filter>src\core\lib\json</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_window_update.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
+      <Filter>src\core\lib\json</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_encoder.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\proto\grpc\lb\v0\load_balancer.pb.c">
+      <Filter>src\core\lib\proto\grpc\lb\v0</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_parser.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\b64.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_table.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\client_auth_filter.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\huffsyms.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\incoming_metadata.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials_metadata.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\parsing.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials_posix.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\status_conversion.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\credentials_win32.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\stream_lists.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\google_default_credentials.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\stream_map.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\handshake.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\timeout_encoding.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\json_token.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\varint.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\jwt_verifier.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\writing.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\secure_endpoint.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2_transport.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\security_connector.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\connectivity_state.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\security_context.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\metadata.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\security\server_auth_filter.c">
+      <Filter>src\core\lib\security</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\metadata_batch.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\static_metadata.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\transport.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\transport_op_string.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\httpcli_security_connector.c">
-      <Filter>src\core\httpcli</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\b64.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\client_auth_filter.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\credentials.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\credentials_metadata.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_connectivity.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\credentials_posix.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\credentials_win32.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\google_default_credentials.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\handshake.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\json_token.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\jwt_verifier.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\secure_endpoint.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init_secure.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\security_connector.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\security_context.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\server_auth_filter.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\security\server_secure_chttp2.c">
-      <Filter>src\core\security</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\init_secure.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\secure_channel_create.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\fake_transport_security.c">
-      <Filter>src\core\tsi</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\ssl_transport_security.c">
-      <Filter>src\core\tsi</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\transport_security.c">
-      <Filter>src\core\tsi</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\context.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\initialize.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\mlog.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\operation.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\tsi\fake_transport_security.c">
+      <Filter>src\core\lib\tsi</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\placeholders.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\tsi\ssl_transport_security.c">
+      <Filter>src\core\lib\tsi</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\tracing.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security.c">
+      <Filter>src\core\lib\tsi</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_common.c">
       <Filter>third_party\nanopb</Filter>
@@ -483,6 +495,21 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
@@ -504,421 +531,421 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\grpc_filter.h">
-      <Filter>src\core\census</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\alpn.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\channel_args.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\channel_stack.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\client_channel.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\client_uchannel.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\compress_filter.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\connected_channel.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\context.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\http_client_filter.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\http_server_filter.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\subchannel_call_holder.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\client_config.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\connector.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\initial_connect_string.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_errors.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policies\load_balancer_api.h">
-      <Filter>src\core\client_config\lb_policies</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policies\pick_first.h">
-      <Filter>src\core\client_config\lb_policies</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policies\round_robin.h">
-      <Filter>src\core\client_config\lb_policies</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\internal.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policy.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\status_conversion.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policy_factory.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policy_registry.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolver.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolver_factory.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\aggregation.h">
+      <Filter>src\core\lib\census</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolver_registry.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\grpc_filter.h">
+      <Filter>src\core\lib\census</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolvers\dns_resolver.h">
-      <Filter>src\core\client_config\resolvers</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\grpc_plugin.h">
+      <Filter>src\core\lib\census</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolvers\sockaddr_resolver.h">
-      <Filter>src\core\client_config\resolvers</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\mlog.h">
+      <Filter>src\core\lib\census</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\subchannel.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\rpc_metric_id.h">
+      <Filter>src\core\lib\census</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\subchannel_factory.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\subchannel_index.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\uri_parser.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\compression\algorithm_metadata.h">
-      <Filter>src\core\compression</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\compression\message_compress.h">
-      <Filter>src\core\compression</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\debug\trace.h">
-      <Filter>src\core\debug</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\httpcli\format_request.h">
-      <Filter>src\core\httpcli</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\httpcli\httpcli.h">
-      <Filter>src\core\httpcli</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\httpcli\parser.h">
-      <Filter>src\core\httpcli</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\closure.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\subchannel_call_holder.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\endpoint.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\client_config.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\connector.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\exec_ctx.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\initial_connect_string.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\executor.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\load_balancer_api.h">
+      <Filter>src\core\lib\client_config\lb_policies</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\fd_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\pick_first.h">
+      <Filter>src\core\lib\client_config\lb_policies</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iocp_windows.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\round_robin.h">
+      <Filter>src\core\lib\client_config\lb_policies</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iomgr.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iomgr_internal.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_factory.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iomgr_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_registry.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolver.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_factory.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_set.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_registry.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\dns_resolver.h">
+      <Filter>src\core\lib\client_config\resolvers</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_windows.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\sockaddr_resolver.h">
+      <Filter>src\core\lib\client_config\resolvers</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_windows.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\resolve_address.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_factory.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_index.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\uri_parser.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_utils.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
+      <Filter>src\core\lib\compression</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_win32.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h">
+      <Filter>src\core\lib\compression</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h">
+      <Filter>src\core\lib\debug</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\socket_windows.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h">
+      <Filter>src\core\lib\http</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_client.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h">
+      <Filter>src\core\lib\http</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h">
+      <Filter>src\core\lib\http</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_server.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_windows.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\time_averaged_stats.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\fd_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\udp_server.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_pipe.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\workqueue.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\workqueue_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\workqueue_windows.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json.h">
-      <Filter>src\core\json</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json_common.h">
-      <Filter>src\core\json</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json_reader.h">
-      <Filter>src\core\json</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json_writer.h">
-      <Filter>src\core\json</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\proto\grpc\lb\v0\load_balancer.pb.h">
-      <Filter>src\core\proto\grpc\lb\v0</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_win32.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\statistics\census_interface.h">
-      <Filter>src\core\statistics</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\statistics\census_rpc_stats.h">
-      <Filter>src\core\statistics</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\api_trace.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\call.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\call_test_only.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\channel.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\completion_queue.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\event_string.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\init.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\server.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\surface_trace.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\byte_stream.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\alpn.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\bin_encoder.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_data.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_goaway.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h">
+      <Filter>src\core\lib\json</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_ping.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h">
+      <Filter>src\core\lib\json</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_rst_stream.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h">
+      <Filter>src\core\lib\json</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_settings.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h">
+      <Filter>src\core\lib\json</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_window_update.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\proto\grpc\lb\v0\load_balancer.pb.h">
+      <Filter>src\core\lib\proto\grpc\lb\v0</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_encoder.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\auth_filters.h">
+      <Filter>src\core\lib\security</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_parser.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\b64.h">
+      <Filter>src\core\lib\security</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_table.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\credentials.h">
+      <Filter>src\core\lib\security</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\http2_errors.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\handshake.h">
+      <Filter>src\core\lib\security</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\huffsyms.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\json_token.h">
+      <Filter>src\core\lib\security</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\incoming_metadata.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\jwt_verifier.h">
+      <Filter>src\core\lib\security</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\internal.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\secure_endpoint.h">
+      <Filter>src\core\lib\security</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\status_conversion.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\security_connector.h">
+      <Filter>src\core\lib\security</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\stream_map.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\security_context.h">
+      <Filter>src\core\lib\security</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\timeout_encoding.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\statistics\census_interface.h">
+      <Filter>src\core\lib\statistics</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\varint.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\statistics\census_rpc_stats.h">
+      <Filter>src\core\lib\statistics</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2_transport.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\connectivity_state.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\metadata.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\metadata_batch.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\static_metadata.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\transport.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\transport_impl.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\auth_filters.h">
-      <Filter>src\core\security</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\b64.h">
-      <Filter>src\core\security</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\credentials.h">
-      <Filter>src\core\security</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\handshake.h">
-      <Filter>src\core\security</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\json_token.h">
-      <Filter>src\core\security</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\surface_trace.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\jwt_verifier.h">
-      <Filter>src\core\security</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\secure_endpoint.h">
-      <Filter>src\core\security</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\security_connector.h">
-      <Filter>src\core\security</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\security\security_context.h">
-      <Filter>src\core\security</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\fake_transport_security.h">
-      <Filter>src\core\tsi</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\ssl_transport_security.h">
-      <Filter>src\core\tsi</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\ssl_types.h">
-      <Filter>src\core\tsi</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security.h">
-      <Filter>src\core\tsi</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\fake_transport_security.h">
+      <Filter>src\core\lib\tsi</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security_interface.h">
-      <Filter>src\core\tsi</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\ssl_transport_security.h">
+      <Filter>src\core\lib\tsi</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\aggregation.h">
-      <Filter>src\core\census</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\ssl_types.h">
+      <Filter>src\core\lib\tsi</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\mlog.h">
-      <Filter>src\core\census</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security.h">
+      <Filter>src\core\lib\tsi</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\rpc_metric_id.h">
-      <Filter>src\core\census</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security_interface.h">
+      <Filter>src\core\lib\tsi</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h">
       <Filter>third_party\nanopb</Filter>
@@ -953,65 +980,95 @@
     <Filter Include="src\core">
       <UniqueIdentifier>{ea745680-21ea-9c5e-679b-64dc40562d08}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\census">
-      <UniqueIdentifier>{fb3aefc2-8205-b0bf-525f-ab5e339f7f76}</UniqueIdentifier>
+    <Filter Include="src\core\ext">
+      <UniqueIdentifier>{3f32a58f-394f-5f13-06aa-6cc52cc2daaf}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\channel">
-      <UniqueIdentifier>{d897b6c3-c555-234e-a589-b4f008063615}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport">
+      <UniqueIdentifier>{e3abfd0a-064e-0f2f-c8e8-7c5a7e98142a}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\client_config">
-      <UniqueIdentifier>{e71e6928-b1e3-0616-0961-1505370458ab}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2">
+      <UniqueIdentifier>{ac42667b-bbba-3571-20bc-7a4240ef26ca}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\client_config\lb_policies">
-      <UniqueIdentifier>{a3eca4d5-f760-61a6-7251-556b828c8b44}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2\client">
+      <UniqueIdentifier>{dbffebe0-eebb-577d-1860-ef6837f4cf50}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\client_config\resolvers">
-      <UniqueIdentifier>{6d97b8d9-2c15-927a-892a-709d073c02ab}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2\client\insecure">
+      <UniqueIdentifier>{4e699b02-fae4-dabd-afd2-2e41b05bef0e}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\compression">
-      <UniqueIdentifier>{263cb913-dfe6-42a4-096b-cac231f76305}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2\client\secure">
+      <UniqueIdentifier>{e98ed28e-8dc5-3bb4-22a2-8893831a0ab8}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\debug">
-      <UniqueIdentifier>{1da7ef8a-a06d-5499-b3de-19fee4a4214d}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2\server">
+      <UniqueIdentifier>{1d36fe16-b004-6bee-c661-328234bbb469}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\httpcli">
-      <UniqueIdentifier>{a9bc00ad-835f-c625-c6d9-6a1324f98b9f}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2\server\insecure">
+      <UniqueIdentifier>{e8539863-6029-cca4-44a9-5481cacf8144}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\iomgr">
-      <UniqueIdentifier>{1baf3894-af37-e647-bdbc-95dc17ed0073}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2\server\secure">
+      <UniqueIdentifier>{0afa539f-8c83-d4b9-cdea-550091f09638}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\json">
-      <UniqueIdentifier>{e665cc0e-b994-d7c5-cc18-2007392019f0}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2\transport">
+      <UniqueIdentifier>{6f34254e-e69f-c9b4-156d-5024bade5408}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\proto">
-      <UniqueIdentifier>{1ff04466-0905-8a5d-d6f4-7ff2df4c13b5}</UniqueIdentifier>
+    <Filter Include="src\core\lib">
+      <UniqueIdentifier>{5b2ded3f-84a5-f6b4-2060-286c7d1dc945}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\proto\grpc">
-      <UniqueIdentifier>{7c7ad0b3-bf85-5bd3-e0c8-4f5468a8e2e6}</UniqueIdentifier>
+    <Filter Include="src\core\lib\census">
+      <UniqueIdentifier>{f4108884-98c3-ac2e-c669-83cd41343975}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\proto\grpc\lb">
-      <UniqueIdentifier>{3d533dad-8100-e8a3-b7c3-1fc13a4d60da}</UniqueIdentifier>
+    <Filter Include="src\core\lib\channel">
+      <UniqueIdentifier>{1931b044-90f3-cd68-b5f8-23be77ca8efc}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\proto\grpc\lb\v0">
-      <UniqueIdentifier>{0ffcf868-7617-5fed-b6ce-2162d9d09148}</UniqueIdentifier>
+    <Filter Include="src\core\lib\client_config">
+      <UniqueIdentifier>{2f3260de-be57-d18d-6882-61d115baa159}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\security">
-      <UniqueIdentifier>{1d850ac6-e639-4eab-5338-4ba40272fcc9}</UniqueIdentifier>
+    <Filter Include="src\core\lib\client_config\lb_policies">
+      <UniqueIdentifier>{118d2bb5-086f-54f3-11de-26d7d7f73f9d}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\statistics">
-      <UniqueIdentifier>{0ef49896-2313-4a3f-1ce2-716fa0e5c6ca}</UniqueIdentifier>
+    <Filter Include="src\core\lib\client_config\resolvers">
+      <UniqueIdentifier>{b9d8db6c-2c68-1c90-fe5e-37da90f47ae6}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\surface">
-      <UniqueIdentifier>{aeb18e82-5d25-0aad-8b02-a0a3470073ce}</UniqueIdentifier>
+    <Filter Include="src\core\lib\compression">
+      <UniqueIdentifier>{dadf7fe9-3f15-d431-e4f6-f987b090536c}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\transport">
-      <UniqueIdentifier>{168fa1b1-1c18-eb55-9a4d-746bc58df2c1}</UniqueIdentifier>
+    <Filter Include="src\core\lib\debug">
+      <UniqueIdentifier>{19122742-9b92-5b67-9fb9-e552ac62ca5d}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\transport\chttp2">
-      <UniqueIdentifier>{b8b623c3-a168-a2b1-0d5f-b70a1f1cd8d2}</UniqueIdentifier>
+    <Filter Include="src\core\lib\http">
+      <UniqueIdentifier>{dab8f03a-73de-8cfa-88fb-6e04402efb54}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\tsi">
-      <UniqueIdentifier>{0b0f9ab1-efa4-7f03-e446-6fb9b5227e84}</UniqueIdentifier>
+    <Filter Include="src\core\lib\iomgr">
+      <UniqueIdentifier>{5468ba38-b8a3-85b1-216f-48a2364e18df}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\json">
+      <UniqueIdentifier>{cb2b0073-f2a7-5c63-d182-8874b24bdf36}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\proto">
+      <UniqueIdentifier>{b4b19f9a-1575-8a21-0bca-537746f858b7}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\proto\grpc">
+      <UniqueIdentifier>{cbc8ce67-4a97-d533-8dc3-f949c63e2771}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\proto\grpc\lb">
+      <UniqueIdentifier>{933530ae-447b-ea8d-3531-98f0556960b0}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\proto\grpc\lb\v0">
+      <UniqueIdentifier>{c33f944f-37d4-42fd-abc3-61f0d4400462}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\security">
+      <UniqueIdentifier>{c4661d64-349f-01c1-1ba8-0602f9047595}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\statistics">
+      <UniqueIdentifier>{4dc3c48b-e931-ed47-ffa2-b4ea3a7956ec}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\surface">
+      <UniqueIdentifier>{a21971fb-304f-da08-b1b2-7bd8df8ac373}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\transport">
+      <UniqueIdentifier>{e9d0d3fc-c100-f3e6-89b8-649f241155bf}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\tsi">
+      <UniqueIdentifier>{95ad2811-c8d0-7a42-2a73-baf03fcbf699}</UniqueIdentifier>
     </Filter>
     <Filter Include="third_party">
       <UniqueIdentifier>{aaab30a4-2a15-732e-c141-3fbc0f0f5a7a}</UniqueIdentifier>
diff --git a/vsprojects/vcxproj/grpc_codegen_lib/grpc_codegen_lib.vcxproj b/vsprojects/vcxproj/grpc_codegen_lib/grpc_codegen_lib.vcxproj
new file mode 100644
index 0000000..7d7a609
--- /dev/null
+++ b/vsprojects/vcxproj/grpc_codegen_lib/grpc_codegen_lib.vcxproj
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{A828FD72-44CE-4EA5-8966-6E4624458D58}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>grpc_codegen_lib</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>grpc_codegen_lib</TargetName>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\vsprojects\dummy.c">
+    </ClCompile>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/grpc_codegen_lib/grpc_codegen_lib.vcxproj.filters b/vsprojects/vcxproj/grpc_codegen_lib/grpc_codegen_lib.vcxproj.filters
new file mode 100644
index 0000000..891dff0
--- /dev/null
+++ b/vsprojects/vcxproj/grpc_codegen_lib/grpc_codegen_lib.vcxproj.filters
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="include">
+      <UniqueIdentifier>{1fe03afe-0c52-a706-2c50-4ea691805d81}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc">
+      <UniqueIdentifier>{386f8a29-15ac-1f26-30ee-d9a605a802be}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl">
+      <UniqueIdentifier>{9828c5d3-4dc2-f116-97bf-015089243c94}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl\codegen">
+      <UniqueIdentifier>{0e88ed03-ed1e-49c0-15d7-69934b433494}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj
index a76c883..058ae4f 100644
--- a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj
+++ b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj
@@ -148,42 +148,6 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
@@ -227,8 +191,11 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\compiler\ruby_generator.cc">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\grpc_library.cc">
-    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_codegen_lib\grpc++_codegen_lib.vcxproj">
+      <Project>{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}</Project>
+    </ProjectReference>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
diff --git a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters
index de33d98..b1a63eb 100644
--- a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters
@@ -16,119 +16,8 @@
     <ClCompile Include="$(SolutionDir)\..\src\compiler\ruby_generator.cc">
       <Filter>src\compiler</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\grpc_library.cc">
-      <Filter>src\cpp\codegen</Filter>
-    </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h">
-      <Filter>include\grpc++\impl\codegen\security</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
-      <Filter>include\grpc++\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
@@ -230,15 +119,6 @@
     <Filter Include="include\grpc++">
       <UniqueIdentifier>{893c09ee-e315-e763-9d9d-37522ba2f51c}</UniqueIdentifier>
     </Filter>
-    <Filter Include="include\grpc++\impl">
-      <UniqueIdentifier>{3e8c71a4-8a06-a577-2799-2224a1ad1f1b}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc++\impl\codegen">
-      <UniqueIdentifier>{ec2a6e26-915b-ba1b-4f59-f361dc01105c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="include\grpc++\impl\codegen\security">
-      <UniqueIdentifier>{c1593bf9-5ef8-cb28-e46b-543153918a3f}</UniqueIdentifier>
-    </Filter>
     <Filter Include="include\grpc++\support">
       <UniqueIdentifier>{1c34d005-1ffb-8a31-881a-c6bb431cda69}</UniqueIdentifier>
     </Filter>
@@ -254,12 +134,6 @@
     <Filter Include="src\compiler">
       <UniqueIdentifier>{0e6b1e6c-7299-59ce-d757-619bcddd5441}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\cpp">
-      <UniqueIdentifier>{29d80aab-9e9d-0417-6dfa-59dec47c9883}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\cpp\codegen">
-      <UniqueIdentifier>{c0d4a389-f341-8385-4534-fe9d8fb09952}</UniqueIdentifier>
-    </Filter>
   </ItemGroup>
 </Project>
 
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index 5735327..668f8a5 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -147,37 +147,40 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\data\ssl_test_data.h" />
-    <ClInclude Include="$(SolutionDir)\..\test\core\security\oauth2_utils.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\data\ssl_test_data.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\core\security\oauth2_utils.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\grpc_profiler.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\parse_hexstring.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\port.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\core\util\port_server_client.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\slice_splitter.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\server1_cert.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\server1_key.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\test_root_cert.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\security\oauth2_utils.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\security\oauth2_utils.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\grpc_profiler.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\parse_hexstring.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\port_posix.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_server_client.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\port_windows.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\slice_splitter.c">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index 47a689a..7f2876d 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.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="$(SolutionDir)\..\test\core\end2end\cq_verifier.c">
+      <Filter>test\core\end2end</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\server1_cert.c">
       <Filter>test\core\end2end\data</Filter>
     </ClCompile>
@@ -10,18 +13,15 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\test_root_cert.c">
       <Filter>test\core\end2end\data</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\security\oauth2_utils.c">
-      <Filter>test\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.c">
-      <Filter>test\core\end2end</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.c">
       <Filter>test\core\end2end\fixtures</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.c">
       <Filter>test\core\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\security\oauth2_utils.c">
+      <Filter>test\core\security</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\grpc_profiler.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
@@ -31,6 +31,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\util\port_posix.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_server_client.c">
+      <Filter>test\core\util</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\port_windows.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
@@ -39,21 +42,21 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\data\ssl_test_data.h">
-      <Filter>test\core\end2end\data</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\test\core\security\oauth2_utils.h">
-      <Filter>test\core\security</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.h">
       <Filter>test\core\end2end</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\data\ssl_test_data.h">
+      <Filter>test\core\end2end\data</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.h">
       <Filter>test\core\end2end\fixtures</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.h">
       <Filter>test\core\iomgr</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\core\security\oauth2_utils.h">
+      <Filter>test\core\security</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\core\util\grpc_profiler.h">
       <Filter>test\core\util</Filter>
     </ClInclude>
@@ -63,6 +66,9 @@
     <ClInclude Include="$(SolutionDir)\..\test\core\util\port.h">
       <Filter>test\core\util</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\core\util\port_server_client.h">
+      <Filter>test\core\util</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\core\util\slice_splitter.h">
       <Filter>test\core\util</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
index 6ff6ec9..2a3c50e 100644
--- a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
@@ -153,6 +153,7 @@
     <ClInclude Include="$(SolutionDir)\..\test\core\util\grpc_profiler.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\parse_hexstring.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\port.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\core\util\port_server_client.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\slice_splitter.h" />
   </ItemGroup>
   <ItemGroup>
@@ -168,6 +169,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\port_posix.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_server_client.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\port_windows.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\slice_splitter.c">
diff --git a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters
index 3b682ce..cdb19e1 100644
--- a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters
@@ -19,6 +19,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\util\port_posix.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\util\port_server_client.c">
+      <Filter>test\core\util</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\port_windows.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
@@ -45,6 +48,9 @@
     <ClInclude Include="$(SolutionDir)\..\test\core\util\port.h">
       <Filter>test\core\util</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\core\util\port_server_client.h">
+      <Filter>test\core\util</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\core\util\slice_splitter.h">
       <Filter>test\core\util</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index f0d869b..e89cc8a 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -260,415 +260,428 @@
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\grpc_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\channel_args.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\channel_stack.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\client_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\client_uchannel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\compress_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\connected_channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\context.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\http_client_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\http_server_filter.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\subchannel_call_holder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\client_config.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\connector.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\initial_connect_string.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policies\load_balancer_api.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policies\pick_first.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policies\round_robin.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policy.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policy_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policy_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolver_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolver_registry.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolvers\dns_resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolvers\sockaddr_resolver.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\subchannel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\subchannel_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\subchannel_index.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\uri_parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\compression\algorithm_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\compression\message_compress.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\debug\trace.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\httpcli\format_request.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\httpcli\httpcli.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\httpcli\parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\closure.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\endpoint.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\exec_ctx.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\executor.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\fd_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iocp_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iomgr.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iomgr_internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iomgr_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_set.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\resolve_address.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_utils.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_win32.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\socket_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_client.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\time_averaged_stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\udp_server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_pipe.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\workqueue.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\workqueue_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\workqueue_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json_common.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json_writer.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\proto\grpc\lb\v0\load_balancer.pb.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\statistics\census_interface.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\statistics\census_rpc_stats.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\api_trace.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\call.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\call_test_only.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\channel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\completion_queue.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\event_string.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\init.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\server.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\surface_trace.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\byte_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\alpn.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\bin_encoder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_data.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_goaway.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_ping.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_rst_stream.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_settings.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_window_update.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_encoder.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_parser.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_table.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\http2_errors.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\huffsyms.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\incoming_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\internal.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\status_conversion.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\stream_map.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\timeout_encoding.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\varint.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2_transport.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\connectivity_state.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\metadata_batch.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\static_metadata.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\transport.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\transport_impl.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\aggregation.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\mlog.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\rpc_metric_id.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\alpn.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_errors.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\status_conversion.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\aggregation.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\grpc_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\grpc_plugin.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\mlog.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\rpc_metric_id.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\subchannel_call_holder.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\client_config.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\connector.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\initial_connect_string.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\load_balancer_api.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\pick_first.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\round_robin.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_registry.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolver.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_registry.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\dns_resolver.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\sockaddr_resolver.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_index.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\uri_parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\fd_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\proto\grpc\lb\v0\load_balancer.pb.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\statistics\census_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\statistics\census_rpc_stats.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\surface_trace.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_common.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\init_unsecure.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\grpc_context.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\grpc_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\alpn.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_args.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_stack.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\client_channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\client_uchannel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\compress_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\connected_channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\http_client_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\http_server_filter.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\subchannel_call_holder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\client_config.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\connector.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\default_initial_connect_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\initial_connect_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\load_balancer_api.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\parsing.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\pick_first.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\status_conversion.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\round_robin.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_lists.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\writing.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\context.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver_registry.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_context.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolvers\dns_resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolvers\sockaddr_resolver.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_plugin.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\initialize.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel_factory.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\mlog.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel_index.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\operation.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\uri_parser.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\placeholders.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\compression_algorithm.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\tracing.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\message_compress.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\debug\trace.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\format_request.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\httpcli.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\parser.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\closure.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\subchannel_call_holder.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\exec_ctx.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\client_config.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\executor.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\connector.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\fd_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\default_initial_connect_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iocp_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\initial_connect_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\load_balancer_api.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\pick_first.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\round_robin.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\resolve_address_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\dns_resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\resolve_address_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\sockaddr_resolver.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_utils.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_common_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_linux.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_index.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\uri_parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression_algorithm.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_client_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_client_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_server_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_server_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\time_averaged_stats.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\timer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\fd_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\udp_server.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_eventfd.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_nospecial.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_pipe.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_multipoller_with_epoll.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_multipoller_with_poll_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\workqueue_posix.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\workqueue_windows.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_reader.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_writer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\proto\grpc\lb\v0\load_balancer.pb.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\alarm.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\api_trace.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer_reader.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call_details.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call_log_batch.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_connectivity.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_create.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_ping.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\completion_queue.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\event_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\init.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\lame_client.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\metadata_array.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server_chttp2.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server_create.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\validate_metadata.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\version.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\byte_stream.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\alpn.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\bin_encoder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_data.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_goaway.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_ping.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\proto\grpc\lb\v0\load_balancer.pb.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_rst_stream.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_settings.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_window_update.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_encoder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_parser.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_table.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\huffsyms.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\incoming_metadata.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\parsing.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_connectivity.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\status_conversion.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\stream_lists.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\stream_map.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\timeout_encoding.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\varint.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\writing.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2_transport.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init_unsecure.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\connectivity_state.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\metadata.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\metadata_batch.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\static_metadata.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\transport.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\transport_op_string.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\context.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\initialize.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\mlog.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\operation.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\placeholders.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\tracing.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_common.c">
     </ClCompile>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 1f24021..c9f1ad6 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -1,416 +1,428 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\init_unsecure.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
+      <Filter>src\core\ext\transport\chttp2\client\insecure</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\grpc_context.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\insecure\server_chttp2.c">
+      <Filter>src\core\ext\transport\chttp2\server\insecure</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\grpc_filter.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\alpn.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_args.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\channel_stack.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\client_channel.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\client_uchannel.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\compress_filter.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\connected_channel.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\http_client_filter.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\http_server_filter.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\channel\subchannel_call_holder.c">
-      <Filter>src\core\channel</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\client_config.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\connector.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\default_initial_connect_string.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\initial_connect_string.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\load_balancer_api.c">
-      <Filter>src\core\client_config\lb_policies</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\parsing.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\pick_first.c">
-      <Filter>src\core\client_config\lb_policies</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\status_conversion.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policies\round_robin.c">
-      <Filter>src\core\client_config\lb_policies</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_lists.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy_factory.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\lb_policy_registry.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\writing.c">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver_factory.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\context.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolver_registry.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_context.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolvers\dns_resolver.c">
-      <Filter>src\core\client_config\resolvers</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_filter.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\resolvers\sockaddr_resolver.c">
-      <Filter>src\core\client_config\resolvers</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\grpc_plugin.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\initialize.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel_factory.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\mlog.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\subchannel_index.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\operation.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\client_config\uri_parser.c">
-      <Filter>src\core\client_config</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\placeholders.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\compression_algorithm.c">
-      <Filter>src\core\compression</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\census\tracing.c">
+      <Filter>src\core\lib\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\compression\message_compress.c">
-      <Filter>src\core\compression</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\debug\trace.c">
-      <Filter>src\core\debug</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\format_request.c">
-      <Filter>src\core\httpcli</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\httpcli.c">
-      <Filter>src\core\httpcli</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\httpcli\parser.c">
-      <Filter>src\core\httpcli</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\closure.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\subchannel_call_holder.c">
+      <Filter>src\core\lib\channel</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\exec_ctx.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\client_config.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\executor.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\connector.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\fd_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\default_initial_connect_string.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iocp_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\initial_connect_string.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\load_balancer_api.c">
+      <Filter>src\core\lib\client_config\lb_policies</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\pick_first.c">
+      <Filter>src\core\lib\client_config\lb_policies</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\iomgr_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\round_robin.c">
+      <Filter>src\core\lib\client_config\lb_policies</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_multipoller_with_epoll.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_multipoller_with_poll_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_factory.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_registry.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_factory.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\pollset_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_registry.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\resolve_address_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\dns_resolver.c">
+      <Filter>src\core\lib\client_config\resolvers</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\resolve_address_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\sockaddr_resolver.c">
+      <Filter>src\core\lib\client_config\resolvers</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_utils.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_common_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_factory.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_linux.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_index.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\client_config\uri_parser.c">
+      <Filter>src\core\lib\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\socket_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression_algorithm.c">
+      <Filter>src\core\lib\compression</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_client_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
+      <Filter>src\core\lib\compression</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_client_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
+      <Filter>src\core\lib\debug</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
+      <Filter>src\core\lib\http</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_server_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
+      <Filter>src\core\lib\http</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_server_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
+      <Filter>src\core\lib\http</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\tcp_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\time_averaged_stats.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\timer.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\fd_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\udp_server.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_eventfd.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_nospecial.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_pipe.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_multipoller_with_epoll.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_multipoller_with_poll_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\workqueue_posix.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\iomgr\workqueue_windows.c">
-      <Filter>src\core\iomgr</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json.c">
-      <Filter>src\core\json</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_reader.c">
-      <Filter>src\core\json</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_string.c">
-      <Filter>src\core\json</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\json\json_writer.c">
-      <Filter>src\core\json</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\proto\grpc\lb\v0\load_balancer.pb.c">
-      <Filter>src\core\proto\grpc\lb\v0</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\alarm.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\api_trace.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer_reader.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call_details.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\call_log_batch.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_connectivity.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_create.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\channel_ping.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\completion_queue.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\event_string.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\init.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\lame_client.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\metadata_array.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server_chttp2.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\server_create.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\validate_metadata.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\surface\version.c">
-      <Filter>src\core\surface</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\byte_stream.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\alpn.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
+      <Filter>src\core\lib\json</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\bin_encoder.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
+      <Filter>src\core\lib\json</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_data.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
+      <Filter>src\core\lib\json</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_goaway.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
+      <Filter>src\core\lib\json</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_ping.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\proto\grpc\lb\v0\load_balancer.pb.c">
+      <Filter>src\core\lib\proto\grpc\lb\v0</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_rst_stream.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_settings.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_window_update.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_encoder.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_parser.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_table.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\huffsyms.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\incoming_metadata.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\parsing.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_connectivity.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\status_conversion.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\stream_lists.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\stream_map.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\timeout_encoding.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\varint.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2\writing.c">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\chttp2_transport.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init_unsecure.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\connectivity_state.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\metadata.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\metadata_batch.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\static_metadata.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\transport.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
+      <Filter>src\core\lib\surface</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\transport\transport_op_string.c">
-      <Filter>src\core\transport</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\context.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\initialize.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\mlog.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\operation.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\placeholders.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\tracing.c">
-      <Filter>src\core\census</Filter>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
+      <Filter>src\core\lib\transport</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\third_party\nanopb\pb_common.c">
       <Filter>third_party\nanopb</Filter>
@@ -429,15 +441,15 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
@@ -456,364 +468,379 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h">
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\grpc_filter.h">
-      <Filter>src\core\census</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\alpn.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\channel_args.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_encoder.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\channel_stack.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\chttp2_transport.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\client_channel.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\client_uchannel.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_data.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\compress_filter.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_goaway.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\connected_channel.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_ping.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\context.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_rst_stream.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\http_client_filter.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_settings.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\http_server_filter.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\frame_window_update.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\channel\subchannel_call_holder.h">
-      <Filter>src\core\channel</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_encoder.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\client_config.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_parser.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\connector.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\hpack_table.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\initial_connect_string.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\http2_errors.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policies\load_balancer_api.h">
-      <Filter>src\core\client_config\lb_policies</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\huffsyms.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policies\pick_first.h">
-      <Filter>src\core\client_config\lb_policies</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\incoming_metadata.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policies\round_robin.h">
-      <Filter>src\core\client_config\lb_policies</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\internal.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policy.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\status_conversion.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policy_factory.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\lb_policy_registry.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolver.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h">
+      <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolver_factory.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\aggregation.h">
+      <Filter>src\core\lib\census</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolver_registry.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\grpc_filter.h">
+      <Filter>src\core\lib\census</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolvers\dns_resolver.h">
-      <Filter>src\core\client_config\resolvers</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\grpc_plugin.h">
+      <Filter>src\core\lib\census</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\resolvers\sockaddr_resolver.h">
-      <Filter>src\core\client_config\resolvers</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\mlog.h">
+      <Filter>src\core\lib\census</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\subchannel.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\census\rpc_metric_id.h">
+      <Filter>src\core\lib\census</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\subchannel_factory.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\subchannel_index.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\client_config\uri_parser.h">
-      <Filter>src\core\client_config</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\compression\algorithm_metadata.h">
-      <Filter>src\core\compression</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\client_channel.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\compression\message_compress.h">
-      <Filter>src\core\compression</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\debug\trace.h">
-      <Filter>src\core\debug</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\httpcli\format_request.h">
-      <Filter>src\core\httpcli</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\httpcli\httpcli.h">
-      <Filter>src\core\httpcli</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\httpcli\parser.h">
-      <Filter>src\core\httpcli</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\closure.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\subchannel_call_holder.h">
+      <Filter>src\core\lib\channel</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\endpoint.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\client_config.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\endpoint_pair.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\connector.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\exec_ctx.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\initial_connect_string.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\executor.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\load_balancer_api.h">
+      <Filter>src\core\lib\client_config\lb_policies</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\fd_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\pick_first.h">
+      <Filter>src\core\lib\client_config\lb_policies</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iocp_windows.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policies\round_robin.h">
+      <Filter>src\core\lib\client_config\lb_policies</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iomgr.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iomgr_internal.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_factory.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\iomgr_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\lb_policy_registry.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolver.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_factory.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_set.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolver_registry.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\dns_resolver.h">
+      <Filter>src\core\lib\client_config\resolvers</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_set_windows.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\resolvers\sockaddr_resolver.h">
+      <Filter>src\core\lib\client_config\resolvers</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\pollset_windows.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\resolve_address.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_factory.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\subchannel_index.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\client_config\uri_parser.h">
+      <Filter>src\core\lib\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_utils.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
+      <Filter>src\core\lib\compression</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\sockaddr_win32.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h">
+      <Filter>src\core\lib\compression</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\socket_utils_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h">
+      <Filter>src\core\lib\debug</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\socket_windows.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h">
+      <Filter>src\core\lib\http</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h">
+      <Filter>src\core\lib\http</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h">
+      <Filter>src\core\lib\http</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_client.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_server.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\fd_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\tcp_windows.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\time_averaged_stats.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\udp_server.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_pipe.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\workqueue.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\workqueue_posix.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\workqueue_windows.h">
-      <Filter>src\core\iomgr</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json.h">
-      <Filter>src\core\json</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json_common.h">
-      <Filter>src\core\json</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json_reader.h">
-      <Filter>src\core\json</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\json\json_writer.h">
-      <Filter>src\core\json</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\proto\grpc\lb\v0\load_balancer.pb.h">
-      <Filter>src\core\proto\grpc\lb\v0</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_win32.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\statistics\census_interface.h">
-      <Filter>src\core\statistics</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\statistics\census_rpc_stats.h">
-      <Filter>src\core\statistics</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\api_trace.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\call.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\call_test_only.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\channel.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\completion_queue.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\event_string.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\init.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\server.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\surface\surface_trace.h">
-      <Filter>src\core\surface</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\byte_stream.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\alpn.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\bin_encoder.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_data.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_goaway.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h">
+      <Filter>src\core\lib\json</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_ping.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h">
+      <Filter>src\core\lib\json</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_rst_stream.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h">
+      <Filter>src\core\lib\json</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_settings.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h">
+      <Filter>src\core\lib\json</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\frame_window_update.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\proto\grpc\lb\v0\load_balancer.pb.h">
+      <Filter>src\core\lib\proto\grpc\lb\v0</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_encoder.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\statistics\census_interface.h">
+      <Filter>src\core\lib\statistics</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_parser.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\statistics\census_rpc_stats.h">
+      <Filter>src\core\lib\statistics</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\hpack_table.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\http2_errors.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\huffsyms.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\incoming_metadata.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\internal.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\status_conversion.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\stream_map.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\timeout_encoding.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2\varint.h">
-      <Filter>src\core\transport\chttp2</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\chttp2_transport.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\connectivity_state.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\metadata.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\surface_trace.h">
+      <Filter>src\core\lib\surface</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\metadata_batch.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\static_metadata.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\transport.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\transport\transport_impl.h">
-      <Filter>src\core\transport</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\aggregation.h">
-      <Filter>src\core\census</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\mlog.h">
-      <Filter>src\core\census</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\rpc_metric_id.h">
-      <Filter>src\core\census</Filter>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h">
+      <Filter>src\core\lib\transport</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h">
       <Filter>third_party\nanopb</Filter>
@@ -848,59 +875,83 @@
     <Filter Include="src\core">
       <UniqueIdentifier>{88491077-386b-2039-d14c-0c40136b5f7a}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\census">
-      <UniqueIdentifier>{a7596ee2-afee-3a82-7e6e-bd8b8f904e04}</UniqueIdentifier>
+    <Filter Include="src\core\ext">
+      <UniqueIdentifier>{82f86e8c-00a4-f566-d235-670fc629798d}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\channel">
-      <UniqueIdentifier>{cc102c4b-66ff-cf4c-2288-d76327e1a183}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport">
+      <UniqueIdentifier>{967c89fe-c97c-27e2-aac0-9ba5854cb5fa}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\client_config">
-      <UniqueIdentifier>{02bd7340-02ee-4337-ffa5-0b6ecc7cf60c}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2">
+      <UniqueIdentifier>{702829f0-099e-2ab7-6b44-ed7cff3ec083}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\client_config\lb_policies">
-      <UniqueIdentifier>{308af086-46c7-fa66-9021-19b1c3d4a6bd}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2\client">
+      <UniqueIdentifier>{0d589e16-e470-4968-318c-796af5a33637}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\client_config\resolvers">
-      <UniqueIdentifier>{dd617c24-6f07-fdff-80d5-c8610d6f815e}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2\client\insecure">
+      <UniqueIdentifier>{34dfdc9b-ab97-47f0-c1e1-b2e7381c3de6}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\compression">
-      <UniqueIdentifier>{2e3aca1d-223d-10a1-b282-7f9fc68ee6f5}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2\server">
+      <UniqueIdentifier>{81fb55f4-9216-441b-8389-a7120bbcd45e}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\debug">
-      <UniqueIdentifier>{6d8d5774-7291-554d-fafa-583463cd3fd9}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2\server\insecure">
+      <UniqueIdentifier>{3f53dcb6-71d7-28ff-1794-26a08e4601fe}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\httpcli">
-      <UniqueIdentifier>{1ba3a245-47e7-89b5-b0c9-aca758bd0277}</UniqueIdentifier>
+    <Filter Include="src\core\ext\transport\chttp2\transport">
+      <UniqueIdentifier>{45b20f28-376c-9dea-1800-8a0193411946}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\iomgr">
-      <UniqueIdentifier>{a9df8b24-ecea-ff6d-8999-d8fa54cd70bf}</UniqueIdentifier>
+    <Filter Include="src\core\lib">
+      <UniqueIdentifier>{8bd5b461-bff8-6aa8-b5a6-85da2834eb8a}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\json">
-      <UniqueIdentifier>{443ffc61-1bea-2477-6e54-1ddf8c139264}</UniqueIdentifier>
+    <Filter Include="src\core\lib\census">
+      <UniqueIdentifier>{19582d5a-dab7-9dc1-c7e9-cc147fd52e5f}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\proto">
-      <UniqueIdentifier>{7f4bb22a-65ba-0f8f-6387-66b1f6677a80}</UniqueIdentifier>
+    <Filter Include="src\core\lib\channel">
+      <UniqueIdentifier>{fb964f3d-a59c-a7ba-fee5-6072dbb94a7b}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\proto\grpc">
-      <UniqueIdentifier>{9c2bd164-c317-8a13-564d-3b28b0fd79cf}</UniqueIdentifier>
+    <Filter Include="src\core\lib\client_config">
+      <UniqueIdentifier>{29ca2974-89e4-1a74-3e4d-0d63e2f77566}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\proto\grpc\lb">
-      <UniqueIdentifier>{2bad8e10-4fc5-d8b3-e026-4abbd0c25cda}</UniqueIdentifier>
+    <Filter Include="src\core\lib\client_config\lb_policies">
+      <UniqueIdentifier>{6c7e36d4-6117-e0cd-c886-b9eb3c994927}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\proto\grpc\lb\v0">
-      <UniqueIdentifier>{4475c8ed-e01b-8906-47d0-8a504189c0d5}</UniqueIdentifier>
+    <Filter Include="src\core\lib\client_config\resolvers">
+      <UniqueIdentifier>{2d959ef9-9703-dc92-a56f-9fe136dadfb9}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\statistics">
-      <UniqueIdentifier>{e084164c-a069-00e3-db35-4e0b1cd6f0b7}</UniqueIdentifier>
+    <Filter Include="src\core\lib\compression">
+      <UniqueIdentifier>{b88002e9-185e-4e64-49f5-2d8989ce87f6}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\surface">
-      <UniqueIdentifier>{6cd0127e-c24b-d43c-38f5-198db8d4322a}</UniqueIdentifier>
+    <Filter Include="src\core\lib\debug">
+      <UniqueIdentifier>{7f23789d-f18a-2a2d-60fe-a87dc656f539}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\transport">
-      <UniqueIdentifier>{6687ff98-e36e-c0b1-2756-1bc79edec406}</UniqueIdentifier>
+    <Filter Include="src\core\lib\http">
+      <UniqueIdentifier>{748c8078-2027-8641-f485-1d4c66466e79}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src\core\transport\chttp2">
-      <UniqueIdentifier>{5fcd6206-f774-9ae6-4b85-305d6a723843}</UniqueIdentifier>
+    <Filter Include="src\core\lib\iomgr">
+      <UniqueIdentifier>{bb1a1cf2-6824-08f0-a9bd-3fafcaf13042}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\json">
+      <UniqueIdentifier>{681cdaeb-c47f-8853-d985-bf13c2873947}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\proto">
+      <UniqueIdentifier>{4bfbd6c6-f6a8-c6b3-5186-b788f4e11e23}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\proto\grpc">
+      <UniqueIdentifier>{60f3ab7d-ea44-348f-671e-77fdebbd18bb}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\proto\grpc\lb">
+      <UniqueIdentifier>{bcd33510-32e7-c2fb-e11d-a3655f97bc84}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\proto\grpc\lb\v0">
+      <UniqueIdentifier>{bb9b8c80-9eff-5ab6-5b29-c2d54f0fc192}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\statistics">
+      <UniqueIdentifier>{d0ab6d54-ae25-fc49-3656-91d9db57366a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\surface">
+      <UniqueIdentifier>{506dc3b3-d884-2b59-0dfa-57ed6affa2d3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\transport">
+      <UniqueIdentifier>{6c3394d1-27e9-003e-19ed-8116d210f7cc}</UniqueIdentifier>
     </Filter>
     <Filter Include="third_party">
       <UniqueIdentifier>{025c051e-8eba-125b-67f9-173f95176eb2}</UniqueIdentifier>
diff --git a/vsprojects/vcxproj/qps/qps.vcxproj b/vsprojects/vcxproj/qps/qps.vcxproj
index a57b740..d458664 100644
--- a/vsprojects/vcxproj/qps/qps.vcxproj
+++ b/vsprojects/vcxproj/qps/qps.vcxproj
@@ -161,6 +161,14 @@
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\benchmark_config.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\control.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\control.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\control.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\control.grpc.pb.h">
+    </ClInclude>
     <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.pb.cc">
     </ClCompile>
     <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.pb.h">
@@ -177,21 +185,13 @@
     </ClCompile>
     <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\payloads.grpc.pb.h">
     </ClInclude>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.pb.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.pb.cc">
     </ClCompile>
-    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.pb.h">
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.pb.h">
     </ClInclude>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.grpc.pb.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.grpc.pb.cc">
     </ClCompile>
-    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.grpc.pb.h">
-    </ClInclude>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\control.pb.cc">
-    </ClCompile>
-    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\control.pb.h">
-    </ClInclude>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\control.grpc.pb.cc">
-    </ClCompile>
-    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\control.grpc.pb.h">
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.grpc.pb.h">
     </ClInclude>
     <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\services.pb.cc">
     </ClCompile>
@@ -201,13 +201,13 @@
     </ClCompile>
     <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\services.grpc.pb.h">
     </ClInclude>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.pb.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.pb.cc">
     </ClCompile>
-    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.pb.h">
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.pb.h">
     </ClInclude>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.grpc.pb.cc">
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.grpc.pb.cc">
     </ClCompile>
-    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.grpc.pb.h">
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.grpc.pb.h">
     </ClInclude>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\qps\client_async.cc">
     </ClCompile>
diff --git a/vsprojects/vcxproj/qps/qps.vcxproj.filters b/vsprojects/vcxproj/qps/qps.vcxproj.filters
index eeb9555..c3ea63d 100644
--- a/vsprojects/vcxproj/qps/qps.vcxproj.filters
+++ b/vsprojects/vcxproj/qps/qps.vcxproj.filters
@@ -1,22 +1,22 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\control.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.proto">
       <Filter>src\proto\grpc\testing</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\payloads.proto">
       <Filter>src\proto\grpc\testing</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.proto">
-      <Filter>src\proto\grpc\testing</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\control.proto">
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.proto">
       <Filter>src\proto\grpc\testing</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\services.proto">
       <Filter>src\proto\grpc\testing</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.proto">
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.proto">
       <Filter>src\proto\grpc\testing</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\qps\client_async.cc">
diff --git a/vsprojects/vcxproj/test/boringssl/boringssl_asn1_test/boringssl_asn1_test.vcxproj b/vsprojects/vcxproj/test/boringssl/boringssl_asn1_test/boringssl_asn1_test.vcxproj
new file mode 100644
index 0000000..9d5aa67
--- /dev/null
+++ b/vsprojects/vcxproj/test/boringssl/boringssl_asn1_test/boringssl_asn1_test.vcxproj
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{A18A6879-13EB-F421-E270-03C6DBD6A6B7}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\cpptest.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\protobuf.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>boringssl_asn1_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>boringssl_asn1_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>false</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>false</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>false</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>false</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\vsprojects\dummy.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/boringssl\boringssl_asn1_test_lib\boringssl_asn1_test_lib.vcxproj">
+      <Project>{37B78CF5-2090-3DC6-FF98-17381709846A}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\boringssl_test_util\boringssl_test_util.vcxproj">
+      <Project>{427037B1-B51B-D6F1-5025-AD12B200266A}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\boringssl\boringssl.vcxproj">
+      <Project>{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/boringssl/boringssl_asn1_test/boringssl_asn1_test.vcxproj.filters b/vsprojects/vcxproj/test/boringssl/boringssl_asn1_test/boringssl_asn1_test.vcxproj.filters
new file mode 100644
index 0000000..00e4276
--- /dev/null
+++ b/vsprojects/vcxproj/test/boringssl/boringssl_asn1_test/boringssl_asn1_test.vcxproj.filters
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <ItemGroup>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/boringssl/boringssl_asn1_test_lib/boringssl_asn1_test_lib.vcxproj b/vsprojects/vcxproj/test/boringssl/boringssl_asn1_test_lib/boringssl_asn1_test_lib.vcxproj
new file mode 100644
index 0000000..177bfcb
--- /dev/null
+++ b/vsprojects/vcxproj/test/boringssl/boringssl_asn1_test_lib/boringssl_asn1_test_lib.vcxproj
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{37B78CF5-2090-3DC6-FF98-17381709846A}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>boringssl_asn1_test_lib</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>boringssl_asn1_test_lib</TargetName>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>false</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>false</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>false</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>false</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\third_party\boringssl\crypto\asn1\asn1_test.cc">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\boringssl_test_util\boringssl_test_util.vcxproj">
+      <Project>{427037B1-B51B-D6F1-5025-AD12B200266A}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\boringssl\boringssl.vcxproj">
+      <Project>{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/boringssl/boringssl_asn1_test_lib/boringssl_asn1_test_lib.vcxproj.filters b/vsprojects/vcxproj/test/boringssl/boringssl_asn1_test_lib/boringssl_asn1_test_lib.vcxproj.filters
new file mode 100644
index 0000000..d508701
--- /dev/null
+++ b/vsprojects/vcxproj/test/boringssl/boringssl_asn1_test_lib/boringssl_asn1_test_lib.vcxproj.filters
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\third_party\boringssl\crypto\asn1\asn1_test.cc">
+      <Filter>third_party\boringssl\crypto\asn1</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="third_party">
+      <UniqueIdentifier>{4115523a-a0e5-e13f-f46b-76308dedf6f3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="third_party\boringssl">
+      <UniqueIdentifier>{c1481ada-4ab1-0cb6-8828-83f09d5421e4}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="third_party\boringssl\crypto">
+      <UniqueIdentifier>{199f1153-e7a0-fcef-73f5-eb766cb38fc3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="third_party\boringssl\crypto\asn1">
+      <UniqueIdentifier>{c5964062-112a-0884-d3ae-d8aec947c2f3}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/codegen_test/codegen_test.vcxproj b/vsprojects/vcxproj/test/codegen_test/codegen_test.vcxproj
new file mode 100644
index 0000000..7ba2a56
--- /dev/null
+++ b/vsprojects/vcxproj/test/codegen_test/codegen_test.vcxproj
@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{07D92FF8-D0D1-CB1B-51D3-EBA0E5DEBDD7}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\cpptest.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\protobuf.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>codegen_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>codegen_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\control.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\control.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\control.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\control.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\payloads.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\payloads.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\payloads.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\payloads.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\services.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\services.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\services.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\services.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\codegen\codegen_test.cc">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_codegen_lib\grpc++_codegen_lib.vcxproj">
+      <Project>{AAC6AF12-94C8-4A3C-A1BF-DAA4738F4500}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/codegen_test/codegen_test.vcxproj.filters b/vsprojects/vcxproj/test/codegen_test/codegen_test.vcxproj.filters
new file mode 100644
index 0000000..980cf76
--- /dev/null
+++ b/vsprojects/vcxproj/test/codegen_test/codegen_test.vcxproj.filters
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\control.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\payloads.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\perf_db.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\services.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\stats.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\codegen\codegen_test.cc">
+      <Filter>test\cpp\codegen</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{a37f6960-8f92-51ed-9b99-d24970584bb2}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto">
+      <UniqueIdentifier>{dc3f4032-f0dc-f8f0-e07a-78c0f628e9f5}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc">
+      <UniqueIdentifier>{250aede7-067f-590b-42d7-15939da4a59d}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc\testing">
+      <UniqueIdentifier>{57f4543e-acd0-a4a0-f3c3-8494e509b2b3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test">
+      <UniqueIdentifier>{7337b395-7e96-f49b-0a4f-b8a70be23a57}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp">
+      <UniqueIdentifier>{cf9e3404-0ab9-a301-9715-728febcece23}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp\codegen">
+      <UniqueIdentifier>{d349ac75-02e7-cb63-92f1-1785a74c0561}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/concurrent_connectivity_test/concurrent_connectivity_test.vcxproj b/vsprojects/vcxproj/test/concurrent_connectivity_test/concurrent_connectivity_test.vcxproj
new file mode 100644
index 0000000..6d69eae
--- /dev/null
+++ b/vsprojects/vcxproj/test/concurrent_connectivity_test/concurrent_connectivity_test.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{391B366C-D916-45AA-3FE5-67363A46193B}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>concurrent_connectivity_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>concurrent_connectivity_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\surface\concurrent_connectivity_test.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/concurrent_connectivity_test/concurrent_connectivity_test.vcxproj.filters b/vsprojects/vcxproj/test/concurrent_connectivity_test/concurrent_connectivity_test.vcxproj.filters
new file mode 100644
index 0000000..a6492c7
--- /dev/null
+++ b/vsprojects/vcxproj/test/concurrent_connectivity_test/concurrent_connectivity_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\surface\concurrent_connectivity_test.c">
+      <Filter>test\core\surface</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{1320b717-a107-004b-c517-074e6a7baf97}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{f205219c-cee2-c0e8-a922-5486f2d31026}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\surface">
+      <UniqueIdentifier>{6804b6ae-88f4-acf9-b3fc-6b12f8e28d4d}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/dns_resolver_connectivity_test/dns_resolver_connectivity_test.vcxproj b/vsprojects/vcxproj/test/dns_resolver_connectivity_test/dns_resolver_connectivity_test.vcxproj
new file mode 100644
index 0000000..76ac196
--- /dev/null
+++ b/vsprojects/vcxproj/test/dns_resolver_connectivity_test/dns_resolver_connectivity_test.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{F7B6FE68-E847-D7CA-4062-E737E542BCC3}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>dns_resolver_connectivity_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>dns_resolver_connectivity_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\client_config\resolvers\dns_resolver_connectivity_test.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/dns_resolver_connectivity_test/dns_resolver_connectivity_test.vcxproj.filters b/vsprojects/vcxproj/test/dns_resolver_connectivity_test/dns_resolver_connectivity_test.vcxproj.filters
new file mode 100644
index 0000000..e49318d
--- /dev/null
+++ b/vsprojects/vcxproj/test/dns_resolver_connectivity_test/dns_resolver_connectivity_test.vcxproj.filters
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\client_config\resolvers\dns_resolver_connectivity_test.c">
+      <Filter>test\core\client_config\resolvers</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{7743e287-3311-1206-2766-32381628ff07}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{cc06b800-cd26-f7a8-7ecf-ec789e78881b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\client_config">
+      <UniqueIdentifier>{4fbd5c0a-d1e3-6658-5788-2fc6f2cc9071}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\client_config\resolvers">
+      <UniqueIdentifier>{eab637a2-7ac1-f6be-4fc2-c8989c66070b}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/end2end/end2end_certs/end2end_certs.vcxproj b/vsprojects/vcxproj/test/end2end/end2end_certs/end2end_certs.vcxproj
deleted file mode 100644
index 85502ba..0000000
--- a/vsprojects/vcxproj/test/end2end/end2end_certs/end2end_certs.vcxproj
+++ /dev/null
@@ -1,166 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|Win32">
-      <Configuration>Debug</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|Win32">
-      <Configuration>Release</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</ProjectGuid>
-    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
-    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
-    <PlatformToolset>v100</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
-    <PlatformToolset>v110</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
-    <PlatformToolset>v140</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>end2end_certs</TargetName>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>end2end_certs</TargetName>
-  </PropertyGroup>
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\test_root_cert.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\server1_cert.c">
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\server1_key.c">
-    </ClCompile>
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  </ImportGroup>
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-  </Target>
-</Project>
-
diff --git a/vsprojects/vcxproj/test/end2end/end2end_certs/end2end_certs.vcxproj.filters b/vsprojects/vcxproj/test/end2end/end2end_certs/end2end_certs.vcxproj.filters
deleted file mode 100644
index 62b14d1..0000000
--- a/vsprojects/vcxproj/test/end2end/end2end_certs/end2end_certs.vcxproj.filters
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\test_root_cert.c">
-      <Filter>test\core\end2end\data</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\server1_cert.c">
-      <Filter>test\core\end2end\data</Filter>
-    </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\server1_key.c">
-      <Filter>test\core\end2end\data</Filter>
-    </ClCompile>
-  </ItemGroup>
-
-  <ItemGroup>
-    <Filter Include="test">
-      <UniqueIdentifier>{c94707fc-9ae9-9cc3-8743-77776eb9d9cc}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core">
-      <UniqueIdentifier>{f91d3831-d4bb-0981-77a4-16d8c5be07e9}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\end2end">
-      <UniqueIdentifier>{afbaeee0-7ab8-872c-8c47-3e3e5a8cc5e3}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\end2end\data">
-      <UniqueIdentifier>{5e4bc33c-7867-c329-d107-009b198f97dc}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-</Project>
-
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_census_test/h2_census_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_census_test/h2_census_test.vcxproj
index 612b5df..2f63ad0 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_census_test/h2_census_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_census_test/h2_census_test.vcxproj
@@ -165,9 +165,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
       <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_compress_test/h2_compress_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_compress_test/h2_compress_test.vcxproj
index 4b6fbaa..c9efe0b 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_compress_test/h2_compress_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_compress_test/h2_compress_test.vcxproj
@@ -165,9 +165,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
       <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_fakesec_test/h2_fakesec_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_fakesec_test/h2_fakesec_test.vcxproj
index 3406fad..d84176e 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_fakesec_test/h2_fakesec_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_fakesec_test/h2_fakesec_test.vcxproj
@@ -165,9 +165,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
       <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_full+trace_nosec_test/h2_full+trace_nosec_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+trace_nosec_test/h2_full+trace_nosec_test.vcxproj
new file mode 100644
index 0000000..a59e082
--- /dev/null
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+trace_nosec_test/h2_full+trace_nosec_test.vcxproj
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{DFD51943-4906-8051-7D66-6A7D50E0D87E}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>h2_full+trace_nosec_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>h2_full+trace_nosec_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_full+trace.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_nosec_tests\end2end_nosec_tests.vcxproj">
+      <Project>{47C2CB41-4E9F-58B6-F606-F6FAED5D00ED}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util_unsecure\grpc_test_util_unsecure.vcxproj">
+      <Project>{0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_unsecure\grpc_unsecure.vcxproj">
+      <Project>{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_full+trace_nosec_test/h2_full+trace_nosec_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+trace_nosec_test/h2_full+trace_nosec_test.vcxproj.filters
new file mode 100644
index 0000000..c9164af
--- /dev/null
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+trace_nosec_test/h2_full+trace_nosec_test.vcxproj.filters
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_full+trace.c">
+      <Filter>test\core\end2end\fixtures</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{2828a8fc-bcc1-7b1c-4953-0c8eaf9fe643}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{d8e78fb2-4316-018b-704a-0944fd0c6fd9}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end">
+      <UniqueIdentifier>{1981c949-24c5-413c-ab03-24eff55e803a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end\fixtures">
+      <UniqueIdentifier>{bfc11ba4-7401-55f0-8513-598aa93e7e1a}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_full+trace_test/h2_full+trace_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+trace_test/h2_full+trace_test.vcxproj
new file mode 100644
index 0000000..6ca9dfa
--- /dev/null
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+trace_test/h2_full+trace_test.vcxproj
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{16C713C6-062E-F71F-A44C-52DC35494B27}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>h2_full+trace_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>h2_full+trace_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_full+trace.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
+      <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_full+trace_test/h2_full+trace_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+trace_test/h2_full+trace_test.vcxproj.filters
new file mode 100644
index 0000000..87e8e72
--- /dev/null
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+trace_test/h2_full+trace_test.vcxproj.filters
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_full+trace.c">
+      <Filter>test\core\end2end\fixtures</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{00848213-d356-89b0-1d05-8131961dc959}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{863a91b6-f5f9-5326-129a-10003d7af98f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end">
+      <UniqueIdentifier>{2733ff09-adc7-fd49-696f-5f72df2f44e2}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end\fixtures">
+      <UniqueIdentifier>{62aa4eaf-c183-f2af-9ef9-a88ee802702c}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_full_test/h2_full_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_full_test/h2_full_test.vcxproj
index 96bd436..4ac31f1 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_full_test/h2_full_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_full_test/h2_full_test.vcxproj
@@ -165,9 +165,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
       <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_oauth2_test/h2_oauth2_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_oauth2_test/h2_oauth2_test.vcxproj
index f89d32c..67cc3c8 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_oauth2_test/h2_oauth2_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_oauth2_test/h2_oauth2_test.vcxproj
@@ -165,9 +165,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
       <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_proxy_test/h2_proxy_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_proxy_test/h2_proxy_test.vcxproj
index 8f56454..f159dfb 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_proxy_test/h2_proxy_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_proxy_test/h2_proxy_test.vcxproj
@@ -165,9 +165,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
       <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_sockpair+trace_test/h2_sockpair+trace_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_sockpair+trace_test/h2_sockpair+trace_test.vcxproj
index 44427fb..134913d 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_sockpair+trace_test/h2_sockpair+trace_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_sockpair+trace_test/h2_sockpair+trace_test.vcxproj
@@ -165,9 +165,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
       <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_sockpair_1byte_test/h2_sockpair_1byte_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_sockpair_1byte_test/h2_sockpair_1byte_test.vcxproj
index 5f4e43f..67c5486 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_sockpair_1byte_test/h2_sockpair_1byte_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_sockpair_1byte_test/h2_sockpair_1byte_test.vcxproj
@@ -165,9 +165,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
       <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_sockpair_test/h2_sockpair_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_sockpair_test/h2_sockpair_test.vcxproj
index 96359174..515ea02 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_sockpair_test/h2_sockpair_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_sockpair_test/h2_sockpair_test.vcxproj
@@ -165,9 +165,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
       <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_ssl_proxy_test/h2_ssl_proxy_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_ssl_proxy_test/h2_ssl_proxy_test.vcxproj
index 0693d65..c3463b9 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_ssl_proxy_test/h2_ssl_proxy_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_ssl_proxy_test/h2_ssl_proxy_test.vcxproj
@@ -165,9 +165,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
       <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_ssl_test/h2_ssl_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_ssl_test/h2_ssl_test.vcxproj
index 64e0c1b..217e415 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_ssl_test/h2_ssl_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_ssl_test/h2_ssl_test.vcxproj
@@ -165,9 +165,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
       <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_uchannel_nosec_test/h2_uchannel_nosec_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_uchannel_nosec_test/h2_uchannel_nosec_test.vcxproj
deleted file mode 100644
index 76a9e56..0000000
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_uchannel_nosec_test/h2_uchannel_nosec_test.vcxproj
+++ /dev/null
@@ -1,202 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|Win32">
-      <Configuration>Debug</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|Win32">
-      <Configuration>Release</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>{BD79A629-4181-DB5E-C28F-44EB280A6F91}</ProjectGuid>
-    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
-    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
-    <PlatformToolset>v100</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
-    <PlatformToolset>v110</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
-    <PlatformToolset>v140</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>h2_uchannel_nosec_test</TargetName>
-    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
-    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
-    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
-    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>h2_uchannel_nosec_test</TargetName>
-    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
-    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
-    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
-    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
-  </PropertyGroup>
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_uchannel.c">
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_nosec_tests\end2end_nosec_tests.vcxproj">
-      <Project>{47C2CB41-4E9F-58B6-F606-F6FAED5D00ED}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util_unsecure\grpc_test_util_unsecure.vcxproj">
-      <Project>{0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_unsecure\grpc_unsecure.vcxproj">
-      <Project>{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
-      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
-      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
-  </ImportGroup>
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
-  </Target>
-</Project>
-
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_uchannel_nosec_test/h2_uchannel_nosec_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/h2_uchannel_nosec_test/h2_uchannel_nosec_test.vcxproj.filters
deleted file mode 100644
index c9adeee..0000000
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_uchannel_nosec_test/h2_uchannel_nosec_test.vcxproj.filters
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_uchannel.c">
-      <Filter>test\core\end2end\fixtures</Filter>
-    </ClCompile>
-  </ItemGroup>
-
-  <ItemGroup>
-    <Filter Include="test">
-      <UniqueIdentifier>{549b9d3c-70c0-f3de-36d6-5b2ce5fb098c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core">
-      <UniqueIdentifier>{d37f19b6-6893-6a90-09d2-e50d891899ff}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\end2end">
-      <UniqueIdentifier>{bde36bf9-4894-e85b-4a35-f7b1abe9387f}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\end2end\fixtures">
-      <UniqueIdentifier>{e16ce654-bd8c-2527-1077-e6cd2639c1cb}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-</Project>
-
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_uchannel_test/h2_uchannel_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_uchannel_test/h2_uchannel_test.vcxproj
deleted file mode 100644
index bcf0f34..0000000
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_uchannel_test/h2_uchannel_test.vcxproj
+++ /dev/null
@@ -1,205 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|Win32">
-      <Configuration>Debug</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|Win32">
-      <Configuration>Release</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>{E39D59C4-F5CB-7D68-DA6B-C6BC93843435}</ProjectGuid>
-    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
-    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
-    <PlatformToolset>v100</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
-    <PlatformToolset>v110</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
-    <PlatformToolset>v140</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>h2_uchannel_test</TargetName>
-    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
-    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
-    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
-    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>h2_uchannel_test</TargetName>
-    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
-    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
-    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
-    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
-  </PropertyGroup>
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_uchannel.c">
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
-      <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
-      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
-      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
-      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
-      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
-  </ImportGroup>
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
-  </Target>
-</Project>
-
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_uchannel_test/h2_uchannel_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/h2_uchannel_test/h2_uchannel_test.vcxproj.filters
deleted file mode 100644
index 611a643..0000000
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_uchannel_test/h2_uchannel_test.vcxproj.filters
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_uchannel.c">
-      <Filter>test\core\end2end\fixtures</Filter>
-    </ClCompile>
-  </ItemGroup>
-
-  <ItemGroup>
-    <Filter Include="test">
-      <UniqueIdentifier>{0e4c3b3f-4d89-039d-c4d2-3bd39bb5701f}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core">
-      <UniqueIdentifier>{75084bcc-1809-7f7a-8989-d8fe2d5d404f}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\end2end">
-      <UniqueIdentifier>{9e123c51-0a8c-f222-f2f9-3cee19f2f99e}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\end2end\fixtures">
-      <UniqueIdentifier>{999ee744-f147-9430-9a09-a16f69ecfa2a}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-</Project>
-
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
index 2f3b591..568a051 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
@@ -147,8 +147,8 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\tests\cancel_test_helpers.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\end2end_tests.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\tests\cancel_test_helpers.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\end2end_nosec_tests.c">
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
index c63ebe7..ecc23e8 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
@@ -111,12 +111,12 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\tests\cancel_test_helpers.h">
-      <Filter>test\core\end2end\tests</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\end2end_tests.h">
       <Filter>test\core\end2end</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\tests\cancel_test_helpers.h">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
index 9d7bdc5..3e0092ef 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
@@ -147,8 +147,8 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\tests\cancel_test_helpers.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\end2end_tests.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\tests\cancel_test_helpers.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\end2end_tests.c">
@@ -227,9 +227,6 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end\end2end_certs\end2end_certs.vcxproj">
-      <Project>{80EA2691-C037-6DD3-D3AB-21510BF0E64B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
index c30054a..c3aabc4 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
@@ -114,12 +114,12 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\tests\cancel_test_helpers.h">
-      <Filter>test\core\end2end\tests</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\end2end_tests.h">
       <Filter>test\core\end2end</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\core\end2end\tests\cancel_test_helpers.h">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
diff --git a/vsprojects/vcxproj/test/gpr_backoff_test/gpr_backoff_test.vcxproj b/vsprojects/vcxproj/test/gpr_backoff_test/gpr_backoff_test.vcxproj
new file mode 100644
index 0000000..6aa292e
--- /dev/null
+++ b/vsprojects/vcxproj/test/gpr_backoff_test/gpr_backoff_test.vcxproj
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{889F570D-E046-BD52-9E4C-B4CD13DFE2DB}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>gpr_backoff_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>gpr_backoff_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\support\backoff_test.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/gpr_backoff_test/gpr_backoff_test.vcxproj.filters b/vsprojects/vcxproj/test/gpr_backoff_test/gpr_backoff_test.vcxproj.filters
new file mode 100644
index 0000000..eb3c1bb
--- /dev/null
+++ b/vsprojects/vcxproj/test/gpr_backoff_test/gpr_backoff_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\support\backoff_test.c">
+      <Filter>test\core\support</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{4b7f1d25-d344-0bcb-63d8-2ba959874ea8}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{2bd2fba5-8799-2c78-469f-ec3ba6b01da8}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\support">
+      <UniqueIdentifier>{2ef0cfa7-fe3d-2b82-7d0e-f9e293e8f98c}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/http_parser_test/http_parser_test.vcxproj b/vsprojects/vcxproj/test/http_parser_test/http_parser_test.vcxproj
new file mode 100644
index 0000000..bd5cf12
--- /dev/null
+++ b/vsprojects/vcxproj/test/http_parser_test/http_parser_test.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{49D7E690-BDA1-5236-1ABF-3D81C1559DF7}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>http_parser_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>http_parser_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\http\parser_test.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/http_parser_test/http_parser_test.vcxproj.filters b/vsprojects/vcxproj/test/http_parser_test/http_parser_test.vcxproj.filters
new file mode 100644
index 0000000..4353c3b
--- /dev/null
+++ b/vsprojects/vcxproj/test/http_parser_test/http_parser_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\http\parser_test.c">
+      <Filter>test\core\http</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{1d07f09d-a0ec-d684-3589-bff02afbe830}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{eedab59d-9f19-9172-cf0e-83a839217afc}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\http">
+      <UniqueIdentifier>{1fcac48f-3718-00ea-6c0c-aafa1a4de528}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/httpcli_format_request_test/httpcli_format_request_test.vcxproj b/vsprojects/vcxproj/test/httpcli_format_request_test/httpcli_format_request_test.vcxproj
index 97f14f6..5515349 100644
--- a/vsprojects/vcxproj/test/httpcli_format_request_test/httpcli_format_request_test.vcxproj
+++ b/vsprojects/vcxproj/test/httpcli_format_request_test/httpcli_format_request_test.vcxproj
@@ -158,7 +158,7 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\httpcli\format_request_test.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\http\format_request_test.c">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
diff --git a/vsprojects/vcxproj/test/httpcli_format_request_test/httpcli_format_request_test.vcxproj.filters b/vsprojects/vcxproj/test/httpcli_format_request_test/httpcli_format_request_test.vcxproj.filters
index c54ded5..6f941f4 100644
--- a/vsprojects/vcxproj/test/httpcli_format_request_test/httpcli_format_request_test.vcxproj.filters
+++ b/vsprojects/vcxproj/test/httpcli_format_request_test/httpcli_format_request_test.vcxproj.filters
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\httpcli\format_request_test.c">
-      <Filter>test\core\httpcli</Filter>
+    <ClCompile Include="$(SolutionDir)\..\test\core\http\format_request_test.c">
+      <Filter>test\core\http</Filter>
     </ClCompile>
   </ItemGroup>
 
@@ -13,8 +13,8 @@
     <Filter Include="test\core">
       <UniqueIdentifier>{f033cf49-b830-5698-3989-6ec75817333b}</UniqueIdentifier>
     </Filter>
-    <Filter Include="test\core\httpcli">
-      <UniqueIdentifier>{75330e6a-521e-5f90-defd-652a4591dbe9}</UniqueIdentifier>
+    <Filter Include="test\core\http">
+      <UniqueIdentifier>{51615bc9-b61d-8d7d-9abb-5409276c04ec}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
 </Project>
diff --git a/vsprojects/vcxproj/test/httpcli_parser_test/httpcli_parser_test.vcxproj b/vsprojects/vcxproj/test/httpcli_parser_test/httpcli_parser_test.vcxproj
deleted file mode 100644
index 6f97630..0000000
--- a/vsprojects/vcxproj/test/httpcli_parser_test/httpcli_parser_test.vcxproj
+++ /dev/null
@@ -1,199 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
-  <ItemGroup Label="ProjectConfigurations">
-    <ProjectConfiguration Include="Debug|Win32">
-      <Configuration>Debug</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|Win32">
-      <Configuration>Release</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>{B6F60D1C-D4F3-0F1A-4A2F-9134629B7848}</ProjectGuid>
-    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
-    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
-    <PlatformToolset>v100</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
-    <PlatformToolset>v110</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
-    <PlatformToolset>v140</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-  <ImportGroup Label="ExtensionSettings">
-  </ImportGroup>
-  <ImportGroup Label="PropertySheets">
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
-    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
-  </ImportGroup>
-  <PropertyGroup Label="UserMacros" />
-  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>httpcli_parser_test</TargetName>
-    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
-    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
-    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
-    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>httpcli_parser_test</TargetName>
-    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
-    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
-    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
-    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
-  </PropertyGroup>
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <ClCompile>
-      <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <FunctionLevelLinking>true</FunctionLevelLinking>
-      <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <TreatWarningAsError>true</TreatWarningAsError>
-      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
-      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
-    </ClCompile>
-    <Link>
-      <SubSystem>Console</SubSystem>
-      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
-      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\httpcli\parser_test.c">
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
-      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
-      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
-      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
-      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
-  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
-  </ImportGroup>
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
-    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
-  </Target>
-</Project>
-
diff --git a/vsprojects/vcxproj/test/httpcli_parser_test/httpcli_parser_test.vcxproj.filters b/vsprojects/vcxproj/test/httpcli_parser_test/httpcli_parser_test.vcxproj.filters
deleted file mode 100644
index 1cdc32f..0000000
--- a/vsprojects/vcxproj/test/httpcli_parser_test/httpcli_parser_test.vcxproj.filters
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\httpcli\parser_test.c">
-      <Filter>test\core\httpcli</Filter>
-    </ClCompile>
-  </ItemGroup>
-
-  <ItemGroup>
-    <Filter Include="test">
-      <UniqueIdentifier>{f3562e8b-3020-c79a-4e3b-c895f9e49f44}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core">
-      <UniqueIdentifier>{db527686-b5c7-68df-a106-bd919f60742a}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\httpcli">
-      <UniqueIdentifier>{8e60d460-93de-c6e1-b67b-bfae71bd9bca}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-</Project>
-